Skip to content

Commit

Permalink
fix(compiler): Generate stream restriction for scoped exprs [fixes LN…
Browse files Browse the repository at this point in the history
…G-222] (#841)

* Add show for AST

* Update ForSem

* Fix if and try

* Fix else, otherwise, catch, add tests

* Add integration tests
  • Loading branch information
InversionSpaces authored Aug 17, 2023
1 parent f562bd4 commit eb4cdb0
Show file tree
Hide file tree
Showing 17 changed files with 406 additions and 91 deletions.
18 changes: 15 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ lazy val parser = crossProject(JVMPlatform, JSPlatform)
"org.typelevel" %%% "cats-free" % catsV
)
)
.dependsOn(types)
.dependsOn(types, helpers)

lazy val linker = crossProject(JVMPlatform, JSPlatform)
.withoutSuffixFor(JVMPlatform)
Expand All @@ -200,6 +200,7 @@ lazy val tree = crossProject(JVMPlatform, JSPlatform)
"org.typelevel" %%% "cats-free" % catsV
)
)
.dependsOn(helpers)

lazy val raw = crossProject(JVMPlatform, JSPlatform)
.withoutSuffixFor(JVMPlatform)
Expand All @@ -212,7 +213,7 @@ lazy val model = crossProject(JVMPlatform, JSPlatform)
.withoutSuffixFor(JVMPlatform)
.crossType(CrossType.Pure)
.settings(commons)
.dependsOn(types, tree, raw)
.dependsOn(types, tree, raw, helpers)

lazy val res = crossProject(JVMPlatform, JSPlatform)
.withoutSuffixFor(JVMPlatform)
Expand All @@ -228,7 +229,6 @@ lazy val inline = crossProject(JVMPlatform, JSPlatform)
.settings(commons)
.dependsOn(raw, model)


lazy val transform = crossProject(JVMPlatform, JSPlatform)
.withoutSuffixFor(JVMPlatform)
.crossType(CrossType.Pure)
Expand Down Expand Up @@ -304,6 +304,18 @@ lazy val constants = crossProject(JVMPlatform, JSPlatform)
)
.dependsOn(parser, raw)

lazy val helpers = crossProject(JVMPlatform, JSPlatform)
.withoutSuffixFor(JVMPlatform)
.crossType(CrossType.Pure)
.in(file("utils/helpers"))
.settings(commons)
.settings(
libraryDependencies ++= Seq(
"org.typelevel" %%% "cats-core" % catsV,
"org.typelevel" %%% "cats-free" % catsV
)
)

lazy val `backend-air` = crossProject(JVMPlatform, JSPlatform)
.withoutSuffixFor(JVMPlatform)
.crossType(CrossType.Pure)
Expand Down
83 changes: 83 additions & 0 deletions integration-tests/aqua/examples/streamScopes.aqua
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
aqua StreamExports

export FailureSrv, streamIf, streamTry, streamFor, streamComplex

service FailureSrv("failure"):
fail(msg: string)

func streamIf() -> i8:
on HOST_PEER_ID:
if true:
stream: *i8
stream <<- 1
else:
stream: *i8
stream <<- 2

if false:
stream: *i8
stream <<- 3
else:
stream: *i8
stream <<- 4

stream: *i8
stream <<- 5

<- stream!

func streamTry() -> i8:
on HOST_PEER_ID:
try:
stream: *i8
stream <<- 1
FailureSrv.fail("try")
catch e:
stream: *i8
stream <<- 2
FailureSrv.fail("catch")
otherwise:
stream: *i8
stream <<- 3

stream: *i8
stream <<- 4

<- stream!

func streamFor() -> i8:
on HOST_PEER_ID:
for i <- [1, 2, 3]:
stream: *i8
stream <<- i

stream: *i8
stream <<- 4

<- stream!

func streamComplex() -> i8:
on HOST_PEER_ID:
for i <- [1, 2, 3]:
try:
if i == 2:
stream: *i8
stream <<- i
FailureSrv.fail("if")
else:
stream: *i8
stream <<- i

stream: *i8
stream <<- i + 3
catch e:
stream: *i8
stream <<- i + 6

stream: *i8
stream <<- i + 9

stream: *i8
stream <<- 13

<- stream!
25 changes: 25 additions & 0 deletions integration-tests/src/__test__/examples.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { coCall } from '../examples/coCall.js';
import { bugLNG60Call, passArgsCall } from '../examples/passArgsCall.js';
import { streamArgsCall } from '../examples/streamArgsCall.js';
import { streamResultsCall } from '../examples/streamResultsCall.js';
import { streamIfCall, streamForCall, streamTryCall, streamComplexCall } from '../examples/streamScopes.js';
import { pushToStreamCall } from '../examples/pushToStreamCall.js';
import { literalCall } from '../examples/returnLiteralCall.js';
import { multiReturnCall } from '../examples/multiReturnCall.js';
Expand Down Expand Up @@ -158,6 +159,30 @@ describe('Testing examples', () => {
expect(streamResResult).toEqual([[], ['a', 'b', 'c']]);
});

it('streamScopes.aqua streamIf', async () => {
let streamIfResult = await streamIfCall();

expect(streamIfResult).toEqual(5);
});

it('streamScopes.aqua streamTry', async () => {
let streamTryResult = await streamTryCall();

expect(streamTryResult).toEqual(4);
});

it('streamScopes.aqua streamFor', async () => {
let streamTryResult = await streamForCall();

expect(streamTryResult).toEqual(4);
});

it('streamScopes.aqua streamComplex', async () => {
let streamTryResult = await streamComplexCall();

expect(streamTryResult).toEqual(13);
});

it('if.aqua', async () => {
await ifCall();
});
Expand Down
35 changes: 35 additions & 0 deletions integration-tests/src/examples/streamScopes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
streamIf,
streamTry,
streamFor,
streamComplex,
registerFailureSrv,
} from '../compiled/examples/streamScopes.js';

export async function streamIfCall() {
return await streamIf();
}

export async function streamTryCall() {
registerFailureSrv({
fail: (msg) => {
return Promise.reject(msg);
},
});

return await streamTry();
}

export async function streamForCall() {
return await streamFor();
}

export async function streamComplexCall() {
registerFailureSrv({
fail: (msg) => {
return Promise.reject(msg);
},
});

return await streamComplex();
}
6 changes: 4 additions & 2 deletions model/tree/src/main/scala/aqua/tree/TreeNodeCompanion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ import cats.syntax.apply.*

import scala.annotation.tailrec

import aqua.helpers.Tree

trait TreeNodeCompanion[T <: TreeNode[T]] {

given showTreeLabel: Show[T]

type Tree = Cofree[Chain, T]

// TODO: Use helpers.Tree istead of this function
private def showOffset(what: Tree, offset: Int): String = {
val spaces = "| " * offset
spaces + what.head.show + what.tail.map {
Expand Down Expand Up @@ -98,8 +101,7 @@ trait TreeNodeCompanion[T <: TreeNode[T]] {

given Show[Tree] with

override def show(t: Tree): String =
showOffset(t, 0)
override def show(t: Tree): String = Tree.show(t)

given Show[(Tree, Tree)] with

Expand Down
15 changes: 14 additions & 1 deletion parser/src/main/scala/aqua/parser/Ast.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import aqua.parser.expr.*
import aqua.parser.head.{HeadExpr, HeaderExpr}
import aqua.parser.lift.{LiftParser, Span}
import aqua.parser.lift.LiftParser.*
import aqua.helpers.Tree

import cats.data.{Chain, Validated, ValidatedNec}
import cats.free.Cofree
import cats.{Comonad, Eval}
import cats.~>
import cats.Show

case class Ast[S[_]](head: Ast.Head[S], tree: Ast.Tree[S]) {

Expand All @@ -19,6 +22,16 @@ case class Ast[S[_]](head: Ast.Head[S], tree: Ast.Tree[S]) {
}

object Ast {
type Tree[S[_]] = Cofree[Chain, Expr[S]]
type Head[S[_]] = Cofree[Chain, HeaderExpr[S]]
type Tree[S[_]] = Cofree[Chain, Expr[S]]

given [S[_]]: Show[Ast[S]] with {

def show(ast: Ast[S]): String = {
val head = Tree.show(ast.head)
val body = Tree.show(ast.tree)

s"$head\n$body"
}
}
}
11 changes: 9 additions & 2 deletions parser/src/main/scala/aqua/parser/Expr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ import aqua.parser.expr.func.ReturnExpr
import aqua.parser.lift.LiftParser.*
import aqua.parser.lift.Span.{P0ToSpan, PToSpan}
import aqua.parser.lift.{LiftParser, Span}
import aqua.parser.Ast.Tree
import aqua.parser.ListToTreeConverter

import cats.data.Chain.:==
import cats.data.{Chain, NonEmptyChain, Validated, ValidatedNec}
import cats.free.Cofree
import cats.Show
import cats.data.Validated.{invalid, invalidNec, invalidNel, valid, validNec, validNel}
import cats.parse.{Parser as P, Parser0 as P0}
import cats.syntax.comonad.*
import cats.{~>, Comonad, Eval}
import scribe.Logging
import aqua.parser.Ast.Tree
import aqua.parser.ListToTreeConverter

abstract class Expr[F[_]](val companion: Expr.Companion, val token: Token[F]) {

Expand Down Expand Up @@ -109,4 +111,9 @@ object Expr {
.result
}
}

given [S[_]]: Show[Expr[S]] with {
// TODO: Make it better
def show(e: Expr[S]): String = e.toString
}
}
13 changes: 10 additions & 3 deletions parser/src/main/scala/aqua/parser/head/HeaderExpr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ package aqua.parser.head
import aqua.parser.Ast
import aqua.parser.lexer.Token
import aqua.parser.lift.LiftParser
import aqua.parser.lift.Span
import aqua.parser.lift.Span.{P0ToSpan, PToSpan}

import cats.{Comonad, Eval}
import cats.data.Chain
import cats.free.Cofree
import cats.Show
import cats.parse.Parser as P
import cats.~>
import aqua.parser.lift.Span
import aqua.parser.lift.Span.{P0ToSpan, PToSpan}

trait HeaderExpr[S[_]] {
def token: Token[S]

def mapK[K[_]: Comonad](fk: S ~> K): HeaderExpr[K]
}

Expand All @@ -30,4 +32,9 @@ object HeaderExpr {
override def ast: P[Ast.Head[Span.S]] =
p.map(Cofree[Chain, HeaderExpr[Span.S]](_, Eval.now(Chain.empty)))
}

given [S[_]]: Show[HeaderExpr[S]] with {
// TODO: Make it better
def show(e: HeaderExpr[S]): String = e.toString
}
}
26 changes: 13 additions & 13 deletions semantics/src/main/scala/aqua/semantics/expr/func/CatchSem.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@ class CatchSem[S[_]](val expr: CatchExpr[S]) extends AnyVal {
): Prog[Alg, Raw] =
Prog
.around(
N.beginScope(expr.name) >>
L.beginScope() >>
N.define(expr.name, ValueRaw.lastError.baseType),
N.define(expr.name, ValueRaw.lastError.baseType),
(_, g: Raw) =>
N.endScope() >> L.endScope() as (
g match {
case FuncOp(op) =>
TryTag.Catch
g match {
case FuncOp(op) =>
for {
restricted <- FuncOpSem.restrictStreamsInScope(op)
tag = TryTag.Catch
.wrap(
SeqTag.wrap(
AssignmentTag(ValueRaw.lastError, expr.name.value).leaf,
op
restricted
)
)
.toFuncOp
case _ =>
Raw.error("Wrong body of the `catch` expression")
}
)
} yield tag.toFuncOp
case _ =>
Raw.error("Wrong body of the `catch` expression").pure
}
)
.abilitiesScope[S](expr.token)
.namesScope(expr.token)
.locationsScope()

}
Loading

0 comments on commit eb4cdb0

Please sign in to comment.