mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 22:50:18 +00:00
Constant expr (#79)
This commit is contained in:
parent
490cb7873b
commit
ca8e3bfa40
@ -1,9 +1,23 @@
|
||||
import "demo.aqua"
|
||||
service Demo("demo"):
|
||||
get4: u64, u64, string -> u64
|
||||
|
||||
func one() -> u64:
|
||||
variable <- Demo.get4()
|
||||
const bbb = 5
|
||||
const bbb ?= 2
|
||||
const ccc = "privet"
|
||||
const ddd = ccc
|
||||
const eee = bbb
|
||||
const asd = eee
|
||||
-- const ttt = -2
|
||||
|
||||
func two(variable: u64) -> u64:
|
||||
v <- Demo.get4(variable, eee, ddd)
|
||||
-- if bbb == ttt:
|
||||
-- Demo.get4(variable, eee, ddd)
|
||||
-- else:
|
||||
-- Demo.get4(variable, eee, ddd)
|
||||
<- variable
|
||||
|
||||
func two() -> u64:
|
||||
variable <- one()
|
||||
<- variable
|
||||
func three() -> u64:
|
||||
variable <- Demo.get4(asd, eee, ddd)
|
||||
res <- two(variable)
|
||||
<- variable
|
||||
|
@ -2,18 +2,7 @@ package aqua.backend.air
|
||||
|
||||
import aqua.model._
|
||||
import aqua.model.func.Call
|
||||
import aqua.model.func.body.{
|
||||
CallArrowTag,
|
||||
CallServiceTag,
|
||||
ForTag,
|
||||
MatchMismatchTag,
|
||||
NextTag,
|
||||
OnTag,
|
||||
OpTag,
|
||||
ParTag,
|
||||
SeqTag,
|
||||
XorTag
|
||||
}
|
||||
import aqua.model.func.body._
|
||||
import cats.Eval
|
||||
import cats.data.Chain
|
||||
import cats.free.Cofree
|
||||
|
@ -29,9 +29,9 @@ commons
|
||||
lazy val cli = project
|
||||
.settings(commons: _*)
|
||||
.settings(
|
||||
mainClass in (Compile, run) := Some("aqua.AquaCli"),
|
||||
mainClass in assembly := Some("aqua.AquaCli"),
|
||||
assemblyJarName in assembly := "aqua-cli-" + version.value + ".jar",
|
||||
Compile / run / mainClass := Some("aqua.AquaCli"),
|
||||
assembly / mainClass := Some("aqua.AquaCli"),
|
||||
assembly / assemblyJarName := "aqua-cli-" + version.value + ".jar",
|
||||
libraryDependencies ++= Seq(
|
||||
"com.monovore" %% "decline" % declineV,
|
||||
"com.monovore" %% "decline-effect" % declineV,
|
||||
|
@ -14,7 +14,7 @@ object Test extends IOApp.Simple {
|
||||
Paths.get("./aqua-src"),
|
||||
LazyList(Paths.get("./aqua")),
|
||||
Paths.get("./target"),
|
||||
AquaCompiler.AirTarget,
|
||||
AquaCompiler.TypescriptTarget,
|
||||
BodyConfig()
|
||||
)
|
||||
.map {
|
||||
|
@ -26,7 +26,7 @@ case class EmptyFileError(path: Path) extends AquaFileError {
|
||||
}
|
||||
|
||||
case class FileSystemError(err: Throwable) extends Exception(err) with AquaFileError {
|
||||
override def showForConsole: String = s"File system error"
|
||||
override def showForConsole: String = s"File system error: ${err.getMessage}"
|
||||
}
|
||||
|
||||
case class Unresolvable(msg: String) extends AquaFileError {
|
||||
|
3
model/src/main/scala/aqua/model/ConstantModel.scala
Normal file
3
model/src/main/scala/aqua/model/ConstantModel.scala
Normal file
@ -0,0 +1,3 @@
|
||||
package aqua.model
|
||||
|
||||
case class ConstantModel(name: String, value: ValueModel) extends Model
|
@ -4,21 +4,36 @@ import aqua.model.func.{FuncCallable, FuncModel}
|
||||
import cats.Monoid
|
||||
import cats.data.Chain
|
||||
|
||||
// TODO make one chain to have order
|
||||
case class ScriptModel(
|
||||
funcs: Chain[FuncModel] = Chain.empty,
|
||||
services: Chain[ServiceModel] = Chain.empty,
|
||||
types: Chain[TypeModel] = Chain.empty
|
||||
models: Chain[Model] = Chain.empty
|
||||
) extends Model {
|
||||
|
||||
def resolveFunctions: Chain[FuncCallable] =
|
||||
case class Acc(
|
||||
arrows: Map[String, FuncCallable],
|
||||
values: Map[String, ValueModel]
|
||||
)
|
||||
|
||||
lazy val funcs: Chain[FuncModel] = models.collect { case c: FuncModel => c }
|
||||
lazy val constants: Chain[ConstantModel] = models.collect { case c: ConstantModel => c }
|
||||
|
||||
def resolveFunctions: Chain[FuncCallable] = {
|
||||
val constantsToName =
|
||||
constants.map(c => c.name -> c.value).toList.toMap
|
||||
funcs
|
||||
.foldLeft((Map.empty[String, FuncCallable], Chain.empty[FuncCallable])) {
|
||||
case ((funcsAcc, outputAcc), func) =>
|
||||
val fr = func.captureArrows(funcsAcc)
|
||||
funcsAcc.updated(func.name, fr) -> outputAcc.append(fr)
|
||||
.foldLeft(
|
||||
(
|
||||
(
|
||||
Map.empty[String, FuncCallable],
|
||||
Chain.empty[FuncCallable]
|
||||
)
|
||||
)
|
||||
) { case ((acc, outputAcc), func) =>
|
||||
val fr = func.capture(acc, constantsToName)
|
||||
acc -> outputAcc.append(fr)
|
||||
}
|
||||
._2
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
object ScriptModel {
|
||||
@ -27,14 +42,17 @@ object ScriptModel {
|
||||
override def empty: ScriptModel = ScriptModel()
|
||||
|
||||
override def combine(x: ScriptModel, y: ScriptModel): ScriptModel =
|
||||
ScriptModel(x.funcs ++ y.funcs, x.services ++ y.services, x.types ++ y.types)
|
||||
ScriptModel(
|
||||
x.models ++ y.models
|
||||
)
|
||||
}
|
||||
|
||||
// Builds a ScriptModel if given model can be considered as a part of a script
|
||||
def toScriptPart(m: Model): Option[ScriptModel] = m match {
|
||||
case fm: FuncModel => Some(ScriptModel(funcs = Chain.one(fm)))
|
||||
case sm: ServiceModel => Some(ScriptModel(services = Chain.one(sm)))
|
||||
case tm: TypeModel => Some(ScriptModel(types = Chain.one(tm)))
|
||||
case fm: FuncModel => Some(ScriptModel(models = Chain.one(fm)))
|
||||
case sm: ServiceModel => Some(ScriptModel(models = Chain.one(sm)))
|
||||
case tm: TypeModel => Some(ScriptModel(models = Chain.one(tm)))
|
||||
case cm: ConstantModel => Some(ScriptModel(models = Chain.one(cm)))
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,38 @@ case class IntoFieldModel(field: String) extends LambdaModel
|
||||
case class VarModel(name: String, lambda: Chain[LambdaModel] = Chain.empty) extends ValueModel {
|
||||
def deriveFrom(vm: VarModel): VarModel = vm.copy(lambda = vm.lambda ++ lambda)
|
||||
|
||||
override def resolveWith(map: Map[String, ValueModel]): ValueModel = map.get(name) match {
|
||||
case Some(vv: VarModel) => deriveFrom(vv)
|
||||
case Some(vv) => vv // TODO check that lambda is empty, otherwise error
|
||||
case None => this // Should not happen
|
||||
override def resolveWith(map: Map[String, ValueModel]): ValueModel = {
|
||||
map.get(name) match {
|
||||
case Some(vv: VarModel) =>
|
||||
map.get(vv.name) match {
|
||||
case Some(n) =>
|
||||
n match {
|
||||
/* This case protects from infinite recursion
|
||||
when similar names are in a body of a function and a call of a function
|
||||
service Demo("demo"):
|
||||
get4: u64 -> u64
|
||||
|
||||
func two(variable: u64) -> u64:
|
||||
v <- Demo.get4(variable)
|
||||
<- variable
|
||||
|
||||
func three(v: u64) -> u64:
|
||||
variable <- Demo.get4(v)
|
||||
-- here we will try to resolve 'variable' to VarModel('variable')
|
||||
-- that could cause infinite recursion
|
||||
res <- two(variable)
|
||||
<- variable
|
||||
*/
|
||||
case vm @ VarModel(nn, _) if nn == name => deriveFrom(vm)
|
||||
// it couldn't go to a cycle as long as the semantics protects it
|
||||
case _ => n.resolveWith(map)
|
||||
}
|
||||
case _ =>
|
||||
deriveFrom(vv)
|
||||
}
|
||||
|
||||
case Some(vv) => vv // TODO check that lambda is empty, otherwise error
|
||||
case None => this // Should not happen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,8 @@ case class FuncCallable(
|
||||
body: FuncOp,
|
||||
args: ArgsDef,
|
||||
ret: Option[Call.Arg],
|
||||
capturedArrows: Map[String, FuncCallable]
|
||||
capturedArrows: Map[String, FuncCallable],
|
||||
capturedValues: Map[String, ValueModel]
|
||||
) {
|
||||
|
||||
def arrowType: ArrowType =
|
||||
@ -73,7 +74,7 @@ case class FuncCallable(
|
||||
// Accumulator: all used names are forbidden, if we set any more names -- forbid them as well
|
||||
(forbiddenNames ++ shouldRename.values ++ treeDefines) ->
|
||||
// Functions may export variables, so collect them
|
||||
Map.empty[String, ValueModel]
|
||||
capturedValues
|
||||
) {
|
||||
case ((noNames, resolvedExports), CallArrowTag(fn, c)) if allArrows.contains(fn) =>
|
||||
// Apply arguments to a function – recursion
|
||||
|
@ -1,7 +1,7 @@
|
||||
package aqua.model.func
|
||||
|
||||
import aqua.model.func.body.FuncOp
|
||||
import aqua.model.Model
|
||||
import aqua.model.{Model, ValueModel}
|
||||
|
||||
case class FuncModel(
|
||||
name: String,
|
||||
@ -10,7 +10,10 @@ case class FuncModel(
|
||||
body: FuncOp
|
||||
) extends Model {
|
||||
|
||||
def captureArrows(arrows: Map[String, FuncCallable]): FuncCallable =
|
||||
FuncCallable(name, body, args, ret, arrows)
|
||||
def capture(
|
||||
arrows: Map[String, FuncCallable],
|
||||
constants: Map[String, ValueModel]
|
||||
): FuncCallable =
|
||||
FuncCallable(name, body, args, ret, arrows, constants)
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package aqua.model.func.body
|
||||
|
||||
import aqua.model.{LiteralModel, ValueModel}
|
||||
import aqua.model.func.Call
|
||||
import aqua.model.{LiteralModel, ValueModel}
|
||||
import cats.data.Chain
|
||||
import cats.free.Cofree
|
||||
|
||||
|
@ -31,6 +31,7 @@ case class ResolveFunc(
|
||||
callback(name, call),
|
||||
args,
|
||||
ret,
|
||||
Map.empty,
|
||||
Map.empty
|
||||
)
|
||||
}
|
||||
@ -55,7 +56,8 @@ case class ResolveFunc(
|
||||
None,
|
||||
func.args.arrowArgs.collect { case ArgDef.Arrow(argName, arrowType) =>
|
||||
argName -> arrowToCallback(argName, arrowType)
|
||||
}.toList.toMap
|
||||
}.toList.toMap,
|
||||
func.capturedValues
|
||||
)
|
||||
|
||||
def resolve(func: FuncCallable, funcArgName: String = "_func"): Eval[FuncOp] =
|
||||
|
@ -1,9 +1,6 @@
|
||||
package aqua.model.transform
|
||||
|
||||
import aqua.model.func.body.{CallArrowTag, CallServiceTag, FuncOp}
|
||||
import aqua.model.func.{ArgsDef, Call, FuncCallable}
|
||||
import aqua.model.{LiteralModel, Node, VarModel}
|
||||
import aqua.types.ScalarType
|
||||
import aqua.model.Node
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package aqua.model.transform
|
||||
|
||||
import aqua.model.{LiteralModel, Node, VarModel}
|
||||
import aqua.model.func.{ArgsDef, Call, FuncCallable}
|
||||
import aqua.model.func.body.{CallArrowTag, CallServiceTag, FuncOp}
|
||||
import aqua.model.func.{ArgsDef, Call, FuncCallable}
|
||||
import aqua.model.{LiteralModel, Node, VarModel}
|
||||
import aqua.types.ScalarType
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
@ -20,6 +20,7 @@ class TransformSpec extends AnyFlatSpec with Matchers {
|
||||
FuncOp(on(otherPeer, Nil, call(1))),
|
||||
ArgsDef.empty,
|
||||
Some(Call.Arg(ret, ScalarType.string)),
|
||||
Map.empty,
|
||||
Map.empty
|
||||
)
|
||||
|
||||
@ -57,6 +58,7 @@ class TransformSpec extends AnyFlatSpec with Matchers {
|
||||
FuncOp(seq(call(0), on(otherPeer, Nil, call(1)))),
|
||||
ArgsDef.empty,
|
||||
Some(Call.Arg(ret, ScalarType.string)),
|
||||
Map.empty,
|
||||
Map.empty
|
||||
)
|
||||
|
||||
@ -105,6 +107,7 @@ class TransformSpec extends AnyFlatSpec with Matchers {
|
||||
FuncOp(Node(CallServiceTag(LiteralModel("\"srv1\""), "foo", Call(Nil, Some("v")), None))),
|
||||
ArgsDef.empty,
|
||||
Some(Call.Arg(VarModel("v"), ScalarType.string)),
|
||||
Map.empty,
|
||||
Map.empty
|
||||
)
|
||||
|
||||
@ -116,7 +119,8 @@ class TransformSpec extends AnyFlatSpec with Matchers {
|
||||
),
|
||||
ArgsDef.empty,
|
||||
Some(Call.Arg(VarModel("v"), ScalarType.string)),
|
||||
Map("callable" -> f1)
|
||||
Map("callable" -> f1),
|
||||
Map.empty
|
||||
)
|
||||
|
||||
val bc = BodyConfig(wrapWithXor = false)
|
||||
|
@ -20,7 +20,7 @@ object Ast {
|
||||
type Head[F[_]] = Cofree[Chain, HeaderExpr[F]]
|
||||
|
||||
def treeExprs: List[Expr.Companion] =
|
||||
ServiceExpr :: AliasExpr :: DataStructExpr :: FuncExpr :: Nil
|
||||
ServiceExpr :: AliasExpr :: DataStructExpr :: ConstantExpr :: FuncExpr :: Nil
|
||||
|
||||
def headExprs: List[HeaderExpr.Companion] =
|
||||
ImportExpr :: Nil
|
||||
|
21
parser/src/main/scala/aqua/parser/expr/AssignmentExpr.scala
Normal file
21
parser/src/main/scala/aqua/parser/expr/AssignmentExpr.scala
Normal file
@ -0,0 +1,21 @@
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.parser.Expr
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Name, Value}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.parse.{Parser => P}
|
||||
|
||||
case class AssignmentExpr[F[_]](
|
||||
variable: Name[F],
|
||||
value: Value[F]
|
||||
) extends Expr[F]
|
||||
|
||||
object AssignmentExpr extends Expr.Leaf {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: P[AssignmentExpr[F]] =
|
||||
((Name.p[F] <* ` = `).with1 ~ Value.`value`).map { case (variable, value) =>
|
||||
AssignmentExpr(variable, value)
|
||||
}
|
||||
}
|
@ -20,8 +20,9 @@ object CallArrowExpr extends Expr.Leaf {
|
||||
((Name.p[F] <* ` <- `).backtrack.?.with1 ~
|
||||
((Ability.ab[F] <* `.`).?.with1 ~
|
||||
Name.p[F] ~
|
||||
comma0(Value.`value`[F]).between(`(`, `)`))).map { case (variable, ((ability, funcName), args)) =>
|
||||
CallArrowExpr(variable, ability, funcName, args)
|
||||
comma0(Value.`value`[F]).between(`(`, `)`))).map {
|
||||
case (variable, ((ability, funcName), args)) =>
|
||||
CallArrowExpr(variable, ability, funcName, args)
|
||||
}
|
||||
|
||||
}
|
||||
|
25
parser/src/main/scala/aqua/parser/expr/ConstantExpr.scala
Normal file
25
parser/src/main/scala/aqua/parser/expr/ConstantExpr.scala
Normal file
@ -0,0 +1,25 @@
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.parser.Expr
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Name, Value}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.parse.{Parser => P}
|
||||
|
||||
case class ConstantExpr[F[_]](
|
||||
name: Name[F],
|
||||
value: Value[F],
|
||||
skipIfAlreadyDefined: Boolean
|
||||
) extends Expr[F]
|
||||
|
||||
object ConstantExpr extends Expr.Leaf {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: P[ConstantExpr[F]] = {
|
||||
((((`const` *> ` ` *> Name
|
||||
.p[F] <* ` `) ~ `?`.?).with1 <* `=` <* ` `) ~ Value.`value`).map {
|
||||
case ((name, mark), value) =>
|
||||
ConstantExpr(name, value, mark.nonEmpty)
|
||||
}
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@ object Token {
|
||||
private val nl = Set('\n', '\r')
|
||||
|
||||
val ` ` : P[String] = P.charsWhile(fSpaces)
|
||||
val `const`: P[Unit] = P.string("const")
|
||||
val `data`: P[Unit] = P.string("data")
|
||||
val `import`: P[Unit] = P.string("import")
|
||||
val `use`: P[Unit] = P.string("use")
|
||||
@ -62,6 +63,9 @@ object Token {
|
||||
val `)` : P[Unit] = ` `.?.with1 *> P.char(')') <* ` `.?
|
||||
val ` -> ` : P[Unit] = ` `.?.with1 *> P.string("->") <* ` `.?
|
||||
val ` <- ` : P[Unit] = (` `.?.with1 *> P.string("<-") <* ` `.?).backtrack
|
||||
val `=` : P[Unit] = P.string("=")
|
||||
val ` = ` : P[Unit] = (` `.?.with1 *> P.string("=") <* ` `.?).backtrack
|
||||
val `?` : P[Unit] = P.string("?")
|
||||
val `<-` : P[Unit] = P.string("<-").backtrack
|
||||
|
||||
def comma[T](p: P[T]): P[NonEmptyList[T]] =
|
||||
|
@ -4,7 +4,9 @@ import aqua.parser.expr.{
|
||||
AbilityIdExpr,
|
||||
AliasExpr,
|
||||
ArrowTypeExpr,
|
||||
AssignmentExpr,
|
||||
CallArrowExpr,
|
||||
ConstantExpr,
|
||||
DataStructExpr,
|
||||
ElseOtherwiseExpr,
|
||||
FieldTypeExpr,
|
||||
@ -101,6 +103,12 @@ trait AquaSpec extends EitherValues {
|
||||
def parseReturn(str: String): ReturnExpr[Id] =
|
||||
ReturnExpr.p[Id].parseAll(str).value
|
||||
|
||||
def parseAssign(str: String): AssignmentExpr[Id] =
|
||||
AssignmentExpr.p[Id].parseAll(str).value
|
||||
|
||||
def parseConstant(str: String): ConstantExpr[Id] =
|
||||
ConstantExpr.p[Id].parseAll(str).value
|
||||
|
||||
def parseService(str: String): ServiceExpr[Id] =
|
||||
ServiceExpr.p[Id].parseAll(str).value
|
||||
|
||||
|
33
parser/src/test/scala/aqua/parser/AssignmentExprSpec.scala
Normal file
33
parser/src/test/scala/aqua/parser/AssignmentExprSpec.scala
Normal file
@ -0,0 +1,33 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.AquaSpec
|
||||
import aqua.parser.expr.{AssignmentExpr, ConstantExpr}
|
||||
import cats.Id
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
|
||||
class AssignmentExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
||||
import AquaSpec._
|
||||
|
||||
"assign" should "be parsed" in {
|
||||
parseAssign("a = \"b\"") should be(
|
||||
AssignmentExpr[Id]("a", toStr("b"))
|
||||
)
|
||||
|
||||
parseAssign("a = b") should be(
|
||||
AssignmentExpr[Id]("a", toVar("b"))
|
||||
)
|
||||
|
||||
parseConstant("const a = b") should be(
|
||||
ConstantExpr[Id]("a", toVar("b"), skipIfAlreadyDefined = false)
|
||||
)
|
||||
|
||||
parseConstant("const a = 1") should be(
|
||||
ConstantExpr[Id]("a", toNumber(1), skipIfAlreadyDefined = false)
|
||||
)
|
||||
|
||||
parseConstant("const a ?= 1") should be(
|
||||
ConstantExpr[Id]("a", toNumber(1), skipIfAlreadyDefined = true)
|
||||
)
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ import aqua.parser.Ast.parser
|
||||
import aqua.parser.expr._
|
||||
import aqua.parser.lexer.{ArrowTypeToken, BasicTypeToken, EqOp}
|
||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||
import aqua.types.ScalarType.{bool, string, u32, u64, u8}
|
||||
import aqua.types.ScalarType._
|
||||
import cats.Id
|
||||
import cats.data.Chain
|
||||
import cats.free.Cofree
|
||||
@ -89,7 +89,6 @@ class FuncExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
||||
|
||||
val tree = FuncExpr.ast[Id](Indent()).parseAll(script).value
|
||||
val funcBody = checkHeadGetTail(tree, FuncExpr("a", Nil, None, None), 1).toList
|
||||
println("body: " + funcBody)
|
||||
|
||||
val ifBody =
|
||||
checkHeadGetTail(
|
||||
|
@ -1,7 +1,7 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.AquaSpec
|
||||
import aqua.parser.expr.{ParExpr, ReturnExpr}
|
||||
import aqua.parser.expr.ReturnExpr
|
||||
import cats.Id
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
@ -9,7 +9,7 @@ import org.scalatest.matchers.should.Matchers
|
||||
class ReturnExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
||||
import AquaSpec._
|
||||
|
||||
"on" should "be parsed" in {
|
||||
"return" should "be parsed" in {
|
||||
parseReturn("<- true") should be(
|
||||
ReturnExpr[Id](toBool(true))
|
||||
)
|
||||
|
@ -20,6 +20,7 @@ object ExprSem {
|
||||
expr match {
|
||||
case expr: AbilityIdExpr[F] => new AbilityIdSem(expr).program[G]
|
||||
case expr: AliasExpr[F] => new AliasSem(expr).program[G]
|
||||
case expr: ConstantExpr[F] => new ConstantSem(expr).program[G]
|
||||
case expr: ArrowTypeExpr[F] => new ArrowTypeSem(expr).program[G]
|
||||
case expr: CallArrowExpr[F] => new CallArrowSem(expr).program[G]
|
||||
case expr: DataStructExpr[F] => new DataStructSem(expr).program[G]
|
||||
|
@ -1,8 +1,8 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.Model
|
||||
import aqua.model.func.Call
|
||||
import aqua.model.func.body.{CallArrowTag, CallServiceTag, FuncOp}
|
||||
import aqua.model.Model
|
||||
import aqua.parser.expr.CallArrowExpr
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
@ -11,9 +11,9 @@ import aqua.semantics.rules.names.NamesAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import aqua.types.ArrowType
|
||||
import cats.free.Free
|
||||
import cats.syntax.apply._
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
import cats.syntax.apply._
|
||||
|
||||
class CallArrowSem[F[_]](val expr: CallArrowExpr[F]) extends AnyVal {
|
||||
|
||||
|
@ -0,0 +1,42 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.{ConstantModel, Model}
|
||||
import aqua.parser.expr.ConstantExpr
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import cats.free.Free
|
||||
import cats.syntax.functor._
|
||||
|
||||
class ConstantSem[F[_]](val expr: ConstantExpr[F]) extends AnyVal {
|
||||
|
||||
def program[Alg[_]](implicit
|
||||
V: ValuesAlgebra[F, Alg],
|
||||
N: NamesAlgebra[F, Alg],
|
||||
T: TypesAlgebra[F, Alg]
|
||||
): Prog[Alg, Model] = {
|
||||
for {
|
||||
defined <- N.constantDefined(expr.name)
|
||||
t <- V.resolveType(expr.value)
|
||||
model <- (defined, t, expr.skipIfAlreadyDefined) match {
|
||||
case (Some(definedType), Some(actualType), true) =>
|
||||
T.ensureTypeMatches(expr.value, definedType, actualType).map {
|
||||
case true =>
|
||||
Model.empty(s"Constant with name ${expr.name} was already defined, skipping")
|
||||
case false =>
|
||||
Model.error(s"Constant with name ${expr.name} was defined with different type")
|
||||
}
|
||||
case (Some(_), _, _) =>
|
||||
Free.pure[Alg, Model](Model.error(s"Name '${expr.name.value}' was already defined"))
|
||||
case (_, None, _) =>
|
||||
Free.pure[Alg, Model](Model.error(s"There is no such variable ${expr.value}"))
|
||||
case (_, Some(t), _) =>
|
||||
N.defineConstant(expr.name, t) as (ConstantModel(
|
||||
expr.name.value,
|
||||
ValuesAlgebra.valueToModel(expr.value)
|
||||
): Model)
|
||||
}
|
||||
} yield model
|
||||
}
|
||||
}
|
@ -1,17 +1,16 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.func.FuncModel
|
||||
import aqua.model.{Model, ScriptModel, ServiceModel, TypeModel}
|
||||
import aqua.model.{Model, ScriptModel}
|
||||
import aqua.parser.expr.RootExpr
|
||||
import aqua.semantics.Prog
|
||||
import cats.data.Chain
|
||||
import cats.free.Free
|
||||
|
||||
class RootSem[F[_]](val expr: RootExpr[F]) extends AnyVal {
|
||||
|
||||
def program[Alg[_]]: Prog[Alg, Model] =
|
||||
Prog.after {
|
||||
case sm: ScriptModel => Free.pure[Alg, Model](sm)
|
||||
case sm: ScriptModel =>
|
||||
Free.pure[Alg, Model](sm)
|
||||
case m =>
|
||||
Free.pure[Alg, Model](
|
||||
ScriptModel
|
||||
|
@ -1,9 +1,9 @@
|
||||
package aqua.semantics.rules
|
||||
|
||||
import aqua.model.{IntoArrayModel, IntoFieldModel, LambdaModel, LiteralModel, ValueModel, VarModel}
|
||||
import aqua.model._
|
||||
import aqua.parser.lexer._
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import aqua.parser.lexer.{IntoArray, IntoField, LambdaOp, Literal, Token, Value, VarLambda}
|
||||
import aqua.types.{ArrowType, LiteralType, Type}
|
||||
import cats.data.Chain
|
||||
import cats.free.Free
|
||||
|
@ -6,10 +6,12 @@ import aqua.types.{ArrowType, Type}
|
||||
sealed trait NameOp[F[_], T]
|
||||
|
||||
case class ReadName[F[_]](name: Name[F]) extends NameOp[F, Option[Type]]
|
||||
case class ConstantDefined[F[_]](name: Name[F]) extends NameOp[F, Option[Type]]
|
||||
|
||||
case class ReadArrow[F[_]](name: Name[F]) extends NameOp[F, Option[ArrowType]]
|
||||
|
||||
case class DefineName[F[_]](name: Name[F], `type`: Type) extends NameOp[F, Boolean]
|
||||
case class DefineConstant[F[_]](name: Name[F], `type`: Type) extends NameOp[F, Boolean]
|
||||
|
||||
case class DefineArrow[F[_]](name: Name[F], gen: ArrowType, isRoot: Boolean)
|
||||
extends NameOp[F, Boolean]
|
||||
|
@ -1,6 +1,6 @@
|
||||
package aqua.semantics.rules.names
|
||||
|
||||
import aqua.parser.lexer.{Name, Token}
|
||||
import aqua.parser.lexer.{Literal, Name, Token, Value}
|
||||
import aqua.types.{ArrowType, Type}
|
||||
import cats.InjectK
|
||||
import cats.free.Free
|
||||
@ -10,12 +10,18 @@ class NamesAlgebra[F[_], Alg[_]](implicit V: InjectK[NameOp[F, *], Alg]) {
|
||||
def read(name: Name[F]): Free[Alg, Option[Type]] =
|
||||
Free.liftInject[Alg](ReadName(name))
|
||||
|
||||
def constantDefined(name: Name[F]): Free[Alg, Option[Type]] =
|
||||
Free.liftInject[Alg](ConstantDefined(name))
|
||||
|
||||
def readArrow(name: Name[F]): Free[Alg, Option[ArrowType]] =
|
||||
Free.liftInject[Alg](ReadArrow(name))
|
||||
|
||||
def define(name: Name[F], `type`: Type): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineName(name, `type`))
|
||||
|
||||
def defineConstant(name: Name[F], `type`: Type): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineConstant(name, `type`))
|
||||
|
||||
def defineArrow(name: Name[F], gen: ArrowType, isRoot: Boolean): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineArrow(name, gen, isRoot))
|
||||
|
||||
|
@ -2,12 +2,12 @@ package aqua.semantics.rules.names
|
||||
|
||||
import aqua.semantics.rules.{ReportError, StackInterpreter}
|
||||
import aqua.types.{ArrowType, Type}
|
||||
import cats.data.State
|
||||
import cats.data.{OptionT, State}
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
import cats.~>
|
||||
import monocle.Lens
|
||||
import monocle.macros.GenLens
|
||||
import cats.syntax.functor._
|
||||
import cats.syntax.flatMap._
|
||||
|
||||
class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: ReportError[F, X])
|
||||
extends StackInterpreter[F, X, NamesState[F], NamesState.Frame[F]](
|
||||
@ -16,12 +16,15 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
|
||||
|
||||
def readName(name: String): S[Option[Type]] =
|
||||
getState.map { st =>
|
||||
st.stack.collectFirst {
|
||||
st.constants.get(name) orElse st.stack.collectFirst {
|
||||
case frame if frame.names.contains(name) => frame.names(name)
|
||||
case frame if frame.arrows.contains(name) => frame.arrows(name)
|
||||
} orElse st.rootArrows.get(name)
|
||||
}
|
||||
|
||||
def constantDefined(name: String): S[Option[Type]] =
|
||||
getState.map(_.constants.get(name))
|
||||
|
||||
def readArrow(name: String): S[Option[ArrowType]] =
|
||||
getState.map { st =>
|
||||
st.stack.flatMap(_.arrows.get(name)).headOption orElse st.rootArrows.get(name)
|
||||
@ -30,13 +33,19 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
|
||||
override def apply[A](fa: NameOp[F, A]): State[X, A] =
|
||||
(fa match {
|
||||
case rn: ReadName[F] =>
|
||||
readName(rn.name.value).flatTap {
|
||||
case Some(_) => State.pure(())
|
||||
case None =>
|
||||
getState.flatMap(st =>
|
||||
report(rn.name, "Undefined name, available: " + st.allNames.mkString(", "))
|
||||
)
|
||||
}
|
||||
OptionT(constantDefined(rn.name.value))
|
||||
.orElseF(readName(rn.name.value))
|
||||
.value
|
||||
.flatTap {
|
||||
case Some(_) => State.pure(())
|
||||
case None =>
|
||||
getState.flatMap(st =>
|
||||
report(rn.name, "Undefined name, available: " + st.allNames.mkString(", "))
|
||||
)
|
||||
}
|
||||
case rn: ConstantDefined[F] =>
|
||||
constantDefined(rn.name.value)
|
||||
|
||||
case ra: ReadArrow[F] =>
|
||||
readArrow(ra.name.value).flatMap {
|
||||
case Some(g) => State.pure(Option(g))
|
||||
@ -47,6 +56,17 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
|
||||
)
|
||||
}
|
||||
|
||||
case dc: DefineConstant[F] =>
|
||||
readName(dc.name.value).flatMap {
|
||||
case Some(_) =>
|
||||
report(dc.name, "This name was already defined in the scope").as(false)
|
||||
case None =>
|
||||
modify(st =>
|
||||
st.copy(
|
||||
constants = st.constants.updated(dc.name.value, dc.`type`)
|
||||
)
|
||||
).as(true)
|
||||
}
|
||||
case dn: DefineName[F] =>
|
||||
readName(dn.name.value).flatMap {
|
||||
case Some(_) =>
|
||||
|
@ -1,17 +1,22 @@
|
||||
package aqua.semantics.rules.names
|
||||
|
||||
import aqua.parser.lexer.{Name, Token}
|
||||
import aqua.parser.lexer.{Name, Token, Value}
|
||||
import aqua.types.{ArrowType, Type}
|
||||
import cats.kernel.Monoid
|
||||
|
||||
case class NamesState[F[_]](
|
||||
stack: List[NamesState.Frame[F]] = Nil,
|
||||
rootArrows: Map[String, ArrowType] = Map.empty,
|
||||
constants: Map[String, Type] = Map.empty[String, Type],
|
||||
definitions: Map[String, Name[F]] = Map.empty[String, Name[F]]
|
||||
) {
|
||||
|
||||
def allNames: LazyList[String] =
|
||||
LazyList.from(stack).flatMap(s => s.names.keys ++ s.arrows.keys).appendedAll(rootArrows.keys)
|
||||
LazyList
|
||||
.from(stack)
|
||||
.flatMap(s => s.names.keys ++ s.arrows.keys)
|
||||
.appendedAll(rootArrows.keys)
|
||||
.appendedAll(constants.keys)
|
||||
|
||||
def allArrows: LazyList[String] =
|
||||
LazyList.from(stack).flatMap(_.arrows.keys).appendedAll(rootArrows.keys)
|
||||
@ -37,7 +42,8 @@ object NamesState {
|
||||
NamesState(
|
||||
stack = Nil,
|
||||
rootArrows = x.rootArrows ++ y.rootArrows,
|
||||
definitions = x.definitions ++ y.definitions
|
||||
definitions = x.definitions ++ y.definitions,
|
||||
constants = x.constants ++ y.constants
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user