diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index 8f335b6b99..b33f8b36a8 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -472,7 +472,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): val args = argsOpt.map(_.map(_.scrutinee)).getOrElse(Nil) // Normalization should reject cases where the user provides // more sub-patterns than there are actual class parameters. - assert(argsOpt.isEmpty || args.length <= clsParams.length) + assert(argsOpt.isEmpty || args.length <= clsParams.length, (argsOpt, clsParams)) def mkArgs(args: Ls[TermSymbol -> BlockLocalSymbol])(using Subst): Case -> Block = args match case Nil => Case.Cls(ctorSym, st) -> go(tail, topLevel = false) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 86cd20715c..f65ea5cdb9 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -107,9 +107,9 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def newNamedBlockMem(name: Str) = BlockMemberSymbol(name, Nil) private def newNamed(name: Str) = VarSymbol(Tree.Ident(name)) private def newClassSym(name: Str) = - ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N, N), Tree.Ident(name)) + ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N), Tree.Ident(name)) private def newTupleSym(len: Int) = - ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N, N), Tree.Ident(s"Tuple$len")) + ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N), Tree.Ident(s"Tuple$len")) private def newVarSym(name: Str) = VarSymbol(Tree.Ident(name)) private def newFunSym(name: Str) = BlockMemberSymbol(name, Nil) private def newBuiltinSym(name: Str) = BuiltinSymbol(name, false, false, false, false) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/BlockImpl.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/BlockImpl.scala index 9de0ad68a4..fa5b15018e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/BlockImpl.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/BlockImpl.scala @@ -13,14 +13,25 @@ trait BlockImpl(using Elaborator.State): val desugStmts = def desug(stmts: Ls[Tree]): Ls[Tree] = stmts match + case PossiblyAnnotated(anns, syntax.Desugared(td: TypeDef)) :: stmts => + val ctors = td.withPart.toList.flatMap: + case Block(sts) => sts.flatMap: + case Constructor(Block(ctors)) => ctors + case _ => Nil + case _ => Nil + PossiblyAnnotated(anns, td) :: ( + ctors.map(head => PossiblyAnnotated(anns, TypeDef(syntax.Cls, + td.name match + case L(_) => head + case R(name) => + InfixApp(head, syntax.Keyword.`extends`, name) + , N + ))) + ) ::: desug(stmts) case stmt :: stmts => stmt.desugared match case PossiblyAnnotated(anns, h @ Hndl(body = N)) => PossiblyAnnotated(anns, h.copy(body = S(Block(stmts)))) :: Nil - case PossiblyAnnotated(anns, TypeDef(syntax.Cls, Ident(name), rhs, S(Block(Constructor(Block(ctors)) :: rest)))) => - PossiblyAnnotated(anns, TypeDef(syntax.Cls, Ident(name), rhs, if rest.isEmpty then N else S(Block(rest)))) :: - (ctors.map(head => PossiblyAnnotated(anns, TypeDef(syntax.Cls, InfixApp(head, syntax.Keyword.`extends`, Ident(name)), N, N)))) - ::: desug(stmts) case stmt => stmt :: desug(stmts) case Nil => Nil desug(stmts) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index ad3f474b99..942cf9903e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -145,8 +145,8 @@ object Elaborator: case huh => wat(huh) protected def assumeObject(nme: Str): BlockMemberSymbol = module.tree.definedSymbols.get(nme).getOrElse: - throw new NoSuchElementException: - s"builtin module symbol source.$nme. we have" + throw new NoSuchElementException( + s"builtin module symbol source.$nme") object source extends VirtualModule(assumeBuiltinMod("source")): val line = assumeObject("line") val name = assumeObject("name") @@ -202,17 +202,18 @@ object Elaborator: val importSymbol = new VarSymbol(syntax.Tree.Ident("import")) val runtimeSymbol = TempSymbol(N, "runtime") val termSymbol = TempSymbol(N, "Term") - val effectSigSymbol = ClassSymbol(TypeDef(syntax.Cls, Dummy, N, N), Ident("EffectSig")) + val effectSigSymbol = ClassSymbol(DummyTypeDef(syntax.Cls), Ident("EffectSig")) val nonLocalRetHandlerTrm = val id = new Ident("NonLocalReturn") - val sym = ClassSymbol(TypeDef(syntax.Cls, Dummy, N, N), id) + val sym = ClassSymbol(DummyTypeDef(syntax.Cls), id) Term.Sel(runtimeSymbol.ref(), id)(S(sym)) val nonLocalRet = val id = new Ident("ret") BlockMemberSymbol(id.name, Nil, true) val matchResultClsSymbol = val id = new Ident("MatchResult") - val td = TypeDef(syntax.Cls, App(id, Tup(Ident("captures") :: Nil)), N, N) + // val td = DummyTypeDef(syntax.Cls) + val td = TypeDef(syntax.Cls, App(id, Tup(Ident("captures") :: Nil)), N) val cs = ClassSymbol(td, id) val flag = FldFlags.empty.copy(value = true) val ps = PlainParamList(Param(flag, VarSymbol(Ident("captures")), N, Modulefulness(N)(false)) :: Nil) @@ -221,7 +222,7 @@ object Elaborator: cs val matchFailureClsSymbol = val id = new Ident("MatchFailure") - val td = TypeDef(syntax.Cls, App(id, Tup(Ident("errors") :: Nil)), N, N) + val td = DummyTypeDef(syntax.Cls) val cs = ClassSymbol(td, id) val flag = FldFlags.empty.copy(value = true) val ps = PlainParamList(Param(flag, VarSymbol(Ident("errors")), N, Modulefulness(N)(false)) :: Nil) @@ -337,11 +338,11 @@ extends Importer: subterm(Block(d :: Unt() :: Nil)) case LetLike(`let`, lhs, rhso, S(bod)) => subterm(Block(LetLike(`let`, lhs, rhso, N) :: bod :: Nil)) - case LetLike(`let`, lhs, S(rhs), N) => + case LetLike(`let`, lhs, rhso, N) => raise(ErrorReport( msg"Expected a body for let bindings in expression position" -> tree.toLoc :: Nil)) - block(LetLike(`let`, lhs, S(rhs), N) :: Nil, hasResult = true)._1 + block(LetLike(`let`, lhs, rhso, N) :: Nil, hasResult = true)._1 case LetLike(`set`, lhs, S(rhs), N) => Term.Assgn(subterm(lhs), subterm(rhs)) case LetLike(`set`, lhs, S(rhs), S(bod)) => @@ -361,7 +362,7 @@ extends Importer: val sym = fieldOrVarSym(HandlerBind, id) log(s"Processing `handle` statement $id (${sym}) ${ctx.outer}") - val derivedClsSym = ClassSymbol(Tree.TypeDef(syntax.Cls, Tree.Error(), N, N), Tree.Ident(s"Handler$$${id.name}$$")) + val derivedClsSym = ClassSymbol(Tree.DummyTypeDef(syntax.Cls), Tree.Ident(s"Handler$$${id.name}$$")) derivedClsSym.defn = S(ClassDef( N, syntax.Cls, derivedClsSym, BlockMemberSymbol(derivedClsSym.name, Nil), @@ -481,9 +482,9 @@ extends Importer: scoped("ucs:desugared"): log(s"Desugared:\n${Split.display(des)}") Term.IfLike(Keyword.`if`, des) - case InfixApp(lhs, Keyword.`then`, rhs) => + case InfixApp(lhs, kw @ (Keyword.`then` | Keyword.`with`), rhs) => raise: - ErrorReport(msg"Unexpected infix use of 'then' keyword here" -> tree.toLoc :: Nil) + ErrorReport(msg"Unexpected infix use of keyword '${kw.name}' here" -> tree.toLoc :: Nil) Term.Error case OpApp(lhs, Ident("|"), rhs :: Nil) => Term.CompType(subterm(lhs), subterm(rhs), true) @@ -585,7 +586,10 @@ extends Importer: ) case tree @ Tup(fields) => Term.Tup(fields.map(fld(_)))(tree) - case New(body, rfto) => // TODO handle Under + // case New(c, rfto) => + // assert(rfto.isEmpty) + // Term.New(cls(subterm(c), inAppPrefix = inAppPrefix), params.map(subterm(_)), bodo).withLocOf(tree) + case ProperNew(body, rfto) => // TODO handle Under lazy val bodo = rfto.map: rft => val clsSym = new ClassSymbol(Tree.DummyTypeDef(syntax.Cls), Tree.Ident("$anon")) ctx.nestInner(clsSym).givenIn: @@ -644,7 +648,7 @@ extends Importer: Term.Throw(subterm(body)) case Modified(Keyword.`do`, kwLoc, body) => Blk(subterm(body) :: Nil, unit) - case TypeDef(Mod, head, N, N) => + case TypeDef(Mod, head, N) => subterm(head) case Tree.Region(id: Tree.Ident, body) => val sym = VarSymbol(id) @@ -667,7 +671,7 @@ extends Importer: case TermDef(k, nme, rhs) => raise(ErrorReport(msg"Illegal definition in term position." -> tree.toLoc :: Nil)) Term.Error - case TypeDef(k, head, rhs, body) => + case TypeDef(k, head, rhs) => raise(ErrorReport(msg"Illegal type declaration in term position." -> tree.toLoc :: Nil)) Term.Error case Modified(kw, kwLoc, body) => @@ -815,6 +819,9 @@ extends Importer: case Nil => reportUnusedAnnotations (mkBlk(acc, N, hasResult), ctx) + case Constructor(Block(ctors)) :: sts => + // TODO properly handle (it currently desugars to sibling classes) + go(sts, annotations, acc) case Open(bod) :: sts => reportUnusedAnnotations bod match @@ -922,7 +929,7 @@ extends Importer: LetDecl(sym, annotations) :: acc (ctx + (id.name -> sym)) givenIn: go(sts, Nil, newAcc) - case (tree @ LetLike(`let`, lhs, S(rhs), N)) :: sts => + case (tree @ LetLike(`let`, lhs, _, N)) :: sts => raise(ErrorReport(msg"Unsupported let binding shape" -> tree.toLoc :: Nil)) go(sts, Nil, Term.Error :: acc) case Def(lhs, rhs) :: sts => @@ -990,7 +997,7 @@ extends Importer: // TypeDef(Mod, _, N, N) indicates if the function marks // its result as "module". e.g, `fun f: module M` // ^^^^^^ - case S(TypeDef(Mod, _, N, N)) => + case S(TypeDef(Mod, _, N)) => Modulefulness.ofSign(s)(true) case _ => Modulefulness.none @@ -1005,8 +1012,11 @@ extends Importer: reportUnusedAnnotations raise(d) go(sts, Nil, acc) - case (td @ TypeDef(k, head, rhs, body)) :: sts => + case (td @ TypeDef(k, head, rhs)) :: sts => + assert((k is Als) || (k is Cls) || (k is Mod) || (k is Obj) || (k is Pat), k) + val body = td.withPart + td.symbName match case S(L(d)) => raise(d) case _ => () @@ -1016,9 +1026,11 @@ extends Importer: raise(d) return go(sts, Nil, acc) val sym = members.getOrElse(nme.name, lastWords(s"Symbol not found: ${nme.name}")) + var newCtx = S(td.symbol).collectFirst: case s: InnerSymbol => s .fold(ctx.nest(OuterCtx.NonReturnContext))(ctx.nestInner(_)) + val tps = td.typeParams match case S(ts) => ts.tys.flatMap: targ => @@ -1034,10 +1046,13 @@ extends Importer: vs.decl = S(res) res :: Nil case N => Nil + newCtx ++= tps.map(tp => tp.sym.name -> tp.sym) // TODO: correct ++? + val isDataClass = annotations.exists: case Annot.Modifier(Keyword.`data`) => true case _ => false + val ps = td.paramLists.match case Nil => N @@ -1054,6 +1069,7 @@ extends Importer: params(ps, isDataClass) newCtx = newCtx2 res + def withFields(using Ctx)(fn: (Ctx) ?=> (Term.Blk, Ctx)): (Term.Blk, Ctx) = val fields: Opt[List[TermDefinition | LetDecl | DefineVar]] = ps.map: ps => ps.params.flatMap: p => @@ -1084,7 +1100,6 @@ extends Importer: val decl = LetDecl(psym, Nil) val defn = DefineVar(psym, p.sym.ref()) decl :: defn :: Nil - val ctxWithFields = ctx .withMembers( fields.fold(Nil)(_.collect: @@ -1097,6 +1112,16 @@ extends Importer: val (blk, c) = fn(using ctxWithFields) val blkWithFields = fields.fold[Term.Blk](blk)(fs => blk.copy(stats = fs ::: blk.stats)) (blkWithFields, c) + + def mkBody(using Ctx) = withFields: + body match + case N | S(Error()) => (new Blk(Nil, Term.Lit(UnitLit(false))), ctx) + case S(b: Tree.Block) => block(b, hasResult = false) + case S(t) => + raise(ErrorReport( + msg"Illegal body of ${k.desc} definition (should be a block; found ${t.describe})." -> t.toLoc :: Nil)) + (new Blk(Nil, Term.Lit(UnitLit(false))), ctx) + val defn = k match case Als => val alsSym = td.symbol.asInstanceOf[TypeAliasSymbol] // TODO improve `asInstanceOf` @@ -1148,12 +1173,7 @@ extends Importer: newCtx.nestInner(clsSym).givenIn: log(s"Processing type definition $nme") val cd = - val (bod, c) = withFields: - body match - case S(b: Tree.Block) => block(b, hasResult = false) - // case S(t) => block(t :: Nil) - case S(t) => ??? - case N => (new Blk(Nil, Term.Lit(UnitLit(false))), ctx) + val (bod, c) = mkBody ModuleDef(owner, clsSym, sym, tps, ps, newOf(td), k, ObjBody(bod), annotations) clsSym.defn = S(cd) cd @@ -1163,12 +1183,7 @@ extends Importer: newCtx.nestInner(clsSym).givenIn: log(s"Processing type definition $nme") val cd = - val (bod, c) = withFields: - body match - case S(b: Tree.Block) => block(b, hasResult = false) - // case S(t) => block(t :: Nil) - case S(t) => ??? - case N => (new Blk(Nil, Term.Lit(UnitLit(false))), ctx) + val (bod, c) = mkBody ClassDef(owner, Cls, clsSym, sym, tps, ps, newOf(td), ObjBody(bod), annotations) clsSym.defn = S(cd) cd @@ -1204,7 +1219,7 @@ extends Importer: def newOf(td: TypeDef)(using Ctx): Opt[Term.New] = td.extension match - case S(ext) => S(term(New(S(ext), N))) + case S(ext) => S(term(ProperNew(S(ext), N))) case N => N match case S(n: Term.New) => S(n) @@ -1222,9 +1237,9 @@ extends Importer: def param(t: Tree, inUsing: Bool, inDataClass: Bool): Ctxl[Opt[Opt[Bool] -> Param]] = // mm: `module`-modified def go(t: Tree, inUsing: Bool, flags: FldFlags, mm: Bool): Ctxl[Opt[Opt[Bool] -> Param]] = t match - case TypeDef(Mod, inner, N, N) => + case TypeDef(Mod, inner, N) => go(inner, inUsing, flags, true) - case TypeDef(Pat, inner, N, N) => + case TypeDef(Pat, inner, N) => go(inner, inUsing, flags.copy(pat = true), mm) case TermDef(ImmutVal, inner, _) => go(inner, inUsing, flags.copy(value = true), mm) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/DeBrujinSplit.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/DeBrujinSplit.scala index fb2e280d7d..3ab4c25fc6 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/DeBrujinSplit.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/DeBrujinSplit.scala @@ -113,7 +113,7 @@ object DeBrujinSplit: case App(ctor: (Ident | Sel), Tup(params)) => dealWithCtor(ctor, params) case OpApp(lhs, op: Ident, rhs :: Nil) => dealWithCtor(op, Ls(lhs, rhs)) case literal: syntax.Literal => Branch(_, Literal(literal), _, _) - case Tree.TypeDef(syntax.Pat, body, N, N) => go(body) + case Tree.TypeDef(syntax.Pat, body, N) => go(body) scoped("ucs:rp:elaborate"): log(s"tree: ${tree.showDbg}") Binder(go(tree)(Outermost, Accept(0), Reject)) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/Desugarer.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/Desugarer.scala index caaa949933..6cba70e434 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/Desugarer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/Desugarer.scala @@ -453,7 +453,7 @@ class Desugarer(elaborator: Elaborator)(using Ctx, Raise, State, UnderCtx) exten val matches = scrutinees.iterator.zip(args).map: case (symbol, tree) => val argument = tree match - case TypeDef(syntax.Pat, body, N, N) => S(DeBrujinSplit.elaborate(Nil, body, elaborator)) + case TypeDef(syntax.Pat, body, N) => S(DeBrujinSplit.elaborate(Nil, body, elaborator)) case td @ TypeDef(k = syntax.Pat) => error(msg"Ill-formed pattern argument" -> td.toLoc); N case _ => N diff --git a/hkmc2/shared/src/main/scala/hkmc2/syntax/Keyword.scala b/hkmc2/shared/src/main/scala/hkmc2/syntax/Keyword.scala index 5447ffdc99..b453d96ef9 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/syntax/Keyword.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/syntax/Keyword.scala @@ -48,7 +48,12 @@ object Keyword: _curPrec += 1 S(_curPrec) - val `class` = Keyword("class", N, curPrec) + val `class` = Keyword("class", N, N) + + val `extends` = Keyword("extends", nextPrec, curPrec) + val `restricts` = Keyword("restricts", curPrec, curPrec) + val `with` = Keyword("with", curPrec, curPrec) + val `val` = Keyword("val", N, curPrec) val `mut` = Keyword("mut", N, curPrec) @@ -78,9 +83,10 @@ object Keyword: val `and` = Keyword("and", nextPrec, nextPrec) val `is` = Keyword("is", nextPrec, curPrec, canStartInfixOnNewLine = false) val `as` = Keyword("as", nextPrec, curPrec) - val `let` = Keyword("let", nextPrec, curPrec) - val `handle` = Keyword("handle", nextPrec, curPrec) - val `region` = Keyword("region", curPrec, curPrec) + // val `let` = Keyword("let", nextPrec, curPrec) + val `let` = Keyword("let", N, N) + val `handle` = Keyword("handle", N, N) + val `region` = Keyword("region", N, N) val `rec` = Keyword("rec", N, N) val `in` = Keyword("in", curPrec, curPrec) val `out` = Keyword("out", N, curPrec) @@ -90,17 +96,13 @@ object Keyword: val `trait` = Keyword("trait", N, N) val `mixin` = Keyword("mixin", N, N) val `interface` = Keyword("interface", N, N) - val `restricts` = Keyword("restricts", eqPrec, nextPrec) - val `extends` = Keyword("extends", nextPrec, nextPrec) - val `with` = Keyword("with", curPrec, curPrec) val `override` = Keyword("override", N, N) val `super` = Keyword("super", N, N) - val `new` = Keyword("new", N, curPrec) // TODO: check the prec // val `namespace` = Keyword("namespace", N, N) val `use` = Keyword("use", N, curPrec) val `using` = Keyword("using", N, N) - val `module` = Keyword("module", N, curPrec) - val `object` = Keyword("object", N, curPrec) + val `module` = Keyword("module", N, N) + val `object` = Keyword("object", N, N) val `open` = Keyword("open", N, curPrec) val `type` = Keyword("type", N, N) val `where` = Keyword("where", curPrec, curPrec) @@ -131,7 +133,15 @@ object Keyword: // * so that we can write things like `f() |> x => x is 0` ie `(f()) |> (x => (x is 0))` // * Currently, the precedence of normal operators starts at the maximum precedence of keywords, // * so we need to start the precedence of `=>` to account for that. - val `=>` = Keyword("=>", S(_curPrec + charPrecList.length), eqPrec) + val `=>` = Keyword("=>", S(maxPrec.get + charPrecList.length), eqPrec) + + // * `new` is a strange keyword: + // * it has a very high precedence that sits between that of selection and that of application. + // * Indeed, `new Foo().bar` should parse as `(new Foo()).bar`, not `new (Foo().bar)`, + // * but `new Foo.Bar` should parse as `new (Foo.Bar)`. + val newRightPrec = S(maxPrec.get + charPrecList.length - 1) + // * ^ maxPrec.get + charPrecList.length is the precedence of selection + val `new` = Keyword("new", N, newRightPrec) val __ = Keyword("_", N, N) @@ -139,11 +149,11 @@ object Keyword: `abstract`, mut, virtual, `override`, declare, public, `private`) type Infix = - `is`.type | `:`.type | `->`.type | `=>`.type | `extends`.type | `restricts`.type | `as`.type | `do`.type | `where`.type | + `is`.type | `:`.type | `->`.type | `=>`.type | `extends`.type | `restricts`.type | `as`.type | `do`.type | `where`.type | `with`.type | `and`.type | `or`.type | `then`.type | `else`.type type InfixSplittable = - `is`.type | `:`.type | `->`.type | `=>`.type | `extends`.type | `restricts`.type | `as`.type | `do`.type | `where`.type | + `is`.type | `:`.type | `->`.type | `=>`.type | `extends`.type | `restricts`.type | `as`.type | `do`.type | `where`.type | `with`.type | `of`.type type Ellipsis = `...`.type | `..`.type diff --git a/hkmc2/shared/src/main/scala/hkmc2/syntax/ParseRule.scala b/hkmc2/shared/src/main/scala/hkmc2/syntax/ParseRule.scala index f708d2ddad..93ce04155a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/syntax/ParseRule.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/syntax/ParseRule.scala @@ -71,18 +71,10 @@ class ParseRules(using State): Expr(body)(k) :: Blk(body)(k) :: Nil - - def typeDeclTemplateThen[A](after: Alt[A]*): Alt[(S[Tree], A)] = - Kw(`with`): - ParseRule("type declaration body")( - Blk( - ParseRule("type declaration block")(after*) - ) { case (res, t) => (S(res), t) } - ) - val typeDeclTemplate: Alt[Opt[Tree]] = typeDeclTemplateThen(end(())).map((res, _) => res) + val typeDeclTemplate: Alt[Opt[Tree]] = end(N) - /* + /* // * What we had before we allowed parsing juxtapositions def termDefBody(k: TermDefKind): ParseRule[Tree] = ParseRule(s"'${k.str}' binding keyword")( Expr( @@ -117,22 +109,11 @@ class ParseRules(using State): def typeDeclBody(k: TypeDefKind): ParseRule[TypeDef] = ParseRule("type declaration keyword"): Expr( - ParseRule("type declaration head")( - end((N, N)), - Kw(`extends`): // TODO: rm? this no longer triggers after `extension` was made an infix kw - ParseRule("extension clause")( - Expr( - ParseRule("parent specification")( - typeDeclTemplate, - end(N), - ) - ) { case (ext, bod) => (S(ext), bod) } - ), - typeDeclTemplate.map(bod => (N, bod)), - ) + ParseRule("type declaration head"): + end(()) ): - case (head, (ext, bod)) => - TypeDef(k, head, ext, bod) + case (head, ()) => + TypeDef(k, head, N) def letLike(kw: Keyword.letLike) = Kw(kw): @@ -212,7 +193,7 @@ class ParseRules(using State): ) { case (rhs, ()) => S(rhs) }, end(N), ) - ) { (lhs, rhs) => TypeDef(kind, lhs, rhs, N) } + ) { (lhs, rhs) => TypeDef(kind, lhs, rhs) } val prefixRules: ParseRule[Tree] = ParseRule("start of expression", omitAltsStr = true)( letLike(`let`), @@ -226,13 +207,17 @@ class ParseRules(using State): ParseRule("'handle' binding equals sign"): Expr( ParseRule("'handle' binding class name"): - typeDeclTemplateThen( - Kw(`in`): - ParseRule(s"'handle' binding `in` clause")( - exprOrBlk(ParseRule(s"'handle' binding body")(end(())))((body, _: Unit) => S(body))* - ), - end(N) - ) + Kw(`with`): + ParseRule("type declaration body")( + Blk( + ParseRule("type declaration block")( + Kw(`in`): + ParseRule(s"'handle' binding `in` clause")( + exprOrBlk(ParseRule(s"'handle' binding body")(end(())))((body, _: Unit) => S(body))* + ), + end(N)) + ) { case (res, t) => (S(res), t) } + ) ) { case (rhs, (S(defs), body)) => (rhs, defs, body) } ) { case (lhs, (rhs, defs, body)) => Hndl(lhs, rhs, defs, body) } , @@ -245,11 +230,11 @@ class ParseRules(using State): ) ParseRule("`new` keyword")( ( - withRefinement.map(rfto => New(N, rfto)) :: + withRefinement.map(rfto => LexicalNew(N, rfto)) :: exprOrBlk(ParseRule("`new` expression")( withRefinement, end(N), - ))((body, rfto) => New(S(body), rfto)) + ))((body, rfto) => LexicalNew(S(body), rfto)) )* ) , @@ -399,6 +384,7 @@ class ParseRules(using State): genInfixRule(`restricts`, (rhs, _: Unit) => lhs => InfixApp(lhs, `restricts`, rhs)), genInfixRule(`do`, (rhs, _: Unit) => lhs => InfixApp(lhs, `do`, rhs)), genInfixRule(`where`, (rhs, _: Unit) => lhs => InfixApp(lhs, `where`, rhs)), + genInfixRule(`with`, (rhs, _: Unit) => lhs => InfixApp(lhs, `with`, rhs)), ) end ParseRules diff --git a/hkmc2/shared/src/main/scala/hkmc2/syntax/Parser.scala b/hkmc2/shared/src/main/scala/hkmc2/syntax/Parser.scala index eebdeca59b..78df8d049d 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/syntax/Parser.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/syntax/Parser.scala @@ -40,6 +40,7 @@ val charPrecList: List[Str] = List( "~", "", // Precedence of prefix operators "", // Precedence of application + "", // Precedence of `new` // ".", ". \\", ) @@ -63,6 +64,8 @@ object Parser: case (cs, i) => cs.filterNot(_ === ' ').map(_ -> (i + Keyword.maxPrec.get)) }.toMap.withDefaultValue(Int.MaxValue) + // * Note: keywords without a specified right precedence are now assumed to have right precedence `CommaPrecNext` + // private val CommaPrec = prec(',') private val CommaPrec = 0 private val CommaPrecNext = CommaPrec + 1 @@ -317,7 +320,8 @@ abstract class Parser( errExpr blk.map(annotations.annotate) ::: blockContOf(rule) case _ => - val res = parseRule(CommaPrecNext, subRule, allowNewlines = allowNewlines).getOrElse(errExpr) + val p = kw.rightPrec.getOrElse(CommaPrecNext) + val res = parseRule(p, subRule, allowNewlines = allowNewlines).getOrElse(errExpr) annotations.annotate(exprCont(res, CommaPrecNext, allowNewlines = allowNewlines)) :: blockContOf(rule) case N => @@ -411,9 +415,9 @@ abstract class Parser( case (tok @ BRACKETS(_: Indent_Curly, toks), loc) :: _ if subRule.blkAlt.isEmpty => consume rec(toks, S(tok.innerLoc), tok.describe) - .concludeWith(_.parseRule(kw.rightPrecOrMax, subRule, allowNewlines = true)) + .concludeWith(_.parseRule(kw.rightPrec.getOrElse(CommaPrecNext), subRule, allowNewlines = true)) case _ => - parseRule(kw.rightPrecOrMax, subRule, allowNewlines = allowNewlines) + parseRule(kw.rightPrec.getOrElse(CommaPrecNext), subRule, allowNewlines = allowNewlines) case N => if verbose then printDbg(s"$$ cannot find a rule starting with: ${id.name}") rule.exprAlt match diff --git a/hkmc2/shared/src/main/scala/hkmc2/syntax/Tree.scala b/hkmc2/shared/src/main/scala/hkmc2/syntax/Tree.scala index b501cb1d79..30e36524f3 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/syntax/Tree.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/syntax/Tree.scala @@ -58,7 +58,7 @@ enum Tree extends AutoLocated: case Hndl(lhs: Tree, cls: Tree, defs: Tree, body: Opt[Tree]) case Def(lhs: Tree, rhs: Tree) case TermDef(k: TermDefKind, head: Tree, rhs: Opt[Tree]) extends Tree with TermDefImpl - case TypeDef(k: TypeDefKind, head: Tree, rhs: Opt[Tree], body: Opt[Tree])(using State) + case TypeDef(k: TypeDefKind, head: Tree, rhs: Opt[Tree])(using State) extends Tree with TypeDefImpl case Open(opened: Tree) case OpenIn(opened: Tree, body: Tree) @@ -75,7 +75,8 @@ enum Tree extends AutoLocated: case Sel(prefix: Tree, name: Ident) case MemberProj(cls: Tree, name: Ident) case InfixApp(lhs: Tree, kw: Keyword.Infix, rhs: Tree) - case New(body: Opt[Tree], rft: Opt[Block]) + case LexicalNew(body: Opt[Tree], rft: Opt[Block]) // * New as it is parsed, with its weird precedence + case ProperNew(body: Opt[Tree], rft: Opt[Block]) // * A desugared version of New that sets it right case IfLike(kw: Keyword.`if`.type | Keyword.`while`.type, kwLoc: Opt[Loc], split: Tree) case SplitPoint() case OpSplit(lhs: Tree, ops_rhss: Ls[Tree]) // * the rhss trees are expressions rooted in `SplitPoint`s @@ -111,8 +112,7 @@ enum Tree extends AutoLocated: case Hndl(lhs, rhs, defs, body) => body match case Some(value) => lhs :: rhs :: defs :: value :: Nil case None => lhs :: rhs :: defs :: Nil - case TypeDef(k, head, extension, body) => - head :: extension.toList ::: body.toList + case TypeDef(k, head, rhs) => head :: rhs.toList case Modified(_, _, body) => Ls(body) case Quoted(body) => Ls(body) case Unquoted(body) => Ls(body) @@ -122,7 +122,8 @@ enum Tree extends AutoLocated: case Jux(lhs, rhs) => Ls(lhs, rhs) case InfixApp(lhs, _, rhs) => Ls(lhs, rhs) case TermDef(k, head, rhs) => head :: rhs.toList - case New(body, rft) => body.toList ::: rft.toList + case LexicalNew(body, rft) => body.toList ::: rft.toList + case ProperNew(body, rft) => body.toList ::: rft.toList case IfLike(_, _, split) => split :: Nil case Case(_, bs) => Ls(bs) case Region(name, body) => name :: body :: Nil @@ -161,7 +162,7 @@ enum Tree extends AutoLocated: case Block(stmts) => "block" case LetLike(kw, lhs, rhs, body) => kw.name case TermDef(k, alphaName, rhs) => "term definition" - case TypeDef(k, head, extension, body) => "type definition" + case TypeDef(k, head, rhs) => "type definition" case Modified(kw, _, body) => s"${kw.name}-modified ${body.describe}" case Quoted(body) => "quoted" case Unquoted(body) => "unquoted" @@ -175,7 +176,8 @@ enum Tree extends AutoLocated: case DynAccess(prefix, name, true) => "dynamic index access" case DynAccess(prefix, name, false) => "dynamic field access" case InfixApp(lhs, kw, rhs) => "infix operator" - case New(body, _) => "new" + case LexicalNew(body, _) => "new" + case ProperNew(body, _) => "new" case IfLike(Keyword.`if`, _, split) => "if expression" case IfLike(Keyword.`while`, _, split) => "while expression" case Case(_, branches) => "case" @@ -228,6 +230,13 @@ enum Tree extends AutoLocated: // TODO only do this if the lhs is non-expansive/a valid assignment receiver? PossiblyAnnotated(anns, LetLike(letLike, lhs, S(OpApp(lhs, Ident(nme.init), rhss)), bodo).withLocOf(this).desugared) + case Apps(LexicalNew(S(body), N), argss) => + ProperNew(S(Apps(body, argss)), N).withLocOf(this) + case LexicalNew(bodo, rfto) => + ProperNew(bodo, rfto).withLocOf(this) + case InfixApp(Desugared(ProperNew(bodo, N)), Keyword.`with`, rhs: Block) => + ProperNew(bodo, S(rhs)).withLocOf(this) + case _ => this /** @@ -252,14 +261,14 @@ enum Tree extends AutoLocated: case _ => S(N, Ident(""), S(inner)) def isModuleModifier: Bool = this match - case Tree.TypeDef(Mod, _, N, N) => true + case td @ Tree.TypeDef(Mod, _, rhs) => rhs.isEmpty && td.extension.isEmpty && td.withPart.isEmpty case _ => false object Tree: val DummyApp: App = App(Dummy, Dummy) // TODO change the places where this is used val DummyTup: Tup = Tup(Dummy :: Nil) def DummyTypeDef(k: TypeDefKind)(using State): TypeDef = - Tree.TypeDef(syntax.Cls, Tree.Dummy, N, N) + Tree.TypeDef(syntax.Cls, Tree.Dummy, N) object Block: def mk(stmts: Ls[Tree])(using State): Tree = stmts match case Nil => UnitLit(false) @@ -272,10 +281,16 @@ object Tree: case App(lhs, TyTup(targs)) => S(lhs, targs) case _ => N +object Desugared: + def unapply(t: Tree): S[Tree] = S(t.desugared) + object PlainTup: def apply(fields: Tree*): Tree = Tup(fields.toList) object Apps: + def apply(t: Tree, as: Ls[Tup]): Tree = as match + case Nil => t + case arg :: args => App(Apps(t, args), arg) def unapply(t: Tree): S[(Tree, Ls[Tup])] = t match case App(Apps(base, args), arg: Tup) => S(base, args :+ arg) case t => S(t, Nil) @@ -304,7 +319,7 @@ case object LetBind extends ValLike("let", "let binding") case object HandlerBind extends TermDefKind("handler", "handler binding") case object ParamBind extends ValLike("", "parameter") case object Fun extends TermDefKind("fun", "function") -case object Ins extends TermDefKind("use", "implicit instance") +case object Ins extends TermDefKind("using", "implicit instance") sealed abstract class TypeDefKind(desc: Str) extends DeclKind(desc) sealed trait ObjDefKind sealed trait ClsLikeKind extends ObjDefKind: @@ -397,12 +412,16 @@ trait TypeOrTermDef: rec(baseHead, N, N) - val (baseHead, extension) = + val (baseHead, extension, withPart) = head match + case InfixApp(InfixApp(base, Keyword.`extends`, ext), Keyword.`with`, wp) => + (base, S(ext), S(wp)) + case InfixApp(base, Keyword.`with`, wp) => + (base, N, S(wp)) case InfixApp(base, Keyword.`extends`, ext) => - (base, S(ext)) + (base, S(ext), N) case h => - (h, N) + (h, N, N) end TypeOrTermDef @@ -423,7 +442,7 @@ trait TypeDefImpl(using State) extends TypeOrTermDef: lazy val definedSymbols: Map[Str, semantics.BlockMemberSymbol] = // val fromParams = // val fromTypeParams = - body match + withPart match case S(blk: Block) => blk.definedSymbols.toMap case _ => diff --git a/hkmc2/shared/src/test/mlscript-compile/Char.mls b/hkmc2/shared/src/test/mlscript-compile/Char.mls index 0914081a6d..e4d7a7cfcf 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Char.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Char.mls @@ -1,3 +1,4 @@ + module Char with pattern Lowercase = "a" ..= "z" pattern Uppercase = "A" ..= "Z" @@ -7,3 +8,4 @@ module Char with pattern OctDigit = "0" ..= "7" pattern BinDigit = "0" | "1" pattern Whitespace = " " | "\t" | "\n" | "\r" + diff --git a/hkmc2/shared/src/test/mlscript/backlog/Lifter.mls b/hkmc2/shared/src/test/mlscript/backlog/Lifter.mls index a7e565eea5..216955578b 100644 --- a/hkmc2/shared/src/test/mlscript/backlog/Lifter.mls +++ b/hkmc2/shared/src/test/mlscript/backlog/Lifter.mls @@ -160,7 +160,13 @@ fun foo(x, y) = //│ ═══[WARNING] Modules are not yet lifted. //│ ╔══[COMPILATION ERROR] No definition found in scope for 'M' //│ ║ l.154: module M with -//│ ╙── ^ +//│ ║ ^^^^^^ +//│ ║ l.155: fun foo() = +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.156: set y = 2 +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.157: x + y +//│ ╙── ^^^^^^^^^^^ :expect 12 foo(10, 0) @@ -199,5 +205,11 @@ fun f = M.g //│ ═══[WARNING] Modules are not yet lifted. //│ ╔══[COMPILATION ERROR] No definition found in scope for 'M' -//│ ║ l.195: module M with -//│ ╙── ^ +//│ ║ l.201: module M with +//│ ║ ^^^^^^ +//│ ║ l.202: fun g = +//│ ║ ^^^^^^^^^^^ +//│ ║ l.203: fun h = M.g +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.204: h +//│ ╙── ^^^^^^^ diff --git a/hkmc2/shared/src/test/mlscript/backlog/NewWith.mls b/hkmc2/shared/src/test/mlscript/backlog/NewWith.mls index 6413247c8e..18d44500e6 100644 --- a/hkmc2/shared/src/test/mlscript/backlog/NewWith.mls +++ b/hkmc2/shared/src/test/mlscript/backlog/NewWith.mls @@ -22,20 +22,41 @@ new Object with //│ ║ l.20: new Object with //│ ╙── ^ +:pe +new Object with 1 +//│ ╔══[PARSE ERROR] Expected block after 'new' body; found literal instead +//│ ║ l.26: new Object with 1 +//│ ╙── ^ +//│ ╔══[PARSE ERROR] Expected end of input; found literal instead +//│ ║ l.26: new Object with 1 +//│ ╙── ^ + +:e +(new Object) with 1 +//│ ╔══[ERROR] Unexpected infix use of keyword 'with' here +//│ ║ l.35: (new Object) with 1 +//│ ╙── ^^^^^^^^^^^^^^^^^^^ + +// TODO don't show as `$anon` +new Object with { val x = 1 } +//│ = $anon + +:e +new Object with { val x = 1 } with { val y = 1 } +//│ ╔══[ERROR] Unexpected infix use of keyword 'with' here +//│ ║ l.45: new Object with { val x = 1 } with { val y = 1 } +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + let obj = new Object with - val x = 12 + val x = 12 //│ obj = $anon obj.x //│ = 12 -:s -// :pt -// :lot -// :dl -// :sjs -// :lot + let n = new with val x = 12 @@ -45,30 +66,38 @@ n.x //│ = 12 -:sjs -object Foo with - val x = 1 -//│ JS (unsanitized): -//│ let Foo1; -//│ const Foo$class = class Foo { -//│ constructor() { -//│ this.x = 1; -//│ } -//│ toString() { return "Foo"; } -//│ }; Foo1 = new Foo$class; -//│ Foo1.class = Foo$class; - - class Foo(x) with fun foo = x + 1 print("Foo", x, foo) +new Foo(123) with { fun foo = 27 } +//│ > Foo 123 27 +//│ = $anon + +// TODO change semantics? Looks error-prone +:re +new (Foo(123)) with { fun foo = 27 } +//│ > Foo 123 124 +//│ ═══[RUNTIME ERROR] TypeError: Class extends value [object Object] is not a constructor or null + +// TODO change semantics? Looks error-prone +:re +new {Foo(123)} with { fun foo = 27 } +//│ > Foo 123 124 +//│ ═══[RUNTIME ERROR] TypeError: Class extends value [object Object] is not a constructor or null + new Foo(123) with - // fun foo = super.foo + 1 // TODO + // fun foo = super.foo + 1 // TODO (super) fun foo = 27 print("Bar", foo) //│ > Foo 123 27 //│ > Bar 27 //│ = $anon +:e +new Foo(123) with 1 +//│ ╔══[ERROR] Unexpected infix use of keyword 'with' here +//│ ║ l.98: new Foo(123) with 1 +//│ ╙── ^^^^^^^^^^^^^^^ + diff --git a/hkmc2/shared/src/test/mlscript/backlog/ToTriage.mls b/hkmc2/shared/src/test/mlscript/backlog/ToTriage.mls index b9d196c032..7f082df749 100644 --- a/hkmc2/shared/src/test/mlscript/backlog/ToTriage.mls +++ b/hkmc2/shared/src/test/mlscript/backlog/ToTriage.mls @@ -223,7 +223,7 @@ class Foo' with module Example with // whoops val a = this -//│ ╔══[PARSE ERROR] Expected block after type declaration body; found new line instead +//│ ╔══[PARSE ERROR] Expected start of expression in this position; found new line instead //│ ║ l.223: module Example with //│ ║ ^ //│ ║ l.224: // whoops diff --git a/hkmc2/shared/src/test/mlscript/basics/ADTs.mls b/hkmc2/shared/src/test/mlscript/basics/ADTs.mls index 260fac1262..76d15f75ff 100644 --- a/hkmc2/shared/src/test/mlscript/basics/ADTs.mls +++ b/hkmc2/shared/src/test/mlscript/basics/ADTs.mls @@ -15,11 +15,12 @@ class Expr[A] with constructor Lit(n: Int) { A = Int } Add(lhs: Expr[Int], rhs: Expr[Int]) { A = Int } -//│ ╔══[ERROR] Unsupported constructor in this position. +//│ ╔══[ERROR] Expected a valid class definition head; found block instead //│ ║ l.16: Lit(n: Int) { A = Int } -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Expected a valid class definition head; found block instead //│ ║ l.17: Add(lhs: Expr[Int], rhs: Expr[Int]) { A = Int } -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^ // * one can also go the TypeScript way @@ -36,7 +37,7 @@ enum Expr = | Lit(n: Int) | Add(lhs: Expr, rhs: Expr) //│ ╔══[ERROR] Unrecognized definitional assignment left-hand side: juxtaposition -//│ ║ l.35: enum Expr = +//│ ║ l.36: enum Expr = //│ ╙── ^^^^^^^^^ diff --git a/hkmc2/shared/src/test/mlscript/basics/BlockArgs.mls b/hkmc2/shared/src/test/mlscript/basics/BlockArgs.mls index bd8927c333..97555fbe29 100644 --- a/hkmc2/shared/src/test/mlscript/basics/BlockArgs.mls +++ b/hkmc2/shared/src/test/mlscript/basics/BlockArgs.mls @@ -33,12 +33,9 @@ foo(1) { x => x } //│ ╙── ^^^^^^ foo(1) with x => x -//│ ╔══[PARSE ERROR] Expected end of input; found 'with' keyword instead +//│ ╔══[ERROR] Unexpected infix use of keyword 'with' here //│ ║ l.35: foo(1) with x => x -//│ ╙── ^^^^ -//│ ╔══[ERROR] Name not found: foo -//│ ║ l.35: foo(1) with x => x -//│ ╙── ^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^ diff --git a/hkmc2/shared/src/test/mlscript/basics/Indentation.mls b/hkmc2/shared/src/test/mlscript/basics/Indentation.mls index f838fd3c5b..450ac9ac7e 100644 --- a/hkmc2/shared/src/test/mlscript/basics/Indentation.mls +++ b/hkmc2/shared/src/test/mlscript/basics/Indentation.mls @@ -175,17 +175,19 @@ P.x //│ Parsed tree: //│ TypeDef: //│ k = Mod -//│ head = Ident of "P" +//│ head = InfixApp: +//│ lhs = Ident of "P" +//│ kw = keyword 'with' +//│ rhs = Block of Ls of +//│ App: +//│ lhs = Ident of "print" +//│ rhs = Tup of Ls of +//│ IntLit of 2 +//│ TermDef: +//│ k = ImmutVal +//│ head = Ident of "x" +//│ rhs = S of IntLit of 1 //│ rhs = N -//│ body = S of Block of Ls of -//│ App: -//│ lhs = Ident of "print" -//│ rhs = Tup of Ls of -//│ IntLit of 2 -//│ TermDef: -//│ k = ImmutVal -//│ head = Ident of "x" -//│ rhs = S of IntLit of 1 //│ Sel: //│ prefix = Ident of "P" //│ name = Ident of "x" diff --git a/hkmc2/shared/src/test/mlscript/basics/Modules.mls b/hkmc2/shared/src/test/mlscript/basics/Modules.mls index 9f0779061a..ca365f9ffe 100644 --- a/hkmc2/shared/src/test/mlscript/basics/Modules.mls +++ b/hkmc2/shared/src/test/mlscript/basics/Modules.mls @@ -5,21 +5,21 @@ module Foo :pe module Foo with -//│ ╔══[PARSE ERROR] Expected block after type declaration body; found end of input instead +//│ ╔══[PARSE ERROR] Expected start of expression in this position; found end of input instead //│ ║ l.7: module Foo with //│ ╙── ^ -:fixme +:e module Foo with val x = 1 -//│ ╔══[PARSE ERROR] Expected block after type declaration body; found 'val' keyword instead +//│ ╔══[ERROR] Illegal body of module definition (should be a block; found term definition). //│ ║ l.13: module Foo with val x = 1 -//│ ╙── ^^^ -//│ ╔══[PARSE ERROR] Expected end of input; found '=' keyword instead -//│ ║ l.13: module Foo with val x = 1 -//│ ╙── ^ -//│ ╔══[ERROR] Illegal juxtaposition right-hand side (identifier). -//│ ║ l.13: module Foo with val x = 1 -//│ ╙── ^ +//│ ╙── ^^^^^ + +:e +Foo.x +//│ ╔══[ERROR] Module 'Foo' does not contain member 'x' +//│ ║ l.19: Foo.x +//│ ╙── ^^ module Foo with val x = 1 diff --git a/hkmc2/shared/src/test/mlscript/basics/MultilineExpressions.mls b/hkmc2/shared/src/test/mlscript/basics/MultilineExpressions.mls index 6e38de1fc4..3f84379e1a 100644 --- a/hkmc2/shared/src/test/mlscript/basics/MultilineExpressions.mls +++ b/hkmc2/shared/src/test/mlscript/basics/MultilineExpressions.mls @@ -131,7 +131,7 @@ if 1 + 2 //│ ╟── Note: the operator split starts here //│ ║ l.120: * 3 then 0 //│ ╙── ^ -//│ ╔══[ERROR] Unexpected infix use of 'then' keyword here +//│ ╔══[ERROR] Unexpected infix use of keyword 'then' here //│ ║ l.119: if 1 + 2 //│ ║ ^ //│ ║ l.120: * 3 then 0 diff --git a/hkmc2/shared/src/test/mlscript/basics/NewlineOps.mls b/hkmc2/shared/src/test/mlscript/basics/NewlineOps.mls index 7c9dfac08d..fe710cbcd1 100644 --- a/hkmc2/shared/src/test/mlscript/basics/NewlineOps.mls +++ b/hkmc2/shared/src/test/mlscript/basics/NewlineOps.mls @@ -408,27 +408,26 @@ ys |> Arr.len class Foo(x) -:re new Foo(1) is Foo -//│ ═══[RUNTIME ERROR] TypeError: tmp83 is not a constructor +//│ = true :fixme // ? new Foo(1) ,is Foo //│ ╔══[PARSE ERROR] Expected start of expression in this position; found 'is' keyword instead -//│ ║ l.416: new Foo(1) ,is Foo +//│ ║ l.415: new Foo(1) ,is Foo //│ ╙── ^^ //│ ╔══[PARSE ERROR] Expected end of input; found identifier instead -//│ ║ l.416: new Foo(1) ,is Foo +//│ ║ l.415: new Foo(1) ,is Foo //│ ╙── ^^^ :fixme // ? new Foo(1) is Foo //│ ╔══[PARSE ERROR] Expected start of expression in this position; found 'is' keyword instead -//│ ║ l.426: is Foo +//│ ║ l.425: is Foo //│ ╙── ^^ //│ ╔══[PARSE ERROR] Expected end of input; found identifier instead -//│ ║ l.426: is Foo +//│ ║ l.425: is Foo //│ ╙── ^^^ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbSyntax.mls b/hkmc2/shared/src/test/mlscript/bbml/bbSyntax.mls index 800a38c30a..c8242a81a3 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbSyntax.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbSyntax.mls @@ -5,23 +5,23 @@ //│ Type: ⊤ data class Foo //│ Parsed: -//│ Modified(keyword 'data',None,TypeDef(Cls,Ident(Foo),None,None)) +//│ Modified(keyword 'data',None,TypeDef(Cls,Ident(Foo),None)) data class Bar(x: Int) //│ Parsed: -//│ Modified(keyword 'data',None,TypeDef(Cls,App(Ident(Bar),Tup(List(InfixApp(Ident(x),keyword ':',Ident(Int))))),None,None)) +//│ Modified(keyword 'data',None,TypeDef(Cls,App(Ident(Bar),Tup(List(InfixApp(Ident(x),keyword ':',Ident(Int))))),None)) data class Bar2(x: Int, y: Int) //│ Parsed: -//│ Modified(keyword 'data',None,TypeDef(Cls,App(Ident(Bar2),Tup(List(InfixApp(Ident(x),keyword ':',Ident(Int)), InfixApp(Ident(y),keyword ':',Ident(Int))))),None,None)) +//│ Modified(keyword 'data',None,TypeDef(Cls,App(Ident(Bar2),Tup(List(InfixApp(Ident(x),keyword ':',Ident(Int)), InfixApp(Ident(y),keyword ':',Ident(Int))))),None)) data class Baz[A] //│ Parsed: -//│ Modified(keyword 'data',None,TypeDef(Cls,App(Ident(Baz),TyTup(List(Ident(A)))),None,None)) +//│ Modified(keyword 'data',None,TypeDef(Cls,App(Ident(Baz),TyTup(List(Ident(A)))),None)) data class BazBaz[A](f: A -> A) //│ Parsed: -//│ Modified(keyword 'data',None,TypeDef(Cls,App(App(Ident(BazBaz),TyTup(List(Ident(A)))),Tup(List(InfixApp(Ident(f),keyword ':',InfixApp(Tup(List(Ident(A))),keyword '->',Ident(A)))))),None,None)) +//│ Modified(keyword 'data',None,TypeDef(Cls,App(App(Ident(BazBaz),TyTup(List(Ident(A)))),Tup(List(InfixApp(Ident(f),keyword ':',InfixApp(Tup(List(Ident(A))),keyword '->',Ident(A)))))),None)) Baz[Int] //│ Parsed: @@ -77,19 +77,19 @@ f of false let bar = new Bar(42) //│ Parsed: -//│ LetLike(keyword 'let',Ident(bar),Some(New(Some(App(Ident(Bar),Tup(List(IntLit(42))))),None)),None) +//│ LetLike(keyword 'let',Ident(bar),Some(App(LexicalNew(Some(Ident(Bar)),None),Tup(List(IntLit(42))))),None) let bar = new Bar2(1, 1) //│ Parsed: -//│ LetLike(keyword 'let',Ident(bar),Some(New(Some(App(Ident(Bar2),Tup(List(IntLit(1), IntLit(1))))),None)),None) +//│ LetLike(keyword 'let',Ident(bar),Some(App(LexicalNew(Some(Ident(Bar2)),None),Tup(List(IntLit(1), IntLit(1))))),None) new Bar(0) //│ Parsed: -//│ New(Some(App(Ident(Bar),Tup(List(IntLit(0))))),None) +//│ App(LexicalNew(Some(Ident(Bar)),None),Tup(List(IntLit(0)))) new Bar2(114, 514) //│ Parsed: -//│ New(Some(App(Ident(Bar2),Tup(List(IntLit(114), IntLit(514))))),None) +//│ App(LexicalNew(Some(Ident(Bar2)),None),Tup(List(IntLit(114), IntLit(514)))) fun inc: Int -> Int //│ Parsed: diff --git a/hkmc2/shared/src/test/mlscript/codegen/BadNew.mls b/hkmc2/shared/src/test/mlscript/codegen/BadNew.mls index 70f8afd7d7..22e67f0f4f 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/BadNew.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/BadNew.mls @@ -15,8 +15,8 @@ new 2 :re new 2 + 2 //│ JS (unsanitized): -//│ let tmp; tmp = 2 + 2; new tmp() -//│ ═══[RUNTIME ERROR] TypeError: tmp is not a constructor +//│ let tmp; tmp = new 2(); tmp + 2 +//│ ═══[RUNTIME ERROR] TypeError: 2 is not a constructor :re new() @@ -34,7 +34,7 @@ new {} :todo new { x = 1 } //│ Parsed tree: -//│ New: +//│ LexicalNew: //│ body = S of Block of Ls of //│ Def: //│ lhs = Ident of "x" diff --git a/hkmc2/shared/src/test/mlscript/codegen/Bindings.mls b/hkmc2/shared/src/test/mlscript/codegen/Bindings.mls index f0fdcc9b4a..abb715d15a 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/Bindings.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/Bindings.mls @@ -51,40 +51,42 @@ let x |>= incr //│ x = 3 -:todo // proper error +:e let 2 -//│ /!!!\ Uncaught error: scala.MatchError: LetLike(keyword 'let',IntLit(2),None,None) (of class hkmc2.syntax.Tree$LetLike) +//│ ╔══[ERROR] Unsupported let binding shape +//│ ║ l.55: let 2 +//│ ╙── ^ :e let x += 1 = 0 //│ ╔══[ERROR] Unsupported let binding shape -//│ ║ l.59: let x += 1 = 0 +//│ ║ l.61: let x += 1 = 0 //│ ╙── ^^^^^^^^^^ :e let x += 1 = 0 in x //│ ╔══[ERROR] Unsupported let binding shape -//│ ║ l.65: let x += 1 = 0 in x +//│ ║ l.67: let x += 1 = 0 in x //│ ╙── ^^^^^^^^^^ :e (let x = 1) //│ ╔══[ERROR] Expected a body for let bindings in expression position -//│ ║ l.72: (let x = 1) +//│ ║ l.74: (let x = 1) //│ ╙── ^^^^^ :e (let x = 1) + 1 //│ ╔══[ERROR] Expected a body for let bindings in expression position -//│ ║ l.78: (let x = 1) + 1 +//│ ║ l.80: (let x = 1) + 1 //│ ╙── ^^^^^ //│ = "()1" :e (let f(x) = x) + 1 //│ ╔══[ERROR] Expected a body for let bindings in expression position -//│ ║ l.85: (let f(x) = x) + 1 +//│ ║ l.87: (let f(x) = x) + 1 //│ ╙── ^^^^^^^^ //│ = "()1" diff --git a/hkmc2/shared/src/test/mlscript/codegen/CaseShorthand.mls b/hkmc2/shared/src/test/mlscript/codegen/CaseShorthand.mls index 9eecf4f576..07cfe17f23 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/CaseShorthand.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/CaseShorthand.mls @@ -56,7 +56,7 @@ case 0 then true :todo // TODO: support this braceless syntax? case [x] then x, [] then 0 -//│ ╔══[ERROR] Unexpected infix use of 'then' keyword here +//│ ╔══[ERROR] Unexpected infix use of keyword 'then' here //│ ║ l.58: case [x] then x, [] then 0 //│ ╙── ^^^^^^^^^ //│ ╔══[WARNING] Pure expression in statement position diff --git a/hkmc2/shared/src/test/mlscript/codegen/ImportMLs.mls b/hkmc2/shared/src/test/mlscript/codegen/ImportMLs.mls index b99b8a9ff1..cbf4107dbe 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/ImportMLs.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/ImportMLs.mls @@ -42,14 +42,12 @@ Some(1) //│ let tmp3; tmp3 = new Option.Some.class(1); Option.isDefined(tmp3) //│ = true -:re new Some(1) isDefined() -//│ ═══[RUNTIME ERROR] TypeError: tmp5 is not a constructor +//│ = true -:re new Some(1) isDefined() -//│ ═══[RUNTIME ERROR] TypeError: tmp7 is not a constructor +//│ = true open Option { Some, None, isDefined } @@ -68,14 +66,14 @@ None == Option.None :re Option.oops //│ ╔══[ERROR] Module 'Option' does not contain member 'oops' -//│ ║ l.69: Option.oops +//│ ║ l.67: Option.oops //│ ╙── ^^^^^ //│ ═══[RUNTIME ERROR] Error: Access to required field 'oops' yielded 'undefined' :e open Option { oops } //│ ╔══[ERROR] Module 'Option' does not contain member 'oops' -//│ ║ l.76: open Option { oops } +//│ ║ l.74: open Option { oops } //│ ╙── ^^^^ oops @@ -84,7 +82,7 @@ oops :re Option.None.oops //│ ╔══[ERROR] Object 'None' does not contain member 'oops' -//│ ║ l.85: Option.None.oops +//│ ║ l.83: Option.None.oops //│ ╙── ^^^^^ //│ ═══[RUNTIME ERROR] Error: Access to required field 'oops' yielded 'undefined' diff --git a/hkmc2/shared/src/test/mlscript/codegen/ImportMLsJS.mls b/hkmc2/shared/src/test/mlscript/codegen/ImportMLsJS.mls index 44784993fa..76c89394c4 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/ImportMLsJS.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/ImportMLsJS.mls @@ -32,24 +32,8 @@ String(new Option.Both(1, 2)) Option.None String() //│ = "None" -// * Not sure this should be fixed. -// * The weird precedence of `new` is always a pain -:pt -:fixme +// * This used to misbehave due to inadequately handling the weird precedence of `new` new Option.Some(1) String() -//│ Parsed tree: -//│ New: -//│ body = S of Jux: -//│ lhs = App: -//│ lhs = Sel: -//│ prefix = Ident of "Option" -//│ name = Ident of "Some" -//│ rhs = Tup of Ls of -//│ IntLit of 1 -//│ rhs = App: -//│ lhs = Ident of "String" -//│ rhs = Tup of Nil -//│ rft = N -//│ ═══[RUNTIME ERROR] TypeError: tmp5 is not a constructor +//│ = "Some(1)" diff --git a/hkmc2/shared/src/test/mlscript/codegen/PlainClasses.mls b/hkmc2/shared/src/test/mlscript/codegen/PlainClasses.mls index 1aa431c506..1e0e11aa42 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/PlainClasses.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/PlainClasses.mls @@ -231,18 +231,12 @@ class Foo with // ——— TODO ——— -:fixme +:e class Foo with val x = 1 -//│ ╔══[PARSE ERROR] Expected block after type declaration body; found 'val' keyword instead -//│ ║ l.235: class Foo with val x = 1 -//│ ╙── ^^^ -//│ ╔══[PARSE ERROR] Expected end of input; found '=' keyword instead -//│ ║ l.235: class Foo with val x = 1 -//│ ╙── ^ -//│ ╔══[ERROR] Illegal juxtaposition right-hand side (identifier). +//│ ╔══[ERROR] Illegal body of class definition (should be a block; found term definition). //│ ║ l.235: class Foo with val x = 1 -//│ ╙── ^ +//│ ╙── ^^^^^ //│ JS (unsanitized): -//│ /* error */ +//│ let Foo16; Foo16 = class Foo15 { constructor() {} toString() { return "Foo"; } }; diff --git a/hkmc2/shared/src/test/mlscript/codegen/ThisCallVariations.mls b/hkmc2/shared/src/test/mlscript/codegen/ThisCallVariations.mls index 5d27683626..3b79138031 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/ThisCallVariations.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/ThisCallVariations.mls @@ -79,13 +79,13 @@ Example2(1). oops2(2). oops2(2) :todo new Example2(1) . oops2(2) -//│ ═══[RUNTIME ERROR] TypeError: tmp16 is not a constructor +//│ = Example2(1) :todo new Example2(1) . oops2(2) . oops2(2) -//│ ═══[RUNTIME ERROR] TypeError: tmp21 is not a constructor +//│ = Example2(1) // * Alternative syntax – precedence is now inappropriate @@ -105,7 +105,7 @@ Example .> oops(2) //│ rhs = Tup of Ls of //│ IntLit of 2 //│ JS (unsanitized): -//│ let tmp22; tmp22 = runtime.safeCall(oops(2)); call1(Example1, tmp22) +//│ let tmp21; tmp21 = runtime.safeCall(oops(2)); call1(Example1, tmp21) //│ ═══[RUNTIME ERROR] TypeError: Cannot read properties of undefined (reading 'a') // * Note: diff --git a/hkmc2/shared/src/test/mlscript/codegen/While.mls b/hkmc2/shared/src/test/mlscript/codegen/While.mls index a551c8d400..091eb19026 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/While.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/While.mls @@ -269,7 +269,7 @@ while print("Hello World"); false while { print("Hello World"), false } then 0(0) else 1 -//│ ╔══[ERROR] Unexpected infix use of 'then' keyword here +//│ ╔══[ERROR] Unexpected infix use of keyword 'then' here //│ ║ l.269: while { print("Hello World"), false } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.270: then 0(0) @@ -282,7 +282,7 @@ while false then 0(0) else 1 -//│ ╔══[ERROR] Unexpected infix use of 'then' keyword here +//│ ╔══[ERROR] Unexpected infix use of keyword 'then' here //│ ║ l.281: print("Hello World") //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ║ l.282: false diff --git a/hkmc2/shared/src/test/mlscript/parser/Block.mls b/hkmc2/shared/src/test/mlscript/parser/Block.mls index 8d8f3785cb..0ff6396e2d 100644 --- a/hkmc2/shared/src/test/mlscript/parser/Block.mls +++ b/hkmc2/shared/src/test/mlscript/parser/Block.mls @@ -23,7 +23,7 @@ a, b, c class A, res //│ Parsed: -//│ TypeDef(Cls,Ident(A),None,None) +//│ TypeDef(Cls,Ident(A),None) //│ Ident(res) diff --git a/hkmc2/shared/src/test/mlscript/parser/Class.mls b/hkmc2/shared/src/test/mlscript/parser/Class.mls index 287bd74c3c..007cb287ee 100644 --- a/hkmc2/shared/src/test/mlscript/parser/Class.mls +++ b/hkmc2/shared/src/test/mlscript/parser/Class.mls @@ -11,7 +11,7 @@ class class Foo //│ Parsed: -//│ TypeDef(Cls,Ident(Foo),None,None) +//│ TypeDef(Cls,Ident(Foo),None) :pe class Foo extends @@ -19,43 +19,39 @@ class Foo extends //│ ║ l.17: class Foo extends //│ ╙── ^ //│ Parsed: -//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Error()),None,None) +//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Error()),None) class Foo extends Bar //│ Parsed: -//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Ident(Bar)),None,None) +//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Ident(Bar)),None) :pe class Foo extends Bar with -//│ ╔══[PARSE ERROR] Expected block after type declaration body; found end of input instead +//│ ╔══[PARSE ERROR] Expected start of expression in this position; found end of input instead //│ ║ l.29: class Foo extends Bar with //│ ╙── ^ //│ Parsed: -//│ Error() +//│ TypeDef(Cls,InfixApp(InfixApp(Ident(Foo),keyword 'extends',Ident(Bar)),keyword 'with',Error()),None) -:fixme class Foo extends Bar with val x -//│ ╔══[PARSE ERROR] Expected block after type declaration body; found 'val' keyword instead -//│ ║ l.37: class Foo extends Bar with val x -//│ ╙── ^^^ //│ Parsed: -//│ Jux(Error(),Ident(x)) +//│ TypeDef(Cls,InfixApp(InfixApp(Ident(Foo),keyword 'extends',Ident(Bar)),keyword 'with',TermDef(ImmutVal,Ident(x),None)),None) class Foo extends Bar with val x: Int //│ Parsed: -//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Ident(Bar)),None,Some(Block(List(TermDef(ImmutVal,InfixApp(Ident(x),keyword ':',Ident(Int)),None))))) +//│ TypeDef(Cls,InfixApp(InfixApp(Ident(Foo),keyword 'extends',Ident(Bar)),keyword 'with',Block(List(TermDef(ImmutVal,InfixApp(Ident(x),keyword ':',Ident(Int)),None)))),None) class Foo with val x: Int //│ Parsed: -//│ TypeDef(Cls,Ident(Foo),None,Some(Block(List(TermDef(ImmutVal,InfixApp(Ident(x),keyword ':',Ident(Int)),None))))) +//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'with',Block(List(TermDef(ImmutVal,InfixApp(Ident(x),keyword ':',Ident(Int)),None)))),None) :pe with //│ ╔══[PARSE ERROR] Expected start of expression in this position; found 'with' keyword instead -//│ ║ l.56: with +//│ ║ l.52: with //│ ╙── ^^^^ //│ Parsed: //│ Error() @@ -64,31 +60,31 @@ with class Foo //│ Parsed: -//│ TypeDef(Cls,Ident(Foo),None,None) +//│ TypeDef(Cls,Ident(Foo),None) class Foo Bar //│ Parsed: -//│ TypeDef(Cls,Ident(Foo),None,None) -//│ TypeDef(Cls,Ident(Bar),None,None) +//│ TypeDef(Cls,Ident(Foo),None) +//│ TypeDef(Cls,Ident(Bar),None) class Foo extends Bar Bar with x //│ Parsed: -//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Ident(Bar)),None,None) -//│ TypeDef(Cls,Ident(Bar),None,Some(Block(List(Ident(x))))) +//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Ident(Bar)),None) +//│ TypeDef(Cls,InfixApp(Ident(Bar),keyword 'with',Block(List(Ident(x)))),None) :pe class Foo //│ ╔══[PARSE ERROR] Expected expression after type declaration keyword; found new line instead -//│ ║ l.86: class +//│ ║ l.82: class //│ ║ ^ -//│ ║ l.87: Foo +//│ ║ l.83: Foo //│ ╙── //│ Parsed: //│ Error() @@ -99,20 +95,20 @@ class Foo extends Bar //│ ╔══[PARSE ERROR] Expected start of expression in this position; found 'extends' keyword instead -//│ ║ l.100: extends Bar -//│ ╙── ^^^^^^^ +//│ ║ l.96: extends Bar +//│ ╙── ^^^^^^^ //│ ╔══[PARSE ERROR] Expected end of input; found identifier instead -//│ ║ l.100: extends Bar -//│ ╙── ^^^ +//│ ║ l.96: extends Bar +//│ ╙── ^^^ //│ Parsed: -//│ TypeDef(Cls,Ident(Foo),None,None) +//│ TypeDef(Cls,Ident(Foo),None) //│ Error() class Foo extends Bar //│ Parsed: -//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Ident(Bar)),None,None) +//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Ident(Bar)),None) class Foo @@ -120,18 +116,18 @@ class Bar extends Baz //│ Parsed: -//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Ident(Bar)),None,None) -//│ TypeDef(Cls,InfixApp(Ident(Bar),keyword 'extends',Ident(Baz)),None,None) +//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Ident(Bar)),None) +//│ TypeDef(Cls,InfixApp(Ident(Bar),keyword 'extends',Ident(Baz)),None) class Foo extends Bar //│ Parsed: -//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Ident(Bar)),None,None) +//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Ident(Bar)),None) class Foo extends Bar //│ Parsed: -//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Block(List(Ident(Bar)))),None,None) +//│ TypeDef(Cls,InfixApp(Ident(Foo),keyword 'extends',Block(List(Ident(Bar)))),None) diff --git a/hkmc2/shared/src/test/mlscript/parser/Operators.mls b/hkmc2/shared/src/test/mlscript/parser/Operators.mls index 9d1b4371f2..95978d8a0c 100644 --- a/hkmc2/shared/src/test/mlscript/parser/Operators.mls +++ b/hkmc2/shared/src/test/mlscript/parser/Operators.mls @@ -85,7 +85,7 @@ x => x 42 //│ Parsed: -//│ OpApp(IntLit(1),Ident(+),List(Block(List(LetLike(keyword 'let',Ident(x),Some(IntLit(2)),None), TypeDef(Cls,Ident(A),None,None), Ident(x), IntLit(42))))) +//│ OpApp(IntLit(1),Ident(+),List(Block(List(LetLike(keyword 'let',Ident(x),Some(IntLit(2)),None), TypeDef(Cls,Ident(A),None), Ident(x), IntLit(42))))) :pe 1 + diff --git a/hkmc2/shared/src/test/mlscript/parser/Suspension.mls b/hkmc2/shared/src/test/mlscript/parser/Suspension.mls index 9ef2a9874b..cfb3ff4906 100644 --- a/hkmc2/shared/src/test/mlscript/parser/Suspension.mls +++ b/hkmc2/shared/src/test/mlscript/parser/Suspension.mls @@ -43,22 +43,26 @@ module A with //│ Parsed tree: //│ TypeDef: //│ k = Mod -//│ head = Ident of "A" +//│ head = InfixApp: +//│ lhs = Ident of "A" +//│ kw = keyword 'with' +//│ rhs = Block of Ls of +//│ TypeDef: +//│ k = Mod +//│ head = InfixApp: +//│ lhs = Ident of "B" +//│ kw = keyword 'with' +//│ rhs = Block of Ls of +//│ TermDef: +//│ k = ImmutVal +//│ head = Ident of "a" +//│ rhs = S of IntLit of 1 +//│ TermDef: +//│ k = ImmutVal +//│ head = Ident of "b" +//│ rhs = S of IntLit of 2 +//│ rhs = N //│ rhs = N -//│ body = S of Block of Ls of -//│ TypeDef: -//│ k = Mod -//│ head = Ident of "B" -//│ rhs = N -//│ body = S of Block of Ls of -//│ TermDef: -//│ k = ImmutVal -//│ head = Ident of "a" -//│ rhs = S of IntLit of 1 -//│ TermDef: -//│ k = ImmutVal -//│ head = Ident of "b" -//│ rhs = S of IntLit of 2 fun test(x) = @@ -74,11 +78,11 @@ x => 1 let bar = 1 //│ ╔══[WARNING] Pure expression in statement position -//│ ║ l.72: x => +//│ ║ l.76: x => //│ ║ ^^^^ -//│ ║ l.73: if false then 0 else... +//│ ║ l.77: if false then 0 else... //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.74: 1 +//│ ║ l.78: 1 //│ ╙── ^^^ //│ bar = 1 @@ -92,10 +96,10 @@ x => if false then 0 else... 1 let foo = 1 //│ ╔══[ERROR] Illegal position for '...' spread operator. -//│ ║ l.91: x => if false then 0 else... +//│ ║ l.95: x => if false then 0 else... //│ ╙── ^^^ //│ ╔══[WARNING] Pure expression in statement position -//│ ║ l.91: x => if false then 0 else... +//│ ║ l.95: x => if false then 0 else... //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ foo = 1 diff --git a/hkmc2/shared/src/test/mlscript/rp/Future.mls b/hkmc2/shared/src/test/mlscript/rp/Future.mls index 456aeef620..d16fd8cce8 100644 --- a/hkmc2/shared/src/test/mlscript/rp/Future.mls +++ b/hkmc2/shared/src/test/mlscript/rp/Future.mls @@ -110,7 +110,7 @@ if input is Lines of Email then //│ ║ l.108: if input is Lines of Email then //│ ╙── ^ //│ /!!!\ Uncaught error: scala.MatchError: InfixApp(Case(None,Block(List(InfixApp(StrLit(),keyword 'then',Tup(List())), TypeDef(Pat,Ident(Tail),Some(Case(None,Block(List(InfixApp(StrLit(),keyword 'then',Tup(List())), InfixApp(InfixApp(OpApp(StrLit( -//│ ),Ident(~),List(Bra(Round,App(Ident(Lines),Tup(List(Ident(L))))))),keyword 'as',Ident(t)),keyword 'then',Ident(t)))))),None), InfixApp(InfixApp(InfixApp(Ident(L),keyword 'as',OpApp(Ident(h),Ident(~),List(Ident(Tail)))),keyword 'as',Ident(t)),keyword 'then',Tup(List(Ident(h), Spread(keyword '...',Some(Loc(148,151,Future.mls:+100)),Some(Ident(t))))))))),keyword ':',Ident(todo)) (of class hkmc2.syntax.Tree$InfixApp) +//│ ),Ident(~),List(Bra(Round,App(Ident(Lines),Tup(List(Ident(L))))))),keyword 'as',Ident(t)),keyword 'then',Ident(t))))))), InfixApp(InfixApp(InfixApp(Ident(L),keyword 'as',OpApp(Ident(h),Ident(~),List(Ident(Tail)))),keyword 'as',Ident(t)),keyword 'then',Tup(List(Ident(h), Spread(keyword '...',Some(Loc(148,151,Future.mls:+100)),Some(Ident(t))))))))),keyword ':',Ident(todo)) (of class hkmc2.syntax.Tree$InfixApp) :todo pattern Opt(pattern P) = case diff --git a/hkmc2/shared/src/test/mlscript/syntax/AbusiveSuspensions.mls b/hkmc2/shared/src/test/mlscript/syntax/AbusiveSuspensions.mls index a33bcadd0d..8a9fab6c6c 100644 --- a/hkmc2/shared/src/test/mlscript/syntax/AbusiveSuspensions.mls +++ b/hkmc2/shared/src/test/mlscript/syntax/AbusiveSuspensions.mls @@ -39,10 +39,10 @@ fun foo(expr1) = //│ ║ ^ //│ ║ l.29: Error(b) then b //│ ╙── ^^ -//│ ╔══[ERROR] Unexpected infix use of 'then' keyword here +//│ ╔══[ERROR] Unexpected infix use of keyword 'then' here //│ ║ l.29: Error(b) then b //│ ╙── ^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Unexpected infix use of 'then' keyword here +//│ ╔══[ERROR] Unexpected infix use of keyword 'then' here //│ ║ l.30: Ok(a) then... //│ ║ ^^^^^^^^^^^^^ //│ ║ l.31: a diff --git a/hkmc2/shared/src/test/mlscript/syntax/KeywordStutters.mls b/hkmc2/shared/src/test/mlscript/syntax/KeywordStutters.mls index 316765ee14..fe5f216013 100644 --- a/hkmc2/shared/src/test/mlscript/syntax/KeywordStutters.mls +++ b/hkmc2/shared/src/test/mlscript/syntax/KeywordStutters.mls @@ -22,8 +22,8 @@ abstract Bar(b) //│ ┊abstract┊→⟨┊class┊→⟨┊Foo┊(⟨┊a┊⟩)┊↵┊Bar┊(⟨┊b┊⟩)┊⟩←┊⟩←┊ //│ Parsed: -//│ Modified(keyword 'abstract',None,TypeDef(Cls,App(Ident(Foo),Tup(List(Ident(a)))),None,None)) -//│ Modified(keyword 'abstract',None,TypeDef(Cls,App(Ident(Bar),Tup(List(Ident(b)))),None,None)) +//│ Modified(keyword 'abstract',None,TypeDef(Cls,App(Ident(Foo),Tup(List(Ident(a)))),None)) +//│ Modified(keyword 'abstract',None,TypeDef(Cls,App(Ident(Bar),Tup(List(Ident(b)))),None)) :todo abstract class diff --git a/hkmc2/shared/src/test/mlscript/ucs/syntax/IfOpSplit.mls b/hkmc2/shared/src/test/mlscript/ucs/syntax/IfOpSplit.mls index 1b45f43733..721e6dff2c 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/syntax/IfOpSplit.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/syntax/IfOpSplit.mls @@ -38,7 +38,7 @@ if 1 + 2 //│ ╟── Note: the operator split starts here //│ ║ l.27: * 3 then 0 //│ ╙── ^ -//│ ╔══[ERROR] Unexpected infix use of 'then' keyword here +//│ ╔══[ERROR] Unexpected infix use of keyword 'then' here //│ ║ l.26: if 1 + 2 //│ ║ ^ //│ ║ l.27: * 3 then 0 @@ -75,7 +75,7 @@ if 1 + 2 //│ ╟── Note: the operator split starts here //│ ║ l.70: * 3 then 0 //│ ╙── ^ -//│ ╔══[ERROR] Unexpected infix use of 'then' keyword here +//│ ╔══[ERROR] Unexpected infix use of keyword 'then' here //│ ║ l.69: if 1 + 2 //│ ║ ^ //│ ║ l.70: * 3 then 0