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

Optional args #183

Draft
wants to merge 40 commits into
base: new-definition-typing
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
20d1fa9
adding optional flag to FldFlags
mbroughani81 Sep 11, 2023
0316ade
lexing ? char in args NewLexer
mbroughani81 Sep 12, 2023
3b036b3
show parser debug in test
mbroughani81 Sep 12, 2023
5bd9365
fix in parsing
mbroughani81 Sep 13, 2023
a2ad510
delete redundant prints
mbroughani81 Sep 13, 2023
4e795d2
add opt field in Field node, and parse correctly
mbroughani81 Sep 19, 2023
e6e4ae3
add opt field for FieldType
mbroughani81 Sep 19, 2023
fec99d8
adding opt field for FieldType
mbroughani81 Sep 20, 2023
0a653b2
fix typing of funparams
mbroughani81 Sep 20, 2023
723a9a5
WIP Add helpful test cases
LPTK Sep 22, 2023
5f5fdfd
fix type show
mbroughani81 Sep 23, 2023
d8a8ed4
add subtype check for subtyping with <:<
mbroughani81 Sep 23, 2023
b432dc4
add 2 other field size member checks
mbroughani81 Sep 25, 2023
ed45749
fix problem in field type show
mbroughani81 Sep 26, 2023
ea729b5
add some debugs
mbroughani81 Sep 26, 2023
1819d25
debug the place error happens
mbroughani81 Sep 27, 2023
b924f80
fix operations defined on FieldType
mbroughani81 Sep 28, 2023
6f7a599
Merge branch 'new-definition-typing' into optional-args
mbroughani81 Sep 28, 2023
4a6c2e7
add new require for intersection
mbroughani81 Sep 28, 2023
b81c5b4
Fix minor things in test
mbroughani81 Sep 28, 2023
e511ce1
Add isSubtype for TupleTypes
mbroughani81 Sep 28, 2023
33fc41f
Add error flag for some tests
mbroughani81 Sep 28, 2023
79a51a0
Delete some extra debugs
mbroughani81 Sep 28, 2023
a190864
Delete some extra debugs
mbroughani81 Sep 28, 2023
e882b7c
Delete some extra debugs
mbroughani81 Sep 28, 2023
01ddc66
Fix some possible? bugs
mbroughani81 Sep 28, 2023
8383e09
Delete extra log in DiffTests
mbroughani81 Sep 28, 2023
27bfae9
Fix some possible future? bugs
mbroughani81 Sep 28, 2023
a136b37
Fix some possible future? bugs
mbroughani81 Sep 28, 2023
12b3dc5
Fix some possible future? bugs
mbroughani81 Sep 28, 2023
e2df709
Rename fields compatible checker
mbroughani81 Sep 29, 2023
35442de
Merge branch 'new-definition-typing' into optional-args
mbroughani81 Sep 29, 2023
5c6f3c5
Fix syntax problem in helper
mbroughani81 Sep 29, 2023
a92fc4e
Fix syntax errors
mbroughani81 Sep 29, 2023
0b43e89
Merge branch 'new-definition-typing' into optional-args
LPTK Sep 29, 2023
31b3edd
Add some notes
mbroughani81 Sep 30, 2023
b299e54
Using composed type instead of field opt
mbroughani81 Oct 2, 2023
25d7764
Revert to opt + show bracketed
mbroughani81 Oct 2, 2023
59814ac
.
mbroughani81 Oct 3, 2023
028a5b5
Add ascribing for pattern match on optional fields
mbroughani81 Oct 3, 2023
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
3 changes: 2 additions & 1 deletion shared/src/main/scala/mlscript/ConstraintSolver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,7 @@ class ConstraintSolver extends NormalForms { self: Typer =>
}


case (TupleType(fs0), TupleType(fs1)) if fs0.size === fs1.size => // TODO generalize (coerce compatible tuples)
case (t0 @ TupleType(fs0), t1 @ TupleType(fs1)) if t0.isSubtype(t1) => {
fs0.lazyZip(fs1).foreach { case ((ln, l), (rn, r)) =>
ln.foreach { ln => rn.foreach { rn =>
if (ln =/= rn) err(
Expand All @@ -856,6 +856,7 @@ class ConstraintSolver extends NormalForms { self: Typer =>
recLb(r, l)
rec(l.ub, r.ub, false)
}
}
case (t: ArrayBase, a: ArrayType) =>
recLb(a.inner, t.inner)
rec(t.inner.ub, a.inner.ub, false)
Expand Down
6 changes: 3 additions & 3 deletions shared/src/main/scala/mlscript/JSBackend.scala
Original file line number Diff line number Diff line change
Expand Up @@ -950,10 +950,10 @@ class JSBackend(allowUnresolvedSymbols: Boolean) {

def prepare(nme: Str, fs: Ls[Opt[Var] -> Fld], pars: Ls[Term], unit: TypingUnit) = {
val params = fs.map {
case (S(nme), Fld(FldFlags(mut, spec), trm)) =>
case (S(nme), Fld(FldFlags(mut, spec, opt), trm)) =>
val ty = tt(trm)
nme -> Field(if (mut) S(ty) else N, ty)
case (N, Fld(FldFlags(mut, spec), nme: Var)) => nme -> Field(if (mut) S(Bot) else N, Top)
nme -> Field(if (mut) S(ty) else N, ty, false)
case (N, Fld(FldFlags(mut, spec, opt), nme: Var)) => nme -> Field(if (mut) S(Bot) else N, Top, false)
case _ => die
}
val body = pars.map(tt).foldRight(Record(params): Type)(Inter)
Expand Down
28 changes: 14 additions & 14 deletions shared/src/main/scala/mlscript/MLParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) {
}

def toParam(t: Term): Tup =
Tup((N, Fld(FldFlags(false, false), t)) :: Nil)
Tup((N, Fld(FldFlags(false, false, false), t)) :: Nil)

def toParams(t: Term): Tup = t match {
case t: Tup => t
case _ => toParam(t)
}
def toParamsTy(t: Type): Tuple = t match {
case t: Tuple => t
case _ => Tuple((N, Field(None, t)) :: Nil)
case _ => Tuple((N, Field(None, t, false)) :: Nil)
}

def letter[p: P] = P( lowercase | uppercase )
Expand Down Expand Up @@ -67,14 +67,14 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) {

def parens[p: P]: P[Term] = locate(P( "(" ~/ parenCell.rep(0, ",") ~ ",".!.? ~ ")" ).map {
case (Seq(Right(t -> false)), N) => Bra(false, t)
case (Seq(Right(t -> true)), N) => Tup(N -> Fld(FldFlags(true, false), t) :: Nil) // ? single tuple with mutable
case (Seq(Right(t -> true)), N) => Tup(N -> Fld(FldFlags(true, false, false), t) :: Nil) // ? single tuple with mutable
case (ts, _) =>
if (ts.forall(_.isRight)) Tup(ts.iterator.map {
case R(f) => N -> Fld(FldFlags(f._2, false), f._1)
case R(f) => N -> Fld(FldFlags(f._2, false, false), f._1)
case _ => die // left unreachable
}.toList)
else Splc(ts.map {
case R((v, m)) => R(Fld(FldFlags(m, false), v))
case R((v, m)) => R(Fld(FldFlags(m, false, false), v))
case L(spl) => L(spl)
}.toList)
})
Expand Down Expand Up @@ -104,8 +104,8 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) {
"{" ~/ (kw("mut").!.? ~ variable ~ "=" ~ term map L.apply).|(kw("mut").!.? ~
variable map R.apply).rep(sep = ";" | ",") ~ "}"
).map { fs => Rcd(fs.map{
case L((mut, v, t)) => v -> Fld(FldFlags(mut.isDefined, false), t)
case R(mut -> id) => id -> Fld(FldFlags(mut.isDefined, false), id) }.toList)})
case L((mut, v, t)) => v -> Fld(FldFlags(mut.isDefined, false, false), t)
case R(mut -> id) => id -> Fld(FldFlags(mut.isDefined, false, false), id) }.toList)})

def fun[p: P]: P[Term] = locate(P( kw("fun") ~/ term ~ "->" ~ term ).map(nb => Lam(toParams(nb._1), nb._2)))

Expand Down Expand Up @@ -272,8 +272,8 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) {
def rcd[p: P]: P[Record] =
locate(P( "{" ~/ ( kw("mut").!.? ~ variable ~ ":" ~ ty).rep(sep = ";") ~ "}" )
.map(_.toList.map {
case (None, v, t) => v -> Field(None, t)
case (Some(_), v, t) => v -> Field(Some(t), t)
case (None, v, t) => v -> Field(None, t, false)
case (Some(_), v, t) => v -> Field(Some(t), t, false)
} pipe Record))

def parTyCell[p: P]: P[Either[Type, (Type, Boolean)]] = (("..." | kw("mut")).!.? ~ ty). map {
Expand All @@ -287,14 +287,14 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) {
case (fs, _) =>
if (fs.forall(_._2.isRight))
Tuple(fs.map {
case (l, Right(t -> false)) => l -> Field(None, t)
case (l, Right(t -> true)) => l -> Field(Some(t), t)
case (l, Right(t -> false)) => l -> Field(None, t, false)
case (l, Right(t -> true)) => l -> Field(Some(t), t, false)
case _ => ??? // unreachable
})
else Splice(fs.map{ _._2 match {
case L(l) => L(l)
case R(r -> true) => R(Field(Some(r), r))
case R(r -> false) => R(Field(None, r))
case R(r -> true) => R(Field(Some(r), r, false))
case R(r -> false) => R(Field(None, r, false))
} })
})
def litTy[p: P]: P[Type] = P( lit.map(l => Literal(l).withLocOf(l)) )
Expand Down Expand Up @@ -325,7 +325,7 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) {
}
def tup = parTy.map {
case t: Tuple => t
case t => Tuple(N -> Field(N, t) :: Nil)
case t => Tuple(N -> Field(N, t, false) :: Nil)
}
P((ctorName ~ tup.?).map {
case (id, S(body: Tuple)) =>
Expand Down
3 changes: 3 additions & 0 deletions shared/src/main/scala/mlscript/NewLexer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) {
// go(j, if (keywords.contains(n)) KEYWORD(n) else IDENT(n, isAlphaOp(n)))
lex(j, ind, next(j, if (keywords.contains(n)) KEYWORD(n) else IDENT(n, isAlphaOp(n))))
case _ if isOpChar(c) =>
if (c === '?') {
lex(i + 1, ind, next(i, IDENT(c.toString(), true)))
} else
if (c === '-' && isDigit(bytes(i + 1))) {
val (str, j) = takeWhile(i + 1)(isDigit)
lex(j, ind, next(j, LITVAL(IntLit(-BigInt(str)))))
Expand Down
90 changes: 65 additions & 25 deletions shared/src/main/scala/mlscript/NewParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import sourcecode.{Name, Line}
import utils._, shorthands._
import mlscript.Message._
import BracketKind._
import mlscript.codegen.Helpers
import mlscript.ucs.helpers

object NewParser {

Expand Down Expand Up @@ -251,11 +253,11 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
final def toParams(t: Term): Tup = t match {
case t: Tup => t
case Bra(false, t: Tup) => t
case _ => Tup((N, Fld(FldFlags(false, false), t)) :: Nil)
case _ => Tup((N, Fld(FldFlags(false, false, false), t)) :: Nil)
}
final def toParamsTy(t: Type): Tuple = t match {
case t: Tuple => t
case _ => Tuple((N, Field(None, t)) :: Nil)
case _ => Tuple((N, Field(None, t, false)) :: Nil)
}
final def typ(prec: Int = 0)(implicit fe: FoundErr, l: Line): Type =
mkType(expr(prec))
Expand Down Expand Up @@ -462,7 +464,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
case (br @ BRACKETS(Angle | Square, toks), loc) :: _ =>
consume
val ts = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()).map {
case (N, Fld(FldFlags(false, false), v @ Var(nme))) =>
case (N, Fld(FldFlags(false, false, false), v @ Var(nme))) =>
TypeName(nme).withLocOf(v)
case _ => ???
}
Expand All @@ -473,11 +475,11 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
case (br @ BRACKETS(Round, Spaces(cons, (KEYWORD("override"), ovLoc) :: rest)), loc) :: rest2 =>
resetCur(BRACKETS(Round, rest)(br.innerLoc) -> loc :: rest2)
funParams match {
case ps @ Tup(N -> Fld(FldFlags(false, false), pat) :: Nil) :: Nil =>
case ps @ Tup(N -> Fld(FldFlags(false, false, false), pat) :: Nil) :: Nil =>
val fv = freshVar
(Tup(N -> Fld(FldFlags(false, false), fv) :: Nil) :: Nil, S(
(Tup(N -> Fld(FldFlags(false, false, false), fv) :: Nil) :: Nil, S(
(body: Term) => If(IfOpApp(fv, Var("is"), IfThen(pat, body)), S(
App(Sel(Super().withLoc(S(ovLoc)), v), Tup(N -> Fld(FldFlags(false, false), fv) :: Nil))
App(Sel(Super().withLoc(S(ovLoc)), v), Tup(N -> Fld(FldFlags(false, false, false), fv) :: Nil))
))
))
case r =>
Expand Down Expand Up @@ -539,7 +541,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
cur.dropWhile(_._1 === SPACE && { consume; true })

final def funParams(implicit et: ExpectThen, fe: FoundErr, l: Line): Ls[Tup] = wrap(()) { l =>
yeetSpaces match {
val res = yeetSpaces match {
case (KEYWORD("=" | ":"), _) :: _ => Nil
case Nil => Nil
case (KEYWORD("of"), _) :: _ =>
Expand All @@ -557,15 +559,25 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
consume
Nil
}
res match {
case x :: _ =>
printDbg(s"Here, creating the params! ${res} ${Helpers.inspect(x)}" )
case Nil =>
printDbg(s"Here, (not) creating the params! ${res}")
}
res
}

final def expr(prec: Int, allowSpace: Bool = true)(implicit fe: FoundErr, l: Line): Term = wrap(prec,allowSpace) { l =>
exprOrIf(prec, allowSpace)(et = false, fe = fe, l = implicitly) match {
val result = exprOrIf(prec, allowSpace)(et = false, fe = fe, l = implicitly) match {
case R(e) => e
case L(e) =>
err(msg"Expected an expression; found a 'then'/'else' clause instead" -> e.toLoc :: Nil)
errExpr
}
printDbg(s"result => ${result} ## ${Helpers.inspect(result)}")
printDbg(s"result toType => ${result.toType}")
result
}

private def warnDbg(msg: Any, loco: Opt[Loc] = curLoc): Unit =
Expand Down Expand Up @@ -617,7 +629,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
msg"Record field should have a name" -> fld.value.toLoc :: Nil))
Var("<error>") -> fld
}))
case (Round, (N, Fld(FldFlags(false, false), elt)) :: Nil) =>
case (Round, (N, Fld(FldFlags(false, false, false), elt)) :: Nil) =>
Bra(false, elt)
case _ =>
// TODO actually reject round tuples? (except for function arg lists)
Expand All @@ -636,7 +648,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
errExpr
}
R(Forall(as.flatMap {
case N -> Fld(FldFlags(false, false), v: Var) =>
case N -> Fld(FldFlags(false, false, false), v: Var) =>
TypeVar(R(v.name), N).withLocOf(v) :: Nil
case v -> f =>
err(msg"illegal `forall` quantifier body" -> f.value.toLoc :: Nil)
Expand Down Expand Up @@ -665,7 +677,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
val head = body match {
case Var(clsNme) =>
S(TypeName(clsNme).withLocOf(body) -> Tup(Nil))
case App(Var(clsNme), Tup(N -> Fld(FldFlags(false, false), UnitLit(true)) :: Nil)) =>
case App(Var(clsNme), Tup(N -> Fld(FldFlags(false, false, false), UnitLit(true)) :: Nil)) =>
S(TypeName(clsNme).withLocOf(body) -> Tup(Nil))
case App(Var(clsNme), arg) =>
S(TypeName(clsNme).withLocOf(body) -> arg)
Expand Down Expand Up @@ -765,7 +777,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
.concludeWith(_.expr(0, allowSpace = true))
val newAcc = Subs(acc, idx).withLoc(S(l0 ++ l1 ++ idx.toLoc))
exprCont(newAcc, prec, allowNewlines)
case (IDENT(opStr, true), l0) :: _ if /* isInfix(opStr) && */ opPrec(opStr)._1 > prec =>
case (IDENT(opStr, true), l0) :: _ if /* isInfix(opStr) && */ opPrec(opStr)._1 > prec && opStr =/= "?" =>
consume
val v = Var(opStr).withLoc(S(l0))
// printDbg(s">>> $opStr ${opPrec(opStr)}")
Expand Down Expand Up @@ -793,7 +805,9 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
}
case (KEYWORD(":"), l0) :: _ =>
consume
R(Asc(acc, typ(0)))
val asc = Asc(acc, typ(0))
printDbg(s"asc => ${asc}")
R(asc)
// case (KEYWORD(":"), _) :: _ if prec <= 1 =>
// consume
// R(Asc(acc, typ(1)))
Expand Down Expand Up @@ -883,7 +897,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
val as = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented())
// val res = TyApp(acc, as.map(_.mapSecond.to))
val res = TyApp(acc, as.map {
case (N, Fld(FldFlags(false, false), trm)) => trm.toType match {
case (N, Fld(FldFlags(false, false, false), trm)) => trm.toType match {
case L(d) => raise(d); Top // TODO better
case R(ty) => ty
}
Expand Down Expand Up @@ -1052,7 +1066,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
// argsOrIf(Nil).map{case (_, L(x))=> ???; case (n, R(x))=>n->x} // TODO
argsOrIf(Nil, Nil, allowNewlines, prec).flatMap{case (n, L(x))=>
err(msg"Unexpected 'then'/'else' clause" -> x.toLoc :: Nil)
n->Fld(FldFlags(false, false), errExpr)::Nil
n->Fld(FldFlags(false, false, false), errExpr)::Nil
case (n, R(x))=>n->x::Nil} // TODO
/*
final def argsOrIf2()(implicit fe: FoundErr, et: ExpectThen): IfBlock \/ Ls[Opt[Var] -> Fld] = {
Expand All @@ -1068,12 +1082,11 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
final def argsOrIf(acc: Ls[Opt[Var] -> (IfBody \/ Fld)], seqAcc: Ls[Statement], allowNewlines: Bool, prec: Int = NoElsePrec)
(implicit fe: FoundErr, et: ExpectThen): Ls[Opt[Var] -> (IfBody \/ Fld)] =
wrap(acc, seqAcc) { l =>

cur match {
case Nil =>
seqAcc match {
case res :: seqAcc =>
(N -> R(Fld(FldFlags(false, false), Blk((res :: seqAcc).reverse))) :: acc).reverse
(N -> R(Fld(FldFlags(false, false, false), Blk((res :: seqAcc).reverse))) :: acc).reverse
case Nil =>
acc.reverse
}
Expand All @@ -1099,20 +1112,47 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
S(l0)
case _ => N
}
val argName = yeetSpaces match {
case (IDENT(idStr, false), l0) :: (KEYWORD(":"), _) :: _ => // TODO: | ...
val (argName, argOpt) = yeetSpaces match {
case (IDENT(idStr, false), l0) :: (IDENT("?", true), l1) :: (KEYWORD(":"), _) :: _ => // TODO: | ...
consume
consume
S(Var(idStr).withLoc(S(l0)))
case _ => N
consume
(S(Var(idStr).withLoc(S(l0))), S(l1))
case (IDENT(idStr, false), l0) :: (KEYWORD(":"), _) :: _ =>
consume
consume
(S(Var(idStr).withLoc(S(l0))), N)
case _ => (N, N)
}
// val e = expr(NoElsePrec) -> argMut.isDefined
val e = exprOrIf(prec).map(Fld(FldFlags(argMut.isDefined, argSpec.isDefined), _))
val body = exprOrIf(prec)
cur match {
case x :: _ =>
printDbg(s"nexttoken => ${x}")
case _ => ()
}
val isOptinoal = cur match {
case (IDENT("?", true), l0) :: _ =>
consume
true
case _ =>
false
}
val e = body.map(Fld(FldFlags(argMut.isDefined, argSpec.isDefined, argOpt.isDefined || isOptinoal), _))
printDbg(s"flags => ${argMut} ${argSpec} ${argOpt}")
printDbg(s"e => ${e}")

body match {
case Right(value) =>
printDbg(s"body => ${value} ${Helpers.inspect(value)}")
case _ => ()
}


def mkSeq = if (seqAcc.isEmpty) argName -> e else e match {
case L(_) => ???
case R(Fld(FldFlags(m, s), res)) =>
argName -> R(Fld(FldFlags(m, s), Blk((res :: seqAcc).reverse)))
case R(Fld(FldFlags(m, s, o), res)) =>
argName -> R(Fld(FldFlags(m, s, o), Blk((res :: seqAcc).reverse)))
}

cur match {
Expand All @@ -1132,7 +1172,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo
}
e match {
case L(_) => ???
case R(Fld(FldFlags(false, false), res)) =>
case R(Fld(FldFlags(false, false, false), res)) =>
argsOrIf(acc, res :: seqAcc, allowNewlines)
case R(_) => ???
}
Expand Down
Loading