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
Changes from 7 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
4 changes: 2 additions & 2 deletions shared/src/main/scala/mlscript/JSBackend.scala
Original file line number Diff line number Diff line change
@@ -66,7 +66,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) {
translatePattern(base)
case Inst(bod) => translatePattern(bod)
case _: Lam | _: App | _: Sel | _: Let | _: Blk | _: Bind | _: Test | _: With | _: CaseOf | _: Subs | _: Assign
| If(_, _) | New(_, _) | _: Splc | _: Forall | _: Where | _: Super | _: Eqn | _: AdtMatchWith =>
| If(_, _) | New(_, _) | _: Splc | _: Forall | _: Where | _: Super | _: Eqn | _: AdtMatchWith | _: Quoted | _: Unquoted =>
throw CodeGenError(s"term ${inspect(t)} is not a valid pattern")
}

@@ -305,7 +305,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) {
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 =>
case _: Bind | _: Test | If(_, _) | _: Splc | _: Where | _: AdtMatchWith | _: Quoted | _: Unquoted =>
throw CodeGenError(s"cannot generate code for term ${inspect(term)}")
}

56 changes: 42 additions & 14 deletions shared/src/main/scala/mlscript/NewLexer.scala
Original file line number Diff line number Diff line change
@@ -91,11 +91,17 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) {
def loc(start: Int, end: Int): Loc = Loc(start, end, origin)

@tailrec final
def lex(i: Int, ind: Ls[Int], acc: Ls[TokLoc]): Ls[TokLoc] = if (i >= length) acc.reverse else {
def lex(i: Int, ind: Ls[Int], acc: Ls[TokLoc])(implicit qqList: Ls[BracketKind]): Ls[TokLoc] = if (i >= length) acc.reverse else {
val c = bytes(i)
def pe(msg: Message): Unit =
// raise(ParseError(false, msg -> S(loc(i, i + 1)) :: Nil))
raise(ErrorReport(msg -> S(loc(i, i + 1)) :: Nil, newDefs = true, source = Lexing))
def fit(i: Int, syntax: Str): Bool =
i + syntax.length <= length && bytes.slice(i, i + syntax.length).mkString === syntax
def isQuasiquoteOpening(i: Int): Bool = fit(i, BracketKind.Quasiquote.beg)
def isQuasiquoteTripleOpening(i: Int): Bool = fit(i, BracketKind.QuasiquoteTriple.beg)
def isUnquoteOpening(i: Int): Bool = fit(i, BracketKind.Unquote.beg)
def isQuasiquoteTripleClosing(i: Int): Bool = fit(i, BracketKind.QuasiquoteTriple.end)
// @inline
// def go(j: Int, tok: Token) = lex(j, ind, (tok, loc(i, j)) :: acc)
def next(j: Int, tok: Token) = (tok, loc(i, j)) :: acc
@@ -108,15 +114,37 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) {
val j = i + 1
// go(j, COMMA)
lex(j, ind, next(j, COMMA))
case 'c' if isQuasiquoteOpening(i) || isQuasiquoteTripleOpening(i) =>
val isTripleQuoteQQ = isQuasiquoteTripleOpening(i)
val bracket_kind = if (isTripleQuoteQQ)
BracketKind.QuasiquoteTriple
else
BracketKind.Quasiquote
val len = bracket_kind.beg.length
lex(i + len, ind, next(i + len, OPEN_BRACKET(bracket_kind)))(bracket_kind :: qqList)
case '$' if isUnquoteOpening(i) =>
lex(i + 2, ind, next(i + 2, OPEN_BRACKET(BracketKind.Unquote)))
case '"' =>
val j = i + 1
val (chars, k) = str(j, false)
val k2 = if (bytes.lift(k) === Some('"')) k + 1 else {
pe(msg"unclosed quotation mark")
k
val (isTripleQQ, cons) = qqList match {
case h :: t => (h === BracketKind.QuasiquoteTriple, t)
case Nil => (false, Nil)
}
if (isTripleQQ && isQuasiquoteTripleClosing(i)) {
val length = BracketKind.QuasiquoteTriple.end.length
lex(i + length, ind, next(i + length, CLOSE_BRACKET(BracketKind.QuasiquoteTriple)))(cons)
} else if (!isTripleQQ && qqList.nonEmpty) {
lex(i + 1, ind, next(i + 1, CLOSE_BRACKET(BracketKind.Quasiquote)))(cons)
} else {
val j = i + 1
val (chars, k) = str(j, false)
val k2 = if (bytes.lift(k) === Some('"')) k + 1 else {
pe(msg"unclosed quotation mark")
k
}
// go(k2, LITVAL(StrLit(chars)))
lex(k2, ind, next(k2, LITVAL(StrLit(chars))))
}
// go(k2, LITVAL(StrLit(chars)))
lex(k2, ind, next(k2, LITVAL(StrLit(chars))))

case '/' if bytes.lift(i + 1).contains('/') =>
val j = i + 2
val (txt, k) =
@@ -205,7 +233,7 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) {
}


lazy val tokens: Ls[Token -> Loc] = lex(0, Nil, Nil)
lazy val tokens: Ls[Token -> Loc] = lex(0, Nil, Nil)(Nil)

/** Converts the lexed tokens into structured tokens. */
lazy val bracketedTokens: Ls[Stroken -> Loc] = {
@@ -223,7 +251,7 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) {
// * Ignore empty indented blocks:
go(rest, false, stack, oldAcc)
case ((k0, l0), oldAcc) :: stack =>
if (k0 =/= k1)
if (k0 =/= k1 && !(k0 === Unquote && k1 === Curly))
raise(ErrorReport(msg"Mistmatched closing ${k1.name}" -> S(l1) ::
msg"does not correspond to opening ${k0.name}" -> S(l0) :: Nil, newDefs = true,
source = Parsing))
@@ -339,12 +367,12 @@ object NewLexer {
case (KEYWORD(name: String), _) => "#" + name
case (IDENT(name: String, symbolic: Bool), _) => name
case (SELECT(name: String), _) => "." + name
case (OPEN_BRACKET(k), _) => k.beg.toString
case (CLOSE_BRACKET(k), _) => k.end.toString
case (OPEN_BRACKET(k), _) => k.beg
case (CLOSE_BRACKET(k), _) => k.end
case (BRACKETS(k @ BracketKind.Indent, contents), _) =>
k.beg.toString + printTokens(contents) + k.end.toString
k.beg + printTokens(contents) + k.end
case (BRACKETS(k, contents), _) =>
k.beg.toString + printTokens(contents) + k.end.toString
k.beg + printTokens(contents) + k.end
case (COMMENT(text: String), _) => "/*" + text + "*/"
}
def printTokens(ts: Ls[TokLoc]): Str =
8 changes: 8 additions & 0 deletions shared/src/main/scala/mlscript/NewParser.scala
Original file line number Diff line number Diff line change
@@ -604,6 +604,14 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
case (IDENT(nme, false), l0) :: _ =>
consume
exprCont(Var(nme).withLoc(S(l0)), prec, allowNewlines = false)
case (br @ BRACKETS(Quasiquote | QuasiquoteTriple, toks), loc) :: _ =>
consume
val body = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.expr(0))
exprCont(Quoted(body).withLoc(S(loc)), prec, allowNewlines = false)
case (br @ BRACKETS(Unquote, toks), loc) :: _ =>
consume
val body = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.expr(0))
exprCont(Unquoted(body).withLoc(S(loc)), prec, allowNewlines = false)
case (KEYWORD("super"), l0) :: _ =>
consume
exprCont(Super().withLoc(S(l0)), prec, allowNewlines = false)
19 changes: 14 additions & 5 deletions shared/src/main/scala/mlscript/Token.scala
Original file line number Diff line number Diff line change
@@ -48,18 +48,24 @@ final case class COMMENT(text: String) extends Token with Stroken
sealed abstract class BracketKind {
import BracketKind._
lazy val (beg, end) = this match {
case Round => '(' -> ')'
case Curly => '{' -> '}'
case Square => '[' -> ']'
case Angle => '‹' -> '›'
case Indent => '→' -> '←'
case Round => "(" -> ")"
case Curly => "{" -> "}"
case Square => "[" -> "]"
case Angle => "‹" -> "›"
case Indent => "→" -> "←"
case Quasiquote => "code\"" -> "\""
case QuasiquoteTriple => "code\"\"\"" -> "\"\"\""
case Unquote => "${" -> "}"
}
def name: Str = this match {
case Round => "parenthesis"
case Curly => "curly brace"
case Square => "square bracket"
case Angle => "angle bracket"
case Indent => "indentation"
case Quasiquote => "quasiquote"
case QuasiquoteTriple => "quasiquote triple"
case Unquote => "unquote"
}
}

@@ -69,6 +75,9 @@ object BracketKind {
case object Square extends BracketKind
case object Angle extends BracketKind
case object Indent extends BracketKind
case object Quasiquote extends BracketKind
case object QuasiquoteTriple extends BracketKind
case object Unquote extends BracketKind

def unapply(c: Char): Opt[Either[BracketKind, BracketKind]] = c |>? {
case '(' => Left(Round)
82 changes: 80 additions & 2 deletions shared/src/main/scala/mlscript/Typer.scala
Original file line number Diff line number Diff line change
@@ -62,15 +62,48 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne
env: MutMap[Str, TypeInfo],
mthEnv: MutMap[(Str, Str) \/ (Opt[Str], Str), MethodType],
lvl: Int,
qenv: MutMap[Str, SkolemTag], // * SkolemTag for variables in quasiquotes
fvars: MutSet[ST], // * Free variables
quotedLvl: Int, // * Level of quasiquotes
inPattern: Bool,
tyDefs: Map[Str, TypeDef],
tyDefs2: MutMap[Str, DelayedTypeInfo],
inRecursiveDef: Opt[Var], // TODO rm
extrCtx: ExtrCtx,
) {
def +=(b: Str -> TypeInfo): Unit = env += b
def +=(b: Str -> TypeInfo): Unit = {
env += b
if (quotedLvl > 0) {
val tag = SkolemTag(freshVar(NoProv, N)(lvl))(NoProv)
println(s"Create skolem tag $tag for ${b._2} in quasiquote.")
qenv += b._1 -> tag
}
}
def ++=(bs: IterableOnce[Str -> TypeInfo]): Unit = bs.iterator.foreach(+=)
def get(name: Str): Opt[TypeInfo] = env.get(name) orElse parent.dlof(_.get(name))(N)
def qget(name: Str, qlvl: Int = quotedLvl): Opt[SkolemTag] =
if (qlvl === quotedLvl) qenv.get(name) orElse parent.dlof(_.qget(name, qlvl))(N)
else parent.dlof(_.qget(name, qlvl))(N)
def wrapCode: Ls[(Str, TypeInfo)] = qenv.flatMap {
case (name, tag) =>
get(name) match {
case S(VarSymbol(ty, _)) =>
name -> VarSymbol(TypeRef(TypeName("Code"), ty :: tag :: Nil)(noProv), Var(name)) :: Nil
case S(_: AbstractConstructor) | S(_: LazyTypeInfo) => die // * Abstract ctors and type defs are not allowed
case N => Nil // * In the same quasiquote but not the same scope
}
}.toList
def unwrap[T](names: Ls[Str], f: () => T): T = { // * Revert ctx modification temporarily
val cache: MutMap[Str, TypeInfo] = MutMap.empty
names.foreach(name => {
cache += name -> env.getOrElse(name, die)
env -= name
})
val res = f()
cache.foreach(env += _)
res
}
def traceFV(fv: ST): Unit = fvars += fv
def contains(name: Str): Bool = env.contains(name) || parent.exists(_.contains(name))
def addMth(parent: Opt[Str], nme: Str, ty: MethodType): Unit = mthEnv += R(parent, nme) -> ty
def addMthDefn(parent: Str, nme: Str, ty: MethodType): Unit = mthEnv += L(parent, nme) -> ty
@@ -147,6 +180,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne
env = MutMap.from(builtinBindings.iterator.map(nt => nt._1 -> VarSymbol(nt._2, Var(nt._1)))),
mthEnv = MutMap.empty,
lvl = MinLevel,
qenv = MutMap.empty,
fvars = MutSet.empty,
quotedLvl = 0,
inPattern = false,
tyDefs = Map.from(builtinTypes.map(t => t.nme.name -> t)),
tyDefs2 = MutMap.empty,
@@ -239,6 +275,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne
NuTypeDef(Cls, TN("Str"), Nil, N, N, N, Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)),
NuTypeDef(Als, TN("undefined"), Nil, N, N, S(Literal(UnitLit(true))), Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)),
NuTypeDef(Als, TN("null"), Nil, N, N, S(Literal(UnitLit(false))), Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)),
NuTypeDef(Cls, TN("Code"), (S(VarianceInfo.co) -> TN("T")) :: (S(VarianceInfo.co) -> TN("C")) :: Nil, N, N, N, Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc))
)
val builtinTypes: Ls[TypeDef] =
TypeDef(Cls, TN("?"), Nil, TopType, Nil, Nil, Set.empty, N, Nil) :: // * Dummy for pretty-printing unknown type locations
@@ -370,6 +407,11 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne
val v = freshVar(noProv, N)(1)
PolymorphicType(0, ArrayType(FieldType(S(v), v)(noProv))(noProv))
},
"run" -> {
val tv = freshVar(noProv, N)(1)
PolymorphicType(0, fun(singleTup(TypeRef(TypeName("Code"), tv :: BotType :: Nil)(noProv)), tv)(noProv))
},
"Const" -> fun(singleTup(IntType), TypeRef(TypeName("Code"), IntType :: BotType :: Nil)(noProv))(noProv),
) ++ (if (!newDefs) primTypes ++ primTypes.map(p => p._1.capitalize -> p._2) // TODO settle on naming convention...
else Nil)
}
@@ -834,7 +876,15 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne
res
}
case v @ ValidVar(name) =>
val ty = ctx.get(name).fold(err("identifier not found: " + name, term.toLoc): ST) {
val tyOpt = if (ctx.quotedLvl > 0 && !builtinBindings.contains(name)) {
ctx.qget(name) match {
case S(ctxTy) =>
if (!ctx.qenv.contains(name)) ctx.traceFV(ctxTy)
ctx.get(name)
case _ => N
}
} else ctx.get(name)
val ty = tyOpt.fold(err("identifier not found: " + name, term.toLoc): ST) {
case AbstractConstructor(absMths, traitWithMths) =>
val td = ctx.tyDefs(name)
err((msg"Instantiation of an abstract type is forbidden" -> term.toLoc)
@@ -1382,6 +1432,34 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne
res
case Eqn(lhs, rhs) =>
err(msg"Unexpected equation in this position", term.toLoc)
case Quoted(body) =>
val newCtx =
ctx.nest.copy(quotedLvl = ctx.quotedLvl + 1, qenv = MutMap.empty, fvars = MutSet.empty)
val bodyType = ctx.parent match {
case S(p) if p.quotedLvl > ctx.quotedLvl =>
ctx.unwrap(p.wrapCode.map(_._1), () => typePolymorphicTerm(body)(newCtx, raise, vars))
case _ => typePolymorphicTerm(body)(newCtx, raise, vars)
}
val ctxTy = newCtx.fvars.foldLeft[ST](BotType)((res, ty) => res | ty)
TypeRef(TypeName("Code"), bodyType :: ctxTy :: Nil)(noProv) // TODO: trace the unbound free vars
case Unquoted(body) =>
if (ctx.quotedLvl > 0) {
val newCtx = ctx.nest.copy(quotedLvl = 0)
val wrappedCodes = ctx.wrapCode
println("Map qenv to env in unquote...")
wrappedCodes.foreach(c => {
println(s"Create ${c._2} in newCtx")
newCtx += c
})
val bodyType = typePolymorphicTerm(body)(newCtx, raise, vars)
val res = freshVar(noTyProv, N)
val ctxTy = freshVar(noTyProv, N)
val ty =
con(bodyType, TypeRef(TypeName("Code"), res :: ctx.qenv.foldLeft[ST](ctxTy)((res, ty) => ty._2 | res) :: Nil)(noProv), res)
ctx.traceFV(ctxTy)
ty
}
else err("Unquotes should be enclosed with a quasiquote.", body.toLoc)(raise)
}
}(r => s"$lvl. : ${r}")

4 changes: 4 additions & 0 deletions shared/src/main/scala/mlscript/codegen/Helpers.scala
Original file line number Diff line number Diff line change
@@ -60,6 +60,10 @@ object Helpers {
case Super() => "Super()"
case AdtMatchWith(cond, arms) =>
s"match ${inspect(cond)} with ${arms.map(patmat => s"${inspect(patmat.pat)} -> ${inspect(patmat.rhs)}").mkString(" | ")}"
case Quoted(body) =>
s"Quoted(${inspect(body)})"
case Unquoted(body) =>
s"Unquoted(${inspect(body)})"
}

def inspect(body: IfBody): Str = body match {
6 changes: 6 additions & 0 deletions shared/src/main/scala/mlscript/helpers.scala
Original file line number Diff line number Diff line change
@@ -548,6 +548,8 @@ trait TermImpl extends StatementImpl { self: Term =>
case Super() => "super"
case Eqn(lhs, rhs) => "assign for ctor"
case AdtMatchWith(cond, arms) => "ADT pattern matching"
case Quoted(_) => "quasiquote"
case Unquoted(_) => "unquote"
}
}

@@ -603,6 +605,8 @@ trait TermImpl extends StatementImpl { self: Term =>
case Eqn(lhs, rhs) => s"${lhs} = ${rhs}"
case AdtMatchWith(cond, arms) =>
s"match ${cond} with ${arms.map (patmat => s"${patmat.pat} -> ${patmat.rhs}").mkString (" | ") }"
case Quoted(b) => s"code\"$b\""
case Unquoted(b) => s"$${$b}"
}}

def toTypeRaise(implicit raise: Raise): Type = toType match {
@@ -975,6 +979,8 @@ trait StatementImpl extends Located { self: Statement =>
case NuTypeDef(k, nme, tps, ps, ctor, sig, pars, sup, ths, bod) =>
nme :: tps.map(_._2) ::: ps.toList ::: pars ::: ths.toList ::: bod :: Nil
case AdtMatchWith(cond, _) => cond :: Nil // FIXME discards branches...
case Quoted(body) => body :: Nil
case Unquoted(body) => body :: Nil
}


2 changes: 2 additions & 0 deletions shared/src/main/scala/mlscript/syntax.scala
Original file line number Diff line number Diff line change
@@ -89,6 +89,8 @@ final case class Forall(params: Ls[TypeVar], body: Term) extends Ter
final case class Inst(body: Term) extends Term
final case class Super() extends Term
final case class Eqn(lhs: Var, rhs: Term) extends Term // equations such as x = y, notably used in constructors; TODO: make lhs a Term
final case class Quoted(body: Term) extends Term
final case class Unquoted(body: Term) extends Term

final case class AdtMatchWith(cond: Term, arms: Ls[AdtMatchPat]) extends Term
final case class AdtMatchPat(pat: Term, rhs: Term) extends AdtMatchPatImpl
14 changes: 7 additions & 7 deletions shared/src/test/diff/basics/Simplesub1.fun
Original file line number Diff line number Diff line change
@@ -439,28 +439,28 @@ let rec x = (let y = (x x); (z => z))
//│ where
//│ forall 'c 'd. 'd -> 'c
//│ where
//│ 'e <: (forall 'f 'g. 'f -> 'g
//│ 'e <: (forall 'f 'g. 'g -> 'f
//│ where
//│ 'd <: 'd -> 'f -> 'g) -> 'c <: (forall 'c 'd. 'd -> 'c
//│ 'd <: 'd -> 'g -> 'f) -> 'c <: (forall 'c 'd. 'd -> 'c
//│ where
//│ 'e <: (forall 'f 'g. 'f -> 'g
//│ 'e <: (forall 'f 'g. 'g -> 'f
//│ where
//│ 'd <: 'd -> 'f -> 'g) -> 'c) -> 'a -> 'b) -> 'h & 'e) -> 'h
//│ 'd <: 'd -> 'g -> 'f) -> 'c) -> 'a -> 'b) -> 'h & 'e) -> 'h

// * Function that takes arbitrarily many arguments:
// :e // Works thanks to inconsistent constrained types...
(f => (x => f (v => (x x) v)) (x => f (v => (x x) v))) (f => x => f)
//│ res: anything -> (forall 'a 'b. 'a -> 'b
//│ where
//│ forall 'c 'd. 'c -> 'd
//│ forall 'c 'd. 'd -> 'c
//│ where
//│ forall 'e. 'e -> anything -> 'e <: (forall 'f 'g. 'f -> 'g
//│ where
//│ 'c <: 'c -> 'f -> 'g) -> 'd <: (forall 'c 'd. 'c -> 'd
//│ 'd <: 'd -> 'f -> 'g) -> 'c <: (forall 'c 'd. 'd -> 'c
//│ where
//│ forall 'e. 'e -> anything -> 'e <: (forall 'f 'g. 'f -> 'g
//│ where
//│ 'c <: 'c -> 'f -> 'g) -> 'd) -> 'a -> 'b)
//│ 'd <: 'd -> 'f -> 'g) -> 'c) -> 'a -> 'b)



2 changes: 1 addition & 1 deletion shared/src/test/diff/codegen/IndirectRecursion.mls
Original file line number Diff line number Diff line change
@@ -155,7 +155,7 @@ def z =
//│ ((anything -> nothing) -> anything) -> error
//│ <: z:
//│ (('a -> 'b) -> ('a -> 'b & 'c)) -> 'c
//│ ╔══[ERROR] Subtyping constraint of the form `?a -> ?b <: (forall ?c ?d. ?d -> ?c) -> ?e` exceeded recursion depth limit (250)
//│ ╔══[ERROR] Subtyping constraint of the form `?a -> ?b <: (forall ?c ?d. ?c -> ?d) -> ?e` exceeded recursion depth limit (250)
//│ ║ l.154: (fun f -> (fun x -> f (fun v -> (x x) v)) (fun x -> f (fun v -> (x x) v)))
//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//│ ╙── Note: use flag `:ex` to see internal error info.
Loading