diff --git a/.github/workflows/test_branch.yml b/.github/workflows/test_branch.yml index 48838a79..23a299e7 100644 --- a/.github/workflows/test_branch.yml +++ b/.github/workflows/test_branch.yml @@ -47,18 +47,19 @@ jobs: sbt test ### Update & build -# - name: Integration test -# run: | -# git clone https://github.com/fluencelabs/aqua-playground.git -# cd aqua-playground -# npm i -# cd .. -# sbt "cli/run -i aqua-playground/aqua/examples -o aqua-playground/src/compiled/examples -m aqua-playground/node_modules -c \"uniqueConst = 1\" -c \"anotherConst = \\\"ab\\\"\"" -# cd aqua-playground -# npm run examples -# cd .. -# sbt "cliJS/fastOptJS" -# rm -rf aqua-playground/src/compiled/examples/* -# node cli/.js/target/scala-3.0.1/cli-fastopt.js -i aqua-playground/aqua/examples -o aqua-playground/src/compiled/examples -m aqua-playground/node_modules -c "uniqueConst = 1" -c "anotherConst = \"ab\"" -# cd aqua-playground -# npm run examples + - name: Integration test + run: | + git clone https://github.com/fluencelabs/aqua-playground.git + cd aqua-playground + rm -rf src/compiled/examples/* + npm i + cd .. + sbt "cli/run -i aqua-playground/aqua/examples -o aqua-playground/src/compiled/examples -m aqua-playground/node_modules -c \"UNIQUE_CONST = 1\" -c \"ANOTHER_CONST = \\\"ab\\\"\"" + cd aqua-playground + npm run examples + cd .. + sbt "cliJS/fastOptJS" + rm -rf aqua-playground/src/compiled/examples/* + node cli/.js/target/scala-3.0.1/cli-fastopt.js -i aqua-playground/aqua/examples -o aqua-playground/src/compiled/examples -m aqua-playground/node_modules -c "UNIQUE_CONST = 1" -c "ANOTHER_CONST = \"ab\"" + cd aqua-playground + npm run examples diff --git a/.jvmopts b/.jvmopts index 1321950e..5de9cbcb 100644 --- a/.jvmopts +++ b/.jvmopts @@ -1,6 +1,6 @@ -Dfile.encoding=UTF8 -Xms1G --Xmx5G +-Xmx6G -XX:ReservedCodeCacheSize=500M -XX:+TieredCompilation -XX:+UseParallelGC \ No newline at end of file diff --git a/aqua-src/export.aqua b/aqua-src/export.aqua index 24ef4491..67d492c5 100644 --- a/aqua-src/export.aqua +++ b/aqua-src/export.aqua @@ -1,4 +1,6 @@ -module Export.Test declares foobar, foo, bar +module Export.Test declares foobar, foo, bar, ExpSrv, FA + +const FA = "constant" func bar() -> string: <- " I am MyFooBar bar" @@ -12,5 +14,6 @@ func foobar() -> []string: res <- bar() <- res -service ExpSrv: - baz() \ No newline at end of file +service ExpSrv("exp-srv"): + baz() + log: string -> () \ No newline at end of file diff --git a/aqua-src/import.aqua b/aqua-src/import.aqua index 7a2219f2..937308c9 100644 --- a/aqua-src/import.aqua +++ b/aqua-src/import.aqua @@ -1,8 +1,9 @@ -- import.aqua module Import.Test -import foobar from "export.aqua" +import foobar, FA as C, ExpSrv from "export.aqua" -use foo as f from "export.aqua" as Exp +use foo as f, FA as U from "export.aqua" as Exp +use foo as f, FA from "export.aqua" as Exp1 use "export.aqua" @@ -10,7 +11,13 @@ import "gen/OneMore.aqua" import OneMore as OM from "gen/OneMore.aqua" -export foo_wrapper as wrap, foobar as barfoo +export consts as main--, foobar as barfoo + +func consts(): + ExpSrv.log(C) + ExpSrv.log(Exp.U) + ExpSrv.log(Exp1.FA) + ExpSrv.log(Export.Test.FA) func foo_wrapper() -> string: z <- Exp.f() @@ -20,4 +27,6 @@ func foo_wrapper() -> string: OM "ohmygod" OM.more_call() OM.consume(q) + ExpSrv.log(C) + ExpSrv.log(Exp.U) <- z \ No newline at end of file diff --git a/aqua-src/ret.aqua b/aqua-src/ret.aqua index 13acd12d..e80862bd 100644 --- a/aqua-src/ret.aqua +++ b/aqua-src/ret.aqua @@ -3,7 +3,7 @@ module Ret import Service from "service.aqua" use "error.aqua" -export GetStr, tupleFunc, Service as S +export GetStr, multiReturnFunc, Service as S service GetStr("multiret-test"): retStr: string -> string @@ -11,18 +11,21 @@ service GetStr("multiret-test"): service GetNum("multiret-num"): retNum: -> u8 -const someNum = 5 -const someStr = "some-str" +const SOME_NUM = 5 +const SOME_STR = "some-str" func tupleFunc() -> string, u8: - str <- GetStr.retStr(someStr) + str <- GetStr.retStr(SOME_STR) n <- GetNum.retNum() Err.Peer.is_connected("Connected?") <- str, n func multiReturnFunc(somethingToReturn: []u8, smthOption: ?string) -> []string, u8, string, []u8, ?string, u8: res: *string - res <- GetStr.retStr(someStr) - res <- GetStr.retStr("random-str") + res <- GetStr.retStr(SOME_STR) + try: + res <- GetStr.retStr("random-str") + catch e: + GetStr.retStr(e.msg) res, tNum <- tupleFunc() - <- res, 5, someStr, somethingToReturn, smthOption, tNum + <- res, 5, SOME_STR, somethingToReturn, smthOption, tNum diff --git a/backend/air/src/main/scala/aqua/backend/air/AirGen.scala b/backend/air/src/main/scala/aqua/backend/air/AirGen.scala index 524a4859..dc86df09 100644 --- a/backend/air/src/main/scala/aqua/backend/air/AirGen.scala +++ b/backend/air/src/main/scala/aqua/backend/air/AirGen.scala @@ -29,10 +29,10 @@ object AirGen extends Logging { def valueToData(vm: ValueModel): DataView = vm match { case LiteralModel(value, _) => DataView.StringScalar(value) case VarModel(name, t, lambda) => - val n = t match { + val n = (t match { case _: StreamType => "$" + name case _ => name - } + }).replace('.', '_') if (lambda.isEmpty) DataView.Variable(n) else DataView.VarLens(n, lambdaToString(lambda.toList)) } @@ -43,10 +43,10 @@ object AirGen extends Logging { case list => list.reduceLeft(SeqGen(_, _)) } - def exportToString(exportTo: Call.Export): String = exportTo match { + def exportToString(exportTo: Call.Export): String = (exportTo match { case Call.Export(name, _: StreamType) => "$" + name case Call.Export(name, _) => name - } + }).replace('.', '_') private def folder(op: ResolvedOp, ops: Chain[AirGen]): Eval[AirGen] = op match { diff --git a/build.sbt b/build.sbt index 99182168..29c27c89 100644 --- a/build.sbt +++ b/build.sbt @@ -17,7 +17,7 @@ val declineV = "2.1.0" name := "aqua-hll" val commons = Seq( - baseAquaVersion := "0.2.2", + baseAquaVersion := "0.3.0", version := baseAquaVersion.value + "-" + sys.env.getOrElse("BUILD_NUMBER", "SNAPSHOT"), scalaVersion := dottyVersion, libraryDependencies ++= Seq( diff --git a/cli/.jvm/src/main/scala/aqua/Test.scala b/cli/.jvm/src/main/scala/aqua/Test.scala index 949abb6d..72ddea77 100644 --- a/cli/.jvm/src/main/scala/aqua/Test.scala +++ b/cli/.jvm/src/main/scala/aqua/Test.scala @@ -16,7 +16,7 @@ object Test extends IOApp.Simple { start <- IO(System.currentTimeMillis()) _ <- AquaPathCompiler .compileFilesTo[IO]( - Path("./aqua-src"), + Path("./aqua-src/import.aqua"), List(Path("./aqua")), Path("./target"), TypeScriptBackend, diff --git a/cli/src/main/scala/aqua/AppOps.scala b/cli/src/main/scala/aqua/AppOps.scala index 7c220f95..feb992bd 100644 --- a/cli/src/main/scala/aqua/AppOps.scala +++ b/cli/src/main/scala/aqua/AppOps.scala @@ -97,12 +97,12 @@ object AppOps { def constantOpts[F[_]: LiftParser: Comonad]: Opts[List[TransformConfig.Const]] = Opts - .options[String]("const", "Constant that will be used in an aqua code", "c") + .options[String]("const", "Constant that will be used in an aqua code. Constant name must be upper cased.", "c") .mapValidated { strs => val parsed = strs.map(s => ConstantExpr.onlyLiteral.parseAll(s)) - val errors = parsed.collect { case Left(er) => - er + val errors = parsed.zip(strs).collect { case (Left(er), str) => + str } NonEmptyList @@ -113,7 +113,8 @@ object AppOps { TransformConfig.Const(v._1.value, LiteralModel(v._2.value, v._2.ts)) }) ) { errors => - Validated.invalid(errors.map(_.toString)) + val errorMsgs = errors.map (str => s"Invalid constant definition '$str'.") + Validated.invalid(errorMsgs) } } .withDefault(List.empty) diff --git a/model/src/main/scala/aqua/model/AquaContext.scala b/model/src/main/scala/aqua/model/AquaContext.scala index 845fa017..fa7a4e19 100644 --- a/model/src/main/scala/aqua/model/AquaContext.scala +++ b/model/src/main/scala/aqua/model/AquaContext.scala @@ -27,6 +27,9 @@ case class AquaContext( private def prefixFirst[T](prefix: String, pair: (String, T)): (String, T) = (prefix + pair._1, pair._2) + def isEmpty: Boolean = this == AquaContext.blank + def nonEmpty: Boolean = !isEmpty + def pick( name: String, rename: Option[String], @@ -45,7 +48,19 @@ case class AquaContext( services = getter(_.services) ) } - .filter(_.`type`(name).nonEmpty) + .filter(_.nonEmpty) + + def pickHeader: AquaContext = + AquaContext.blank.copy(module = module, declares = declares, exports = exports) + + def pickDeclared(implicit semi: Semigroup[AquaContext]): AquaContext = + if (module.isEmpty) this + else + declares + .flatMap(pick(_, None)) + .foldLeft(pickHeader)( + _ |+| _ + ) def allTypes(prefix: String = ""): Map[String, Type] = abilities @@ -83,6 +98,7 @@ case class AquaContext( types ++ values.view.mapValues(_.lastType) ++ services.view.mapValues(_.`type`) ++ + // TODO do we need to pass abilities as type? abilities.flatMap { case (n, c) => c.`type`(n).map(n -> _) } diff --git a/model/src/main/scala/aqua/model/ValueModel.scala b/model/src/main/scala/aqua/model/ValueModel.scala index 761489ae..ce222a20 100644 --- a/model/src/main/scala/aqua/model/ValueModel.scala +++ b/model/src/main/scala/aqua/model/ValueModel.scala @@ -100,6 +100,8 @@ case class VarModel(name: String, `type`: Type, lambda: Chain[LambdaModel] = Cha case Some(vv) => vv // TODO check that lambda is empty, otherwise error case None => this // Should not happen } + + override def toString(): String = s"var{$name: " + `type` + s"}.${lambda.toList.mkString(".")}" } object VarModel { diff --git a/model/transform/src/main/scala/aqua/model/transform/TransformConfig.scala b/model/transform/src/main/scala/aqua/model/transform/TransformConfig.scala index 601fc034..b4cb2808 100644 --- a/model/transform/src/main/scala/aqua/model/transform/TransformConfig.scala +++ b/model/transform/src/main/scala/aqua/model/transform/TransformConfig.scala @@ -24,21 +24,39 @@ case class TransformConfig( // or relay's variable otherwise val hostPeerId: TransformConfig.Const = TransformConfig.Const( - "host_peer_id", + "HOST_PEER_ID", relayVarName.fold[ValueModel](LiteralModel.initPeerId)(r => VarModel(r, ScalarType.string)) ) + val initPeerId: TransformConfig.Const = + TransformConfig.Const( + "INIT_PEER_ID", + LiteralModel.initPeerId + ) + + val nil: TransformConfig.Const = + TransformConfig.Const( + "nil", // TODO: shouldn't it be NIL? + LiteralModel.nil + ) + + val lastError: TransformConfig.Const = + TransformConfig.Const( + "LAST_ERROR", + VarModel.lastError + ) + + val constantsMap = + (hostPeerId :: initPeerId :: nil :: lastError :: constants) + .map(c => c.name -> c.value) + .toMap + implicit val aquaContextMonoid: Monoid[AquaContext] = { - val constantsMap = (hostPeerId :: constants).map(c => c.name -> c.value).toMap + AquaContext .implicits( AquaContext.blank - .copy(values = - Map( - VarModel.lastError.name -> VarModel.lastError, - "nil" -> LiteralModel.nil - ) ++ constantsMap - ) + .copy(values = constantsMap) ) .aquaContextMonoid } diff --git a/parser/src/main/scala/aqua/parser/expr/ConstantExpr.scala b/parser/src/main/scala/aqua/parser/expr/ConstantExpr.scala index dc1ed97b..797a8a22 100644 --- a/parser/src/main/scala/aqua/parser/expr/ConstantExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/ConstantExpr.scala @@ -22,14 +22,14 @@ object ConstantExpr extends Expr.Leaf { override def p[F[_]: LiftParser: Comonad]: P[ConstantExpr[F]] = ((((`const` *> ` ` *> Name - .p[F] <* ` `) ~ `?`.?).with1 <* `=` <* ` `) ~ Value.`value`).map { + .upper[F] <* ` `) ~ `?`.?).with1 <* `=` <* ` `) ~ Value.`value`).map { case ((name, mark), value) => ConstantExpr(name, value, mark.nonEmpty) } def onlyLiteral[F[_]: LiftParser: Comonad]: P[(Name[F], Literal[F])] = ((((Name - .p[F] <* ` `) ~ `?`.?).with1 <* `=` <* ` `) ~ Value.literal).map { case ((name, _), value) => + .upper[F] <* ` `) ~ `?`.?).with1 <* `=` <* ` `) ~ Value.literal).map { case ((name, _), value) => (name, value) } } diff --git a/parser/src/main/scala/aqua/parser/head/FromExpr.scala b/parser/src/main/scala/aqua/parser/head/FromExpr.scala index a1ec63b2..fa6a7200 100644 --- a/parser/src/main/scala/aqua/parser/head/FromExpr.scala +++ b/parser/src/main/scala/aqua/parser/head/FromExpr.scala @@ -27,4 +27,10 @@ object FromExpr { def importFrom[F[_]: LiftParser: Comonad]: P[NonEmptyList[NameOrAbAs[F]]] = comma[NameOrAbAs[F]](nameOrAbAs[F]) <* ` ` <* `from` + + def show[F[_]](ne: NonEmptyList[NameOrAbAs[F]]): String = + ne.toList.map(_.fold( + non => non._1.value + non._2.map(_.value).fold("")(" as "+_), + non => non._1.value + non._2.map(_.value).fold("")(" as "+_) + )).mkString(", ") } \ No newline at end of file diff --git a/parser/src/main/scala/aqua/parser/head/ImportExpr.scala b/parser/src/main/scala/aqua/parser/head/ImportExpr.scala index 1c00aa47..be54ddf8 100644 --- a/parser/src/main/scala/aqua/parser/head/ImportExpr.scala +++ b/parser/src/main/scala/aqua/parser/head/ImportExpr.scala @@ -8,8 +8,11 @@ import cats.parse.Parser import cats.~> case class ImportExpr[F[_]](filename: Literal[F]) extends FilenameExpr[F] { + override def mapK[K[_]: Comonad](fk: F ~> K): ImportExpr[K] = copy(filename.mapK(fk)) + + override def toString: String = s"import ${filename.value}" } object ImportExpr extends HeaderExpr.Leaf { diff --git a/parser/src/main/scala/aqua/parser/head/ImportFromExpr.scala b/parser/src/main/scala/aqua/parser/head/ImportFromExpr.scala index a0e84987..4f226caa 100644 --- a/parser/src/main/scala/aqua/parser/head/ImportFromExpr.scala +++ b/parser/src/main/scala/aqua/parser/head/ImportFromExpr.scala @@ -12,8 +12,11 @@ case class ImportFromExpr[F[_]]( imports: NonEmptyList[FromExpr.NameOrAbAs[F]], filename: Literal[F] ) extends FilenameExpr[F] with FromExpr[F] { + override def mapK[K[_]: Comonad](fk: F ~> K): ImportFromExpr[K] = copy(FromExpr.mapK(imports)(fk), filename.mapK(fk)) + + override def toString: String = s"import ${FromExpr.show(imports)} from ${filename.value}" } object ImportFromExpr extends HeaderExpr.Leaf { diff --git a/parser/src/main/scala/aqua/parser/head/UseExpr.scala b/parser/src/main/scala/aqua/parser/head/UseExpr.scala index a7f44aaf..80871ca6 100644 --- a/parser/src/main/scala/aqua/parser/head/UseExpr.scala +++ b/parser/src/main/scala/aqua/parser/head/UseExpr.scala @@ -11,8 +11,12 @@ case class UseExpr[F[_]]( filename: Literal[F], asModule: Option[Ability[F]] ) extends FilenameExpr[F] { + override def mapK[K[_]: Comonad](fk: F ~> K): UseExpr[K] = copy(filename.mapK(fk), asModule.map(_.mapK(fk))) + + override def toString(): String = + s"use ${filename.value}${asModule.map(_.value).fold("")(" as " + _)}" } object UseExpr extends HeaderExpr.Leaf { diff --git a/parser/src/main/scala/aqua/parser/head/UseFromExpr.scala b/parser/src/main/scala/aqua/parser/head/UseFromExpr.scala index fa8a1db0..a70edabf 100644 --- a/parser/src/main/scala/aqua/parser/head/UseFromExpr.scala +++ b/parser/src/main/scala/aqua/parser/head/UseFromExpr.scala @@ -16,6 +16,9 @@ case class UseFromExpr[F[_]]( override def mapK[K[_]: Comonad](fk: F ~> K): UseFromExpr[K] = copy(FromExpr.mapK(imports)(fk), filename.mapK(fk), asModule.mapK(fk)) + + override def toString(): String = + s"use ${FromExpr.show(imports)} from ${filename.value} as ${asModule.value}" } object UseFromExpr extends HeaderExpr.Leaf { diff --git a/parser/src/main/scala/aqua/parser/lexer/Name.scala b/parser/src/main/scala/aqua/parser/lexer/Name.scala index b12bd851..4b7f25ff 100644 --- a/parser/src/main/scala/aqua/parser/lexer/Name.scala +++ b/parser/src/main/scala/aqua/parser/lexer/Name.scala @@ -24,8 +24,11 @@ object Name { def p[F[_]: LiftParser: Comonad]: P[Name[F]] = `name`.lift.map(Name(_)) + def upper[F[_]: LiftParser: Comonad]: P[Name[F]] = + NAME.lift.map(Name(_)) + def dotted[F[_]: LiftParser: Comonad]: P[Name[F]] = - ((`Class`.repSep(`.`).map(_.toList.mkString(".")) ~ `.`).?.with1 ~ `name`).string.lift + ((`Class` ~ `.`).backtrack.rep0.?.with1 ~ P.oneOf(`name` :: NAME :: Nil)).string.lift .map(Name(_)) def nameAs[F[_]: LiftParser: Comonad]: P[As[F]] = diff --git a/parser/src/main/scala/aqua/parser/lexer/Token.scala b/parser/src/main/scala/aqua/parser/lexer/Token.scala index 26ba235e..9a349395 100644 --- a/parser/src/main/scala/aqua/parser/lexer/Token.scala +++ b/parser/src/main/scala/aqua/parser/lexer/Token.scala @@ -19,8 +19,10 @@ object Token { private val AZ = ('A' to 'Z').toSet private val f09 = ('0' to '9').toSet private val anum = az ++ AZ ++ f09 + private val upperAnum = AZ ++ f09 private val f_ = Set('_') private val anum_ = anum ++ f_ + private val upperAnum_ = upperAnum ++ f_ private val nl = Set('\n', '\r') val ` *` : P0[String] = P.charsWhile0(fSpaces) @@ -59,9 +61,10 @@ object Token { val ` : ` : P[Unit] = P.char(':').surroundedBy(` `.?) val `anum_*` : P[Unit] = P.charsWhile(anum_).void + val NAME: P[String] = P.charsWhile(upperAnum_).string val `name`: P[String] = (P.charIn(az) ~ P.charsWhile(anum_).?).string - val `Class`: P[String] = (P.charIn(AZ) ~ P.charsWhile(anum_).?).map { case (c, s) ⇒ + val `Class`: P[String] = (P.charIn(AZ) ~ P.charsWhile(anum_).backtrack.?).map { case (c, s) ⇒ c.toString ++ s.getOrElse("") } val `\n` : P[Unit] = P.string("\n\r") | P.char('\n') | P.string("\r\n") diff --git a/parser/src/test/scala/aqua/parser/AssignmentExprSpec.scala b/parser/src/test/scala/aqua/parser/AssignmentExprSpec.scala index f089ff54..8050f195 100644 --- a/parser/src/test/scala/aqua/parser/AssignmentExprSpec.scala +++ b/parser/src/test/scala/aqua/parser/AssignmentExprSpec.scala @@ -18,16 +18,16 @@ class AssignmentExprSpec extends AnyFlatSpec with Matchers with AquaSpec { AssignmentExpr[Id]("a", toVar("b")) ) - parseConstant("const a = b") should be( - ConstantExpr[Id]("a", toVar("b"), skipIfAlreadyDefined = false) + 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 = false) ) - parseConstant("const a ?= 1") should be( - ConstantExpr[Id]("a", toNumber(1), skipIfAlreadyDefined = true) + parseConstant("const A ?= 1") should be( + ConstantExpr[Id]("A", toNumber(1), skipIfAlreadyDefined = true) ) } } diff --git a/parser/src/test/scala/aqua/parser/head/FromSpec.scala b/parser/src/test/scala/aqua/parser/head/FromSpec.scala index d70db83a..5060576b 100644 --- a/parser/src/test/scala/aqua/parser/head/FromSpec.scala +++ b/parser/src/test/scala/aqua/parser/head/FromSpec.scala @@ -14,6 +14,12 @@ class FromSpec extends AnyFlatSpec with Matchers with AquaSpec { import AquaSpec.* + "from constants" should "be parsed" in { + FromExpr.nameOrAbAs[Id].parseAll("SOME_CONSTANT").value shouldBe Right((toAb("SOME_CONSTANT"), None)) + + FromExpr.nameOrAbAs[Id].parseAll("SOME_CONSTANT as SC").value shouldBe Right((toAb("SOME_CONSTANT"), Some(toAb("SC")))) + } + "from expression" should "be parsed" in { FromExpr.nameOrAbAs[Id].parseAll("Ability").value should be(Right(toAb("Ability") -> None)) FromExpr.nameOrAbAs[Id].parseAll("Ability as Ab").value should be( diff --git a/parser/src/test/scala/aqua/parser/head/UseSpec.scala b/parser/src/test/scala/aqua/parser/head/UseSpec.scala new file mode 100644 index 00000000..b4fc34d1 --- /dev/null +++ b/parser/src/test/scala/aqua/parser/head/UseSpec.scala @@ -0,0 +1,30 @@ +package aqua.parser.head + +import aqua.AquaSpec +import aqua.parser.expr.AbilityIdExpr +import aqua.parser.lexer.{Literal, Token} +import aqua.parser.lift.LiftParser.Implicits.* +import aqua.types.LiteralType +import cats.Id +import cats.data.NonEmptyList +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +class UseSpec extends AnyFlatSpec with Matchers with AquaSpec { + + import AquaSpec.* + + "use" should "be parsed" in { + UseFromExpr.p[Id].parseAll("use DECLARE_CONST2 as DC2 from \"declare.aqua\" as Declare").value shouldBe + UseFromExpr( + NonEmptyList.one(Right((toAb("DECLARE_CONST2"), Some(toAb("DC2"))))), + toStr("declare.aqua"), + toAb("Declare")) + + UseFromExpr.p[Id].parseAll("use DECLARE_CONST from \"declare.aqua\" as Declare").value shouldBe + UseFromExpr( + NonEmptyList.one(Right((toAb("DECLARE_CONST"), None))), + toStr("declare.aqua"), + toAb("Declare")) + } +} diff --git a/parser/src/test/scala/aqua/parser/lexer/TokenSpec.scala b/parser/src/test/scala/aqua/parser/lexer/TokenSpec.scala index f52760c1..63811e0a 100644 --- a/parser/src/test/scala/aqua/parser/lexer/TokenSpec.scala +++ b/parser/src/test/scala/aqua/parser/lexer/TokenSpec.scala @@ -44,4 +44,12 @@ class TokenSpec extends AnyFlatSpec with Matchers with EitherValues { |""".stripMargin).value should be(()) } + "name token" should "parse" in { + `name`.parseAll("some_name").value should be("some_name") + } + + "NAME token" should "parse" in { + NAME.parseAll("SOME_NAME").value should be("SOME_NAME") + } + } diff --git a/parser/src/test/scala/aqua/parser/lexer/VarLambdaSpec.scala b/parser/src/test/scala/aqua/parser/lexer/VarLambdaSpec.scala new file mode 100644 index 00000000..14fbccaa --- /dev/null +++ b/parser/src/test/scala/aqua/parser/lexer/VarLambdaSpec.scala @@ -0,0 +1,26 @@ +package aqua.parser.lexer + +import aqua.parser.lift.LiftParser.Implicits.idLiftParser +import cats.Id +import cats.data.NonEmptyList +import org.scalatest.EitherValues +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +class VarLambdaSpec extends AnyFlatSpec with Matchers with EitherValues { + + "var lambda" should "parse" in { + val opsP = (s: String) => Name.dotted[Id].parseAll(s).value + + opsP("SomeClass.some_val") should be(Name[Id]("SomeClass.some_val")) + + opsP("some_val") should be(Name[Id]("some_val")) + + opsP("SOME_CONST") should be(Name[Id]("SOME_CONST")) + + opsP("SomeClass.SOME_CONST") should be(Name[Id]("SomeClass.SOME_CONST")) + + + } + +} diff --git a/semantics/src/main/scala/aqua/semantics/CompilerState.scala b/semantics/src/main/scala/aqua/semantics/CompilerState.scala index 87bdcd88..77138d3f 100644 --- a/semantics/src/main/scala/aqua/semantics/CompilerState.scala +++ b/semantics/src/main/scala/aqua/semantics/CompilerState.scala @@ -18,15 +18,12 @@ case class CompilerState[F[_]]( object CompilerState { type S[F[_]] = State[CompilerState[F], Model] - def init[F[_]](ctx: AquaContext): CompilerState[F] = { - // TODO: should go to Monoid[AquaContext].empty, along with overriden constants - val withLE = ctx.copy(values = ctx.values + ("%last_error%" -> VarModel.lastError)) + def init[F[_]](ctx: AquaContext): CompilerState[F] = CompilerState( - names = NamesState.init[F](withLE), - abilities = AbilitiesState.init[F](withLE), - types = TypesState.init[F](withLE) + names = NamesState.init[F](ctx), + abilities = AbilitiesState.init[F](ctx), + types = TypesState.init[F](ctx) ) - } implicit def compilerStateMonoid[F[_]]: Monoid[S[F]] = new Monoid[S[F]] { override def empty: S[F] = State.pure(EmptyModel("compiler state monoid empty")) diff --git a/semantics/src/main/scala/aqua/semantics/header/HeaderSem.scala b/semantics/src/main/scala/aqua/semantics/header/HeaderSem.scala index 20420bdf..53463b60 100644 --- a/semantics/src/main/scala/aqua/semantics/header/HeaderSem.scala +++ b/semantics/src/main/scala/aqua/semantics/header/HeaderSem.scala @@ -58,6 +58,7 @@ object HeaderSem { def resolve(f: FilenameExpr[S]): ResAC[S] = imports .get(f.fileValue) + .map(_.pickDeclared) .fold[ResAC[S]]( error(f.token, "Cannot resolve the import") )(validNec) @@ -91,7 +92,7 @@ object HeaderSem { } ) ) - .reduce + .foldLeft[ResAC[S]](validNec(ctx.pickHeader))(_ |+| _) // Convert an imported context into a module (ability) def toModule(ctx: AquaContext, tkn: Token[S], rename: Option[Ability[S]]): ResAC[S] = @@ -103,7 +104,7 @@ object HeaderSem { tkn, s"Used module has no `module` header. Please add `module` header or use ... as ModuleName, or switch to import" ) - )(modName => validNec(acm.empty.copy(abilities = Map(modName -> ctx)))) + )(modName => validNec(AquaContext.blank.copy(abilities = Map(modName -> ctx)))) // Handler for every header expression, will be combined later val onExpr: PartialFunction[HeaderExpr[S], Res[S]] = { @@ -154,27 +155,33 @@ object HeaderSem { // Import, map declarations resolve(f) .andThen(getFrom(f, _)) - .map(ctx => HeaderSem[S](ctx, (c, _) => validNec(c))) + .map { ctx => + HeaderSem[S](ctx, (c, _) => validNec(c)) + } case f @ UseExpr(_, asModule) => // Import, move into a module scope resolve(f) .andThen(toModule(_, f.token, asModule)) - .map(fc => HeaderSem[S](fc, (c, _) => validNec(c))) + .map { fc => + HeaderSem[S](fc, (c, _) => validNec(c)) + } case f @ UseFromExpr(_, _, asModule) => // Import, cherry-pick declarations, move to a module scope resolve(f) .andThen(getFrom(f, _)) .andThen(toModule(_, f.token, Some(asModule))) - .map(fc => HeaderSem[S](fc, (c, _) => validNec(c))) + .map { fc => + HeaderSem[S](fc, (c, _) => validNec(c)) + } case ExportExpr(pubs) => // Save exports, finally handle them validNec( HeaderSem[S]( // Nothing there - acm.empty, + AquaContext.blank, (ctx, initCtx) => pubs .map( @@ -197,7 +204,7 @@ object HeaderSem { } ) ) - .foldLeft[ResAC[S]](validNec(ctx.exports.getOrElse(acm.empty)))(_ |+| _) + .foldLeft[ResAC[S]](validNec(ctx.exports.getOrElse(AquaContext.blank)))(_ |+| _) .map(expCtx => ctx.copy(exports = Some(expCtx))) ) ) diff --git a/semantics/src/main/scala/aqua/semantics/rules/ValuesAlgebra.scala b/semantics/src/main/scala/aqua/semantics/rules/ValuesAlgebra.scala index 40b3e987..fa103daa 100644 --- a/semantics/src/main/scala/aqua/semantics/rules/ValuesAlgebra.scala +++ b/semantics/src/main/scala/aqua/semantics/rules/ValuesAlgebra.scala @@ -39,7 +39,7 @@ class ValuesAlgebra[F[_], Alg[_]](implicit N: NamesAlgebra[F, Alg], T: TypesAlge case Some(t) => T.resolveLambda(t, ops) .map(Chain.fromSeq) - .map(VarModel(name.value.replace('.', '_'), t, _)) + .map(VarModel(name.value, t, _)) .map(Some(_)) case None => Free.pure(None)