Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New quasiquote implementation #182

Merged
merged 133 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from 121 commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
a1e3b20
Cherry-pick old quasiquote code and re-implement typing
NeilKleistGao Sep 22, 2023
fd25c5c
Merge from new-definition-typing
NeilKleistGao Sep 23, 2023
921d732
Add some scope safety tests
LPTK Sep 23, 2023
f9cc954
WIP: Fix scope?
NeilKleistGao Sep 24, 2023
4e6b709
Fix scope
NeilKleistGao Sep 25, 2023
53ffa3a
Fix qget
NeilKleistGao Sep 25, 2023
517b056
Fix several problems
NeilKleistGao Sep 25, 2023
d388b3a
Provide name hints and remove debug info
NeilKleistGao Sep 25, 2023
d7d4907
WIP: Add some code gen logics
NeilKleistGao Sep 26, 2023
b6f3583
WIP: Add codegen
NeilKleistGao Sep 27, 2023
a122cb0
Remove Const desugar
NeilKleistGao Sep 27, 2023
6e1e06c
Fix operators in unquotes
NeilKleistGao Oct 2, 2023
371acf3
Fix quoted let desugar
NeilKleistGao Oct 3, 2023
50413d9
Update Codegen
NeilKleistGao Oct 3, 2023
2f6a81f
Merge branch 'new-definition-typing' into newQ – some tests now need …
LPTK Oct 5, 2023
77ca6be
Move QQ tests to folder w/ shorter name
LPTK Oct 5, 2023
9ada645
Add a bunch of QQ tests, some exposing current problems/limitations
LPTK Oct 5, 2023
aad64e3
WIP: Fix test cases
NeilKleistGao Oct 6, 2023
2455385
WIP: Fix extrusion
NeilKleistGao Oct 6, 2023
8d2c3c6
Add effectful let insertion interface example in test
LPTK Oct 6, 2023
aeb81fd
WIP: Fix top-level def access
NeilKleistGao Oct 6, 2023
e174477
Merge branch 'newQ' of github.com:NeilKleistGao/mlscript into newQ
NeilKleistGao Oct 6, 2023
508fbd3
WIP: Add FIXME
NeilKleistGao Oct 6, 2023
652a455
WIP: Add printer
NeilKleistGao Oct 6, 2023
4c46dea
WIP: finish unquote
NeilKleistGao Oct 6, 2023
fd980ef
WIP: Fix typer
NeilKleistGao Oct 6, 2023
f5401db
WIP: Improve pretty print
NeilKleistGao Oct 7, 2023
17d9675
WIP: Improve
NeilKleistGao Oct 7, 2023
119ac66
Merge from new-definition-typing
NeilKleistGao Oct 7, 2023
806516f
Remove newline
NeilKleistGao Oct 7, 2023
84f516b
Optimize pretty printer
NeilKleistGao Oct 7, 2023
e51b990
Merge from new-definition-typing
NeilKleistGao Oct 14, 2023
9821c32
WIP: Add new syntax
NeilKleistGao Oct 14, 2023
5204ec5
WIP: Floating parsing
NeilKleistGao Oct 15, 2023
65c1c8b
WIP: Fix binding env
NeilKleistGao Oct 15, 2023
113a07a
WIP: Parse quoted let
NeilKleistGao Oct 15, 2023
aa57568
WIP: Parse quoted application
NeilKleistGao Oct 15, 2023
b2e573c
WIP: Fix example on paper
NeilKleistGao Oct 15, 2023
a3da5e8
WIP: Parse quoted if
NeilKleistGao Oct 15, 2023
b234cd9
WIP: Add error messages
NeilKleistGao Oct 15, 2023
a645b6d
WIP: Fix op parsing
NeilKleistGao Oct 15, 2023
8c46039
WIP: Fix compare parsing
NeilKleistGao Oct 16, 2023
cc02274
WIP: Improve test case
NeilKleistGao Oct 16, 2023
4fdfc97
WIP: Fix some problems
NeilKleistGao Oct 16, 2023
3446fd6
WIP: Fix error desugar
NeilKleistGao Oct 17, 2023
80d4e17
Add quoted error
NeilKleistGao Oct 21, 2023
26d0c18
Fix web demo print
NeilKleistGao Oct 22, 2023
8d185e3
Merge branch 'new-definition-typing' of https://github.com/hkust-taco…
NeilKleistGao Oct 24, 2023
8f513d2
WIP: Rerun test
NeilKleistGao Oct 24, 2023
5aa7e82
WIP: Draft new pretty printer
NeilKleistGao Oct 24, 2023
80dc1a9
Refactor quote parsing
NeilKleistGao Nov 1, 2023
b8f60d2
Fix some bugs
NeilKleistGao Nov 15, 2023
6c0855f
Simplify away skolems
LPTK Nov 24, 2023
2bb2cc3
Refactor code
NeilKleistGao Nov 29, 2023
10ec544
Merge from new-definition typing
NeilKleistGao Nov 29, 2023
320121a
Fix merge mistakes
NeilKleistGao Nov 29, 2023
8c2d4f3
Fix matching
NeilKleistGao Nov 29, 2023
90ed438
Refactor
NeilKleistGao Nov 29, 2023
96cc8ef
Keep unwrap function
NeilKleistGao Nov 29, 2023
907c2b9
Refactor
NeilKleistGao Nov 29, 2023
8cf1cba
Simplify ctx
NeilKleistGao Nov 29, 2023
a34e8ac
WIP: Minor changes
NeilKleistGao Dec 1, 2023
b459498
Merge branch 'new-definition-typing' into newQ
NeilKleistGao Dec 1, 2023
aa40022
WIP: Rerun test cases
NeilKleistGao Dec 1, 2023
5be1c3f
WIP: Remove IsQuoted and add field flags
NeilKleistGao Dec 1, 2023
f89b6e9
WIP: Add var type and remove implicit sets
NeilKleistGao Dec 1, 2023
73cce68
WIP: Refactor desugarQuote
NeilKleistGao Dec 2, 2023
d6f000e
WIP: Simplify parser
NeilKleistGao Dec 4, 2023
166e277
WIP: Refactor
NeilKleistGao Dec 4, 2023
b24a46a
Refactor
NeilKleistGao Dec 4, 2023
0c6fc41
Fix locations and provs
NeilKleistGao Dec 5, 2023
a889f8a
Fix quotes insertion and update the comments
NeilKleistGao Dec 5, 2023
70c60da
Minor changes
NeilKleistGao Dec 5, 2023
1afc4b4
Minor changes
NeilKleistGao Dec 5, 2023
00c755c
Minor changes
NeilKleistGao Dec 6, 2023
ee8d476
Merge branch 'new-definition-typing' into newQ
NeilKleistGao Dec 6, 2023
3246845
Undo
NeilKleistGao Dec 6, 2023
402b5c1
Merge branch 'new-definition-typing' into newQ
NeilKleistGao Dec 11, 2023
4f2ea36
Merge from new-definition-typing
NeilKleistGao Jan 2, 2024
b0e4693
Merge from new-definition-typing
NeilKleistGao Jan 3, 2024
bd763df
Merge from new-definition-typing
NeilKleistGao Jan 12, 2024
3485e3c
Merge from new-definition-typing
NeilKleistGao Jan 15, 2024
91dd726
Merge mlscript
NeilKleistGao Feb 1, 2024
eb4d613
Merge branch 'newQ-simplif' into newQ (has diff-test conflicts)
LPTK Feb 1, 2024
b32cad9
Resolve diff-test conflicts (some tests fail)
LPTK Feb 1, 2024
de1ffb1
Fix tests
LPTK Feb 1, 2024
5676f7c
Fix/update tests
LPTK Feb 1, 2024
4e95a37
Merge branch 'mlscript' into newQ
LPTK Feb 1, 2024
d4e2d00
Update shared/src/main/scala/mlscript/helpers.scala
NeilKleistGao Feb 2, 2024
f786cc1
Add weirdQ test cases and remove finished TODO and FIXME in test cases
NeilKleistGao Feb 2, 2024
a033b5f
Make FreeVars a class
NeilKleistGao Feb 2, 2024
129bc29
Update shared/src/main/scala/mlscript/JSBackend.scala
NeilKleistGao Feb 3, 2024
722a0c6
Update shared/src/main/scala/mlscript/JSBackend.scala
NeilKleistGao Feb 3, 2024
5bfdd72
Update shared/src/main/scala/mlscript/Token.scala
NeilKleistGao Feb 3, 2024
1931d72
Merge from mlscript
NeilKleistGao Feb 3, 2024
9d90e64
WIP: Fix some problems in codegen
NeilKleistGao Feb 5, 2024
f5831c6
WIP: Refactor typer
NeilKleistGao Feb 5, 2024
a36856c
WIP: Update err msg and add err test cases
NeilKleistGao Feb 5, 2024
a0f90a4
WIP: Refactor lexer
NeilKleistGao Feb 6, 2024
3ab49b9
WIP: Minor changes
NeilKleistGao Feb 6, 2024
8a17b5b
WIP: Refactor err msg with def
NeilKleistGao Feb 6, 2024
3d33d27
WIP: Refine `exprCont` function
NeilKleistGao Feb 6, 2024
73a7d86
WIP: Minor changes
NeilKleistGao Feb 6, 2024
cb2f862
WIP: Update lexer
NeilKleistGao Feb 7, 2024
e1352d5
WIP: Minor changes
NeilKleistGao Feb 7, 2024
e70865d
WIP: Minor changes
NeilKleistGao Feb 7, 2024
e3a3486
Merge branch 'mlscript' into newQ
NeilKleistGao Feb 16, 2024
2be8ca1
Update names and comments
NeilKleistGao Feb 16, 2024
0e04dc7
Update comments
NeilKleistGao Feb 16, 2024
a9e6837
Update shared/src/main/scala/mlscript/NuTypeDefs.scala
NeilKleistGao Feb 17, 2024
68c4e6f
Update shared/src/main/scala/mlscript/Typer.scala
NeilKleistGao Feb 17, 2024
4bf33ef
Recover missing test cases
NeilKleistGao Feb 17, 2024
612213a
Refactor typer
NeilKleistGao Feb 17, 2024
7e85483
Refactor typer
NeilKleistGao Feb 17, 2024
b4e7945
Make `ctx: ShowCtx` implicit
NeilKleistGao Feb 17, 2024
83ca44a
Update err msg
NeilKleistGao Feb 17, 2024
caf7dd6
Refactor typer
NeilKleistGao Feb 17, 2024
fa03614
Remove unhelp code
NeilKleistGao Feb 17, 2024
8d18d1a
Refactor typer
NeilKleistGao Feb 17, 2024
69daed1
Refactor typer
NeilKleistGao Feb 18, 2024
ad5cf5d
Fix pp of qq and add test cases
NeilKleistGao Feb 18, 2024
0fc2fd9
Force `` `in `` for quoted let bindings
NeilKleistGao Feb 19, 2024
cee7176
Convert quoted let binding bodies
NeilKleistGao Feb 19, 2024
0a9628d
Merge branch 'mlscript' of https://github.com/hkust-taco/mlscript int…
NeilKleistGao Feb 20, 2024
c8eb876
Update test cases
NeilKleistGao Feb 20, 2024
55737a8
Add test cases
NeilKleistGao Feb 20, 2024
14afc2c
Update test cases
NeilKleistGao Feb 20, 2024
db0b4d8
Update shared/src/test/diff/qq/Basic.mls
NeilKleistGao Feb 20, 2024
a043456
Update shared/src/test/diff/qq/Basic2.mls
NeilKleistGao Feb 20, 2024
13da756
Update shared/src/test/diff/qq/Extrusions.mls
NeilKleistGao Feb 20, 2024
b0dabbb
Update shared/src/test/diff/qq/LetInsertion_repro.mls
NeilKleistGao Feb 20, 2024
4f3751f
Update test cases
NeilKleistGao Feb 20, 2024
4a42960
Remove obsolete comments
NeilKleistGao Feb 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ class ClassLifter(logDebugMsg: Boolean = false) {
val (bod2, ctx) = liftTerm(bod)
val (sts2, ctx2) = liftEntities(sts)
(Where(bod2, sts2), ctx2)
case _: Eqn | _: Super | _: Rft | _: While => throw MonomorphError(s"Unimplemented liftTerm: ${target}") // TODO
case _: Eqn | _: Super | _: Rft | _: While | _: Quoted | _: Unquoted => throw MonomorphError(s"Unimplemented liftTerm: ${target}") // TODO
case patmat: AdtMatchWith => lastWords(s"Cannot liftTermNew ${patmat}")
}

Expand Down
2 changes: 1 addition & 1 deletion js/src/main/scala/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ object Main {

val exp = typer.expandType(sim)(ctx)

val expStr = exp.showIn(ShowCtx.mk(exp :: Nil, newDefs = true), 0).stripSuffix("\n")
val expStr = exp.showIn(0)(ShowCtx.mk(exp :: Nil, newDefs = true)).stripSuffix("\n")
.replaceAll(" ", "  ")
.replaceAll("\n", "<br/>")

Expand Down
203 changes: 186 additions & 17 deletions shared/src/main/scala/mlscript/JSBackend.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ abstract class JSBackend(allowUnresolvedSymbols: Bool) {
case TyApp(base, _) =>
translatePattern(base)
case Inst(bod) => translatePattern(bod)
case _: Lam | _: App | _: Sel | _: Let | _: Blk | _: Bind | _: Test | _: With | _: CaseOf
| _: Subs | _: Assign | _: If | _: New | NuNew(_) | _: Splc | _: Forall | _: Where
| _: Super | _: Eqn | _: AdtMatchWith | _: Rft | _: While =>
case _: Lam | _: App | _: Sel | _: Let | _: Blk | _: Bind | _: Test | _: With | _: CaseOf | _: Subs | _: Assign
| If(_, _) | New(_, _) | NuNew(_) | _: Splc | _: Forall | _: Where | _: Super | _: Eqn | _: AdtMatchWith
| _: Rft | _: While | _: Quoted | _: Unquoted =>
throw CodeGenError(s"term $t is not a valid pattern")
}

Expand Down Expand Up @@ -159,12 +159,12 @@ abstract class JSBackend(allowUnresolvedSymbols: Bool) {
protected def translateApp(term: App)(implicit scope: Scope): JSExpr = term match {
// Binary expressions
case App(App(Var(op), Tup((N -> Fld(_, lhs)) :: Nil)), Tup((N -> Fld(_, rhs)) :: Nil))
if JSBinary.operators contains op =>
if oldDefs && (JSBinary.operators contains op) =>
JSBinary(op, translateTerm(lhs), translateTerm(rhs))
// Binary expressions with new-definitions
case App(Var(op), Tup(N -> Fld(_, lhs) :: N -> Fld(_, rhs) :: Nil))
if JSBinary.operators.contains(op) && !translateVarImpl(op, isCallee = true).isRight =>
JSBinary(op, translateTerm(lhs), translateTerm(rhs))
case App(Var(op), Tup(N -> Fld(_, lhs) :: N -> Fld(_, rhs) :: Nil)) // JS doesn't support operators like `+.` so we need to map them before testing
if JSBinary.operators.contains(mapFloatingOperator(op)) && (!translateVarImpl(op, isCallee = true).isRight || op =/= mapFloatingOperator(op)) =>
JSBinary(mapFloatingOperator(op), translateTerm(lhs), translateTerm(rhs))
// If-expressions
case App(App(App(Var("if"), Tup((_, Fld(_, tst)) :: Nil)), Tup((_, Fld(_, con)) :: Nil)), Tup((_, Fld(_, alt)) :: Nil)) =>
JSTenary(translateTerm(tst), translateTerm(con), translateTerm(alt))
Expand All @@ -184,6 +184,168 @@ abstract class JSBackend(allowUnresolvedSymbols: Bool) {
case _ => throw CodeGenError(s"ill-formed application $term")
}

// * Generate an `App` node for AST constructors
private def createASTCall(tp: Str, args: Ls[Term]): App =
App(Var(tp), Tup(args.map(a => N -> Fld(FldFlags.empty, a))))

// * Bound free variables appearing in quasiquotes
class FreeVars(val vs: Set[Str])

// * Left: the branch is quoted and it has been desugared
// * Right: the branch is not quoted and quoted subterms have been desugared
private def desugarQuotedBranch(branch: CaseBranches)(
implicit scope: Scope, isQuoted: Bool, freeVars: FreeVars
): Either[Term, CaseBranches] = branch match {
case Case(pat, body, rest) =>
val dp = desugarQuote(pat)
val db = desugarQuote(body)
desugarQuotedBranch(rest) match {
case L(t) => L(createASTCall("Case", dp :: db :: t :: Nil))
case R(b) => dp match {
case dp: SimpleTerm => R(Case(dp, db, b))
case _ => die
}
}
case Wildcard(body) =>
if (isQuoted) L(createASTCall("Wildcard", desugarQuote(body) :: Nil)) else R(Wildcard(desugarQuote(body)))
case NoCases => if (isQuoted) L(createASTCall("NoCases", Nil)) else R(NoCases)
}

// * Operators `+`, `-`, and `*` will not be available for floating numbers until we have the correct overloading.
// * Currently, we use OCaml-style floating operators temporarily and translate them into normal JS operators.
private def mapFloatingOperator(op: Str) = op match {
case "+." => "+"
case "-." => "-"
case "*." => "*"
case _ => op
}

// * Desugar `Quoted` into AST constructor invocations.
// * example 1: `` `42 `` is desugared into `IntLit(42)`
// * example 2: `` x `=> id(x) `+ `1 `` is desugared into `let x1 = freshName("x") in Lam(Var(x1), App(Var("+"), id(Var(x1)), IntLit(1)))`
private def desugarQuote(term: Term)(implicit scope: Scope, isQuoted: Bool, freeVars: FreeVars): Term = term match {
case Var(name) =>
val isFreeVar = freeVars.vs(name)
if (isQuoted || isFreeVar) {
val runtimeName = scope.resolveValue(name).fold[Str](
throw CodeGenError(s"unbound free variable $name is not supported yet.")
)(_.runtimeName)
if (isFreeVar) createASTCall("Var", Var(runtimeName) :: Nil) // quoted variables
else createASTCall("Var", StrLit(runtimeName) :: Nil) // built-in symbols (e.g., true, error)
}
else term
case lit: IntLit => if (isQuoted) createASTCall("IntLit", lit :: Nil) else lit
case lit: DecLit => if (isQuoted) createASTCall("DecLit", lit :: Nil) else lit
case lit: StrLit => if (isQuoted) createASTCall("StrLit", lit :: Nil) else lit
case lit: UnitLit => if (isQuoted) createASTCall("UnitLit", lit :: Nil) else lit
case Lam(params, body) =>
if (isQuoted) {
val lamScope = scope.derive("Lam")
params match {
case Tup(params) =>
val newfreeVars = params.map {
case N -> Fld(_, Var(nme)) =>
lamScope.declareParameter(nme)
nme -> lamScope.declareValue(nme, S(false), false, N).runtimeName
case S(Var(nme)) -> _ =>
lamScope.declareParameter(nme)
nme -> lamScope.declareValue(nme, S(false), false, N).runtimeName
case p => throw CodeGenError(s"parameter $p is not supported in quasiquote")
}
newfreeVars.foldRight(desugarQuote(body)(lamScope, isQuoted, new FreeVars(freeVars.vs ++ newfreeVars.map(_._1))))((p, res) =>
Let(false, Var(p._2), createASTCall("freshName", StrLit(p._1) :: Nil), createASTCall("Lam", createASTCall("Var", Var(p._2) :: Nil) :: res :: Nil)))
case _ => throw CodeGenError(s"term $params is not a valid parameter list")
}
}
else Lam(params, desugarQuote(body))
case Unquoted(body) =>
if (isQuoted) {
val unquoteScope = scope.derive("unquote")
desugarQuote(body)(unquoteScope, false, freeVars)
}
else throw CodeGenError("unquoted term should be wrapped by quotes.")
case Quoted(body) =>
val quoteScope = scope.derive("quote")
val res = desugarQuote(body)(quoteScope, true, freeVars)
if (isQuoted) throw CodeGenError("nested quotation is not allowed.")
else res
case App(Var(op), Tup(N -> Fld(f1, lhs) :: N -> Fld(f2, rhs) :: Nil))
if JSBinary.operators.contains(mapFloatingOperator(op)) && (!translateVarImpl(op, isCallee = true).isRight || op =/= mapFloatingOperator(op)) =>
if (isQuoted)
createASTCall("App", createASTCall("Var", StrLit(mapFloatingOperator(op)) :: Nil) :: desugarQuote(lhs) :: desugarQuote(rhs) :: Nil)
else
App(Var(op), Tup(N -> Fld(f1, desugarQuote(lhs)) :: N -> Fld(f2, desugarQuote(rhs)) :: Nil))
case App(lhs, rhs) =>
if (isQuoted) createASTCall("App", desugarQuote(lhs) :: desugarQuote(rhs) :: Nil)
else App(desugarQuote(lhs), desugarQuote(rhs))
case Rcd(fields) =>
if (isQuoted) createASTCall("Rcd", fields.flatMap(f => createASTCall("Var", StrLit(f._1.name) :: Nil) :: desugarQuote(f._2.value) :: Nil))
else Rcd(fields.map(f => (f._1, Fld(f._2.flags, desugarQuote(f._2.value)))))
case Bra(rcd, trm) =>
if (isQuoted) createASTCall("Bra", desugarQuote(trm) :: Nil)
else Bra(rcd, desugarQuote(trm))
case Sel(receiver, f @ Var(name)) =>
if (isQuoted) createASTCall("Sel", desugarQuote(receiver) :: createASTCall("Var", StrLit(name) :: Nil) :: Nil)
else Sel(desugarQuote(receiver), f)
case Let(rec, Var(name), value, body) =>
val letScope = scope.derive("Let")
if (isQuoted) {
letScope.declareParameter(name)
val freshedName = letScope.declareValue(name, S(false), false, N).runtimeName
Let(false, Var(freshedName), createASTCall("freshName", StrLit(name) :: Nil),
createASTCall("Let", createASTCall("Var", Var(freshedName) :: Nil) :: desugarQuote(value)
:: desugarQuote(body)(letScope, isQuoted, new FreeVars(freeVars.vs ++ (name :: Nil))) :: Nil
))
}
else Let(rec, Var(name), desugarQuote(value), desugarQuote(body)(letScope, isQuoted, freeVars))
case Blk(stmts) =>
val blkScope = scope.derive("blk")
val res = stmts.map {
case t: Term =>
desugarQuote(t)(blkScope, isQuoted, freeVars)
case s => throw CodeGenError(s"statement $s is not supported in quasiquotes")
}
if (isQuoted) createASTCall("Blk", res)
else Blk(res)
case Tup(eles) =>
def toVar(b: Bool) = if (b) Var("true") else Var("false")
def toVars(flg: FldFlags) = toVar(flg.mut) :: toVar(flg.spec) :: toVar(flg.genGetter) :: Nil
if (isQuoted) createASTCall("Tup", eles flatMap {
case S(Var(name)) -> Fld(flags, t) =>
createASTCall("Var", Var(name) :: Nil) :: createASTCall("Fld", desugarQuote(t) :: toVars(flags)) :: Nil
case N -> Fld(flags, t) => createASTCall("Fld", desugarQuote(t) :: toVars(flags)) :: Nil
})
else Tup(eles.map {
case v -> Fld(flags, t) => v -> Fld(flags, desugarQuote(t))
})
case Subs(arr, idx) =>
if (isQuoted) createASTCall("Subs", desugarQuote(arr) :: desugarQuote(idx) :: Nil)
else Subs(desugarQuote(arr), desugarQuote(idx))
case Asc(trm, ty) =>
if (isQuoted) desugarQuote(trm)
else Asc(desugarQuote(trm), ty)
case With(lhs, rhs @ Rcd(fields)) =>
if (isQuoted) createASTCall("With", desugarQuote(lhs) :: desugarQuote(rhs) :: Nil)
else With(desugarQuote(lhs), Rcd(fields.map(f => (f._1, Fld(f._2.flags, desugarQuote(f._2.value))))))
case CaseOf(trm, cases) =>
desugarQuotedBranch(cases) match {
case L(t) => createASTCall("CaseOf", desugarQuote(trm) :: t :: Nil)
case R(b) => CaseOf(desugarQuote(trm), b)
}
case _ if term.desugaredTerm.isDefined => desugarQuote(term.desugaredTerm.getOrElse(die))
case Assign(lhs, rhs) if !isQuoted => Assign(desugarQuote(lhs), desugarQuote(rhs))
case NuNew(cls) if !isQuoted => NuNew(desugarQuote(cls))
case TyApp(lhs, targs) if !isQuoted => TyApp(desugarQuote(lhs), targs)
case Forall(p, body) if !isQuoted => Forall(p, desugarQuote(body))
case Inst(body) if !isQuoted => Inst(desugarQuote(body))
case _: Super if !isQuoted => term
case Eqn(lhs, rhs) if !isQuoted => Eqn(lhs, desugarQuote(rhs))
case While(cond, body) if !isQuoted => While(desugarQuote(cond), desugarQuote(body))
case _: Bind | _: Test | If(_, _) | _: Splc | _: Where | _: AdtMatchWith | _: Rft | _: New
| _: Assign | _: NuNew | _: TyApp | _: Forall | _: Inst | _: Super | _: Eqn | _: While =>
throw CodeGenError("this quote syntax is not supported yet.")
}

/**
* Translate MLscript terms into JavaScript expressions.
*/
Expand Down Expand Up @@ -339,7 +501,10 @@ abstract class JSBackend(allowUnresolvedSymbols: Bool) {
case TyApp(base, _) => translateTerm(base)
case Eqn(Var(name), _) =>
throw CodeGenError(s"assignment of $name is not supported outside a constructor")
case _: Bind | _: Test | If(_, _) | _: Splc | _: Where | _: AdtMatchWith | _: Rft =>
case Quoted(body) =>
val quotedScope = scope.derive("quote")
translateTerm(desugarQuote(body)(quotedScope, true, new FreeVars(Set.empty)))(quotedScope)
case _: Bind | _: Test | If(_, _) | _: Splc | _: Where | _: AdtMatchWith | _: Rft | _: Unquoted =>
throw CodeGenError(s"cannot generate code for term $term")
}

Expand Down Expand Up @@ -1265,11 +1430,11 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) {
case _: Def | _: TypeDef | _: Constructor =>
throw CodeGenError("Def and TypeDef are not supported in NewDef files.")
case term: Term =>
val name = translateTerm(term)(topLevelScope)
resultNames += name.toSourceCode.toString
val res = translateTerm(term)(topLevelScope)
resultNames += term.show(true)
topLevelScope.tempVars `with` JSInvoke(
resultsIdent("push"),
name :: Nil
res :: Nil
).stmt :: Nil
})
val epilogue = resultsIdent.member("map")(JSIdent(prettyPrinterName)).`return` :: Nil
Expand All @@ -1289,16 +1454,17 @@ abstract class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) {

/**
* Generate a piece of code for test purpose. It can be invoked repeatedly.
* `prettyPrintQQ` is a temporary hack due to lack of runtime support and should be removed later.
*/
def apply(pgrm: Pgrm, allowEscape: Bool, isNewDef: Boolean): JSTestBackend.Result =
def apply(pgrm: Pgrm, allowEscape: Bool, isNewDef: Bool, prettyPrintQQ: Bool): JSTestBackend.Result =
if (!isNewDef)
try generate(pgrm)(topLevelScope, allowEscape) catch {
case e: CodeGenError => JSTestBackend.IllFormedCode(e.getMessage())
case e: UnimplementedError => JSTestBackend.Unimplemented(e.getMessage())
// case NonFatal(e) => JSTestBackend.UnexpectedCrash(e.getClass().getName, e.getMessage())
}
else
try generateNewDef(pgrm)(topLevelScope, allowEscape) catch {
try generateNewDef(pgrm, prettyPrintQQ)(topLevelScope, allowEscape) catch {
case e: CodeGenError => JSTestBackend.IllFormedCode(e.getMessage())
case e: UnimplementedError => JSTestBackend.Unimplemented(e.getMessage())
// case NonFatal(e) => JSTestBackend.UnexpectedCrash(e.getClass().getName, e.getMessage())
Expand Down Expand Up @@ -1401,8 +1567,8 @@ abstract class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) {
JSTestBackend.TestCode(SourceCode.fromStmts(polyfill.emit() ::: prelude).toLines, queries)
}

private def generateNewDef(pgrm: Pgrm)(implicit scope: Scope, allowEscape: Bool): JSTestBackend.TestCode = {
private def generateNewDef(pgrm: Pgrm, prettyPrintQQ: Bool)(implicit scope: Scope, allowEscape: Bool): JSTestBackend.TestCode = {

val (typeDefs, otherStmts) = pgrm.tops.partitionMap {
case _: Constructor => throw CodeGenError("unexpected constructor.")
case ot: Terms => R(ot)
Expand Down Expand Up @@ -1510,13 +1676,16 @@ abstract class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) {

// If this is the first time, insert the declaration of `res`.
var prelude: Ls[JSStmt] = Ls(moduleDecl, insDecl) ::: includes
if (numRun === 0)
val isFirst = numRun === 0
if (isFirst)
prelude = JSLetDecl(lastResultSymbol.runtimeName -> N :: Nil) :: prelude

// Increase the run number.
numRun = numRun + 1

JSTestBackend.TestCode(SourceCode.fromStmts(polyfill.emit() ::: prelude).toLines, queries)
val qqPredefs =
SourceCode(if (isFirst && prettyPrintQQ) QQHelper.prettyPrinter else "")
JSTestBackend.TestCode((qqPredefs ++ SourceCode.fromStmts(polyfill.emit() ::: prelude)).toLines, queries)
}
}

Expand Down
4 changes: 2 additions & 2 deletions shared/src/main/scala/mlscript/Message.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ final case class Message(bits: Ls[Message.Bit]) {
showIn(ctx)
}
def typeBits: Ls[TypeLike] = bits.collect{ case Message.Code(t) => t }
def showIn(ctx: ShowCtx): Str = {
def showIn(implicit ctx: ShowCtx): Str = {
bits.map {
case Message.Code(ty) => ty.showIn(ctx, 0)
case Message.Code(ty) => ty.showIn(0)
case Message.Text(txt) => txt
}.mkString
}
Expand Down
Loading
Loading