From 9c3cea128636174e373c243bdab2d04688054633 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 30 Sep 2025 15:55:24 +0800 Subject: [PATCH 001/268] Add `staged` keyword --- .../scala/hkmc2/semantics/Elaborator.scala | 5 +- .../src/main/scala/hkmc2/syntax/Keyword.scala | 3 +- .../src/main/scala/hkmc2/syntax/Lexer.scala | 3 +- .../main/scala/hkmc2/syntax/ParseRule.scala | 1 + .../src/main/scala/hkmc2/syntax/Tree.scala | 2 + .../src/test/mlscript/staging/Syntax.mls | 160 ++++++++++++++++++ 6 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/staging/Syntax.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index ce66d08ffe..249e8dbac0 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -308,7 +308,7 @@ extends Importer: case _ => N def annot(tree: Tree): Ctxl[Opt[Annot]] = tree match - case Keywrd(kw @ (Keyword.`abstract` | Keyword.`declare` | Keyword.`data`)) => S(Annot.Modifier(kw)) + case Keywrd(kw @ (Keyword.`abstract` | Keyword.`declare` | Keyword.`data` | Keyword.`staged`)) => S(Annot.Modifier(kw)) case _ => term(tree) match case Term.Error => N case trm => @@ -1334,6 +1334,9 @@ extends Importer: end go ctx.withMembers(members).givenIn: + // log(msg"${blk.showDbg}") + // log(msg"${blk.desugStmts.map(_.showDbg).mkString(",")}") + // transform to Annotated here go(blk.desugStmts, Nil, Nil) diff --git a/hkmc2/shared/src/main/scala/hkmc2/syntax/Keyword.scala b/hkmc2/shared/src/main/scala/hkmc2/syntax/Keyword.scala index 6f4e869a56..be17c06c33 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/syntax/Keyword.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/syntax/Keyword.scala @@ -113,6 +113,7 @@ object Keyword: val `abstract` = Keyword("abstract", N, N) val `constructor` = Keyword("constructor", N, N) val `virtual` = Keyword("virtual", N, N) + val `staged` = Keyword("staged", N, N) val `true` = Keyword("true", N, N) val `false` = Keyword("false", N, N) val `public` = Keyword("public", N, N) @@ -168,5 +169,5 @@ object Keyword: type LetLike = `let`.type | `set`.type type Modifier = `in`.type | `out`.type | `mut`.type | `abstract`.type | `declare`.type | `data`.type | `virtual`.type | `override`.type | - `public`.type | `private`.type + `public`.type | `private`.type | `staged`.type diff --git a/hkmc2/shared/src/main/scala/hkmc2/syntax/Lexer.scala b/hkmc2/shared/src/main/scala/hkmc2/syntax/Lexer.scala index ebab5b54b6..8355ed76e8 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/syntax/Lexer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/syntax/Lexer.scala @@ -576,7 +576,8 @@ object Lexer: "undefined", "abstract", "constructor", - "virtual" + "virtual", + "staged" ) private val SEP = "┊" diff --git a/hkmc2/shared/src/main/scala/hkmc2/syntax/ParseRule.scala b/hkmc2/shared/src/main/scala/hkmc2/syntax/ParseRule.scala index 744226371e..5e4ce63b4f 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/syntax/ParseRule.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/syntax/ParseRule.scala @@ -377,6 +377,7 @@ class ParseRules(using State): modified(`public`), modified(`private`), modified(`out`), + modified(`staged`), singleKw(`true`)(BoolLit(true)), singleKw(`false`)(BoolLit(false)), singleKw(`undefined`)(UnitLit(false)), diff --git a/hkmc2/shared/src/main/scala/hkmc2/syntax/Tree.scala b/hkmc2/shared/src/main/scala/hkmc2/syntax/Tree.scala index ea41d2df03..43e359e6b0 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/syntax/Tree.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/syntax/Tree.scala @@ -243,6 +243,8 @@ enum Tree extends AutoLocated: Annotated(kw, s.desugared) case Modified(kw @ Keywrd(Keyword.`abstract`), s) => Annotated(kw, s.desugared) + case Modified(kw @ Keywrd(Keyword.`staged`), s) => + Annotated(kw, s.desugared) case Modified(kw @ Keywrd(Keyword.`mut`), TermDef(ImmutVal, anme, rhs)) => TermDef(MutVal, anme, rhs).withLocOf(this).desugared case _ => m diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls new file mode 100644 index 0000000000..c0baf4c1b3 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -0,0 +1,160 @@ +import "./../../mlscript-compile/Predef.mjs" + +:de +:elt +module A with + fun f(x) = x +//│ Elab block List(TypeDef(Mod,InfixApp(Ident(A),keyword 'with',Block(List(TermDef(Fun,App(Ident(f),Tup(List(Ident[...] LocalScope(block:3) +//│ | Processing module/object definition Ident(A) +//│ | | Companion: None +//│ | | Elab block List(TermDef(Fun,App(Ident(f),Tup(List(Ident(x)))),Some(Ident(x)))) InnerScope(module:A‹537›) +//│ | | | Processing term definition App(Ident(f),Tup(List(Ident(x)))) +//│ | | | Elaborating ParamTree: ParamTree(‹›,Ident(x),None,None,Set()) +//│ | | | Elab term Ident(x) +//│ | | | | Elab subterm Ident(x) +//│ | | | | ~> Ref(x‹539›) +//│ | | | ~> Ref(x‹539›) +//│ | | ~> Blk(List(TermDefinition(Fun,member:f‹535›,module:A‹537›.f,List(ParamList(‹›,List(Param(‹›,x‹539›,None,Modulefulness(None))),None)),None,None,Some(Ref(x‹539›)),‹result of member:f‹535››‹541›,‹›,Modulefulness(None),List(),None)),Lit(UnitLit(false))) +//│ ~> Blk(List(ModuleOrObjectDef(None,module:A‹537›,member:A‹536›,List(),None,List(),None,Mod,{ fun member:f‹535›(x‹539›) = x‹539›#666; },None,List())),Lit(UnitLit(false))) +//│ Elaborated tree: +//│ Blk: +//│ stats = Ls of +//│ ModuleOrObjectDef: +//│ owner = N +//│ sym = module:A‹537› +//│ bsym = member:A‹536› +//│ tparams = Nil +//│ paramsOpt = N +//│ auxParams = Nil +//│ ext = N +//│ kind = Mod +//│ body = ObjBody of Blk: +//│ stats = Ls of +//│ TermDefinition: +//│ k = Fun +//│ sym = member:f‹535› +//│ tsym = module:A‹537›.f +//│ params = Ls of +//│ ParamList: +//│ flags = () +//│ params = Ls of +//│ Param: +//│ flags = () +//│ sym = x‹539› +//│ sign = N +//│ modulefulness = Modulefulness of N +//│ restParam = N +//│ tparams = N +//│ sign = N +//│ body = S of Ref{sym=x‹539›} of x‹539› +//│ resSym = ‹result of member:f‹535››‹541› +//│ flags = () +//│ modulefulness = Modulefulness of N +//│ annotations = Nil +//│ companion = N +//│ res = Lit of UnitLit of false +//│ companion = N +//│ annotations = Nil +//│ res = Lit of UnitLit of false +staged module B with + fun f(x) = x +B.f(1) +//│ Elab block List(Annotated(Keywrd(keyword 'staged'),TypeDef(Mod,InfixApp(Ident(B),keyword 'with',Block(List(Term[...] LocalScope(block:4) +//│ | Processing module/object definition Ident(B) +//│ | | Companion: None +//│ | | Elab block List(TermDef(Fun,App(Ident(f),Tup(List(Ident(x)))),Some(Ident(x)))) InnerScope(module:B‹545›) +//│ | | | Processing term definition App(Ident(f),Tup(List(Ident(x)))) +//│ | | | Elaborating ParamTree: ParamTree(‹›,Ident(x),None,None,Set()) +//│ | | | Elab term Ident(x) +//│ | | | | Elab subterm Ident(x) +//│ | | | | ~> Ref(x‹547›) +//│ | | | ~> Ref(x‹547›) +//│ | | ~> Blk(List(TermDefinition(Fun,member:f‹543›,module:B‹545›.f,List(ParamList(‹›,List(Param(‹›,x‹547›,None,Modulefulness(None))),None)),None,None,Some(Ref(x‹547›)),‹result of member:f‹543››‹549›,‹›,Modulefulness(None),List(),None)),Lit(UnitLit(false))) +//│ | Elab term App(Sel(Ident(B),Ident(f)),Tup(List(IntLit(1)))) +//│ | | Elab subterm App(Sel(Ident(B),Ident(f)),Tup(List(IntLit(1)))) +//│ | | | Elab subterm Sel(Ident(B),Ident(f)) +//│ | | | | Elab subterm Ident(B) +//│ | | | | ~> Ref(member:B‹544›) +//│ | | | ~> Sel(Ref(member:B‹544›),Ident(f)) +//│ | | | Elab subterm Tup(List(IntLit(1))) +//│ | | | | Elab term IntLit(1) +//│ | | | | | Elab subterm IntLit(1) +//│ | | | | | ~> Lit(IntLit(1)) +//│ | | | | ~> Lit(IntLit(1)) +//│ | | | ~> Tup(List(Fld(‹›,Lit(IntLit(1)),None))) +//│ | | ~> App(Sel(Ref(member:B‹544›),Ident(f)),Tup(List(Fld(‹›,Lit(IntLit(1)),None)))) +//│ | ~> App(Sel(Ref(member:B‹544›),Ident(f)),Tup(List(Fld(‹›,Lit(IntLit(1)),None)))) +//│ ~> Blk(List(ModuleOrObjectDef(None,module:B‹545›,member:B‹544›,List(),None,List(),None,Mod,{ fun member:f‹543›(x‹547›) = x‹547›#666; },None,List(Modifier(keyword 'staged')))),App(Sel(Ref(member:B‹544›),Ident(f)),Tup(List(Fld(‹›,Lit(IntLit(1)),None))))) +//│ Elaborated tree: +//│ Blk: +//│ stats = Ls of +//│ ModuleOrObjectDef: +//│ owner = N +//│ sym = module:B‹545› +//│ bsym = member:B‹544› +//│ tparams = Nil +//│ paramsOpt = N +//│ auxParams = Nil +//│ ext = N +//│ kind = Mod +//│ body = ObjBody of Blk: +//│ stats = Ls of +//│ TermDefinition: +//│ k = Fun +//│ sym = member:f‹543› +//│ tsym = module:B‹545›.f +//│ params = Ls of +//│ ParamList: +//│ flags = () +//│ params = Ls of +//│ Param: +//│ flags = () +//│ sym = x‹547› +//│ sign = N +//│ modulefulness = Modulefulness of N +//│ restParam = N +//│ tparams = N +//│ sign = N +//│ body = S of Ref{sym=x‹547›} of x‹547› +//│ resSym = ‹result of member:f‹543››‹549› +//│ flags = () +//│ modulefulness = Modulefulness of N +//│ annotations = Nil +//│ companion = N +//│ res = Lit of UnitLit of false +//│ companion = N +//│ annotations = Ls of +//│ Modifier of keyword 'staged' +//│ res = App: +//│ lhs = Sel{sym=member:f‹543›}: +//│ prefix = Ref{sym=member:B‹544›} of member:B‹544› +//│ nme = Ident of "f" +//│ rhs = Tup of Ls of +//│ Fld: +//│ flags = () +//│ term = Lit of IntLit of 1 +//│ asc = N + +// should reject these annotations +:de +// :pe +staged object Foo +//│ Elab block List(Annotated(Keywrd(keyword 'staged'),TypeDef(Obj,Ident(Foo),None))) LocalScope(block:5) +//│ | Processing module/object definition Ident(Foo) +//│ | | Companion: None +//│ ~> Blk(List(ModuleOrObjectDef(None,object:Foo‹553›,member:Foo‹552›,List(),None,List(),None,Obj,{ },None,List(Modifier(keyword 'staged')))),Lit(UnitLit(false))) + +:de +:pe +// staged class Foo + +:de +// :pe +staged fun f() = 0 +//│ Elab block List(Annotated(Keywrd(keyword 'staged'),TermDef(Fun,App(Ident(f),Tup(List())),Some(IntLit(0))))) LocalScope(block:6) +//│ | Processing term definition App(Ident(f),Tup(List())) +//│ | Elab term IntLit(0) +//│ | | Elab subterm IntLit(0) +//│ | | ~> Lit(IntLit(0)) +//│ | ~> Lit(IntLit(0)) +//│ ~> Blk(List(TermDefinition(Fun,member:f‹555›,.f,List(ParamList(‹›,List(),None)),None,None,Some(Lit(IntLit(0))),‹result of member:f‹555››‹557›,‹›,Modulefulness(None),List(Modifier(keyword 'staged')),None)),Lit(UnitLit(false))) From 2711dd985927d2a31f9dc33ca53d1ddf7bfe0f46 Mon Sep 17 00:00:00 2001 From: TYeung Date: Tue, 30 Sep 2025 16:49:38 +0800 Subject: [PATCH 002/268] remove comments --- hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index 249e8dbac0..facf91b308 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -1334,11 +1334,8 @@ extends Importer: end go ctx.withMembers(members).givenIn: - // log(msg"${blk.showDbg}") - // log(msg"${blk.desugStmts.map(_.showDbg).mkString(",")}") - // transform to Annotated here go(blk.desugStmts, Nil, Nil) - + def mkBlk(acc: Ls[Statement], res: Opt[Term], hasResult: Bool): Blk | Rcd = // TODO forbid certain kinds of terms in records From 7edc9b64233bc0167ca7225168a9b1590edd112c Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 5 Oct 2025 00:11:37 +0800 Subject: [PATCH 003/268] draft out Block.mls --- .../src/test/mlscript-compile/Block.mls | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 hkmc2/shared/src/test/mlscript-compile/Block.mls diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls new file mode 100644 index 0000000000..d5c4bbaa8d --- /dev/null +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -0,0 +1,124 @@ +import "./Predef.mls" +import "./Option.mls" +import "./Term.mls" + +open Predef +open Option + +type Opt[A] = Option[A] +type Ls[A] = List[A] + +// dependancies referenced in Block classes +class List[A] with + class Cons[A](head: A, tail: List[A]) + object Nil +// copying Tree.Ident => Str in Term.mls +class Ident(name: Str) // translation of Tree.Ident +class VarSymbol(id: Ident) +type Local = Symbol +// should these be replaced with just Symbol? +type FieldSymbol = Symbol +type ClassSymbol = Symbol +type ClassLikeSymbol = Symbol +type TermSymbol = Symbol +type InnerSymbol = Symbol +type BlockMemberSymbol = Symbol +type ModuleOrObjectSymbol = Symbol +type MemberSymbol = Symbol + +type Literal = null | undefined | Str | Int | Num | Bool +class Arg(spread: Opt[Bool], value: Path) + +class ClsLikeKind(desc: Str) +class ParamListFlags(ctx: Bool) +class FldFlags(_mut: Bool, spec: Bool, pat: Bool, isVal: Bool) +class Modulefulness(msym: Opt[ModuleOrObjectSymbol]) +class Param(flags: FldFlags, sym: VarSymbol, sign: Opt[Term.Term], modulefulness: Modulefulness) +class ParamList(flags: ParamListFlags, params: Ls[Param], restParam: Opt[Param]) +// class Handler( +// sym: BlockMemberSymbol, +// resumeSym: VarSymbol, +// params: Ls[ParamList], +// body: Block, +// ) + +class Path with + class Select(qual: Path, name: Ident)(symcol: Opt[FieldSymbol]) + class Value with + constructor + Ref(l: Local) + Lit(lit: Literal) + // TODO Tup + +class Case with + constructor + CaseLit(lit: Literal) + Cls(cls: ClassLikeSymbol, path: Path) + Tup(len: Int, inf: Bool) + Field(name: Ident, safe: Bool) + +class Result with + constructor + TrivialResult + Call(_fun: Path, args: Ls[Arg])(isMlsFun: Bool, mayRaiseEffects: Bool) + Instantiate(_mut: Bool, cls: Path, args: Ls[Arg]) // may assume immutable + Tuple(_mut: Bool, elems: Ls[Arg]) // may assume immutable + +class Defn with + class ValDefn( + tsym: TermSymbol, + sym: BlockMemberSymbol, + rhs: Path + ) with + val innerSym = Some(tsym) + val owner: Opt[InnerSymbol] = tsym.owner + class ClsLikeDefn( + owner: Opt[InnerSymbol], + isym: MemberSymbol & InnerSymbol, + sym: BlockMemberSymbol, + k: ClsLikeKind, + paramsOpt: Opt[ParamList], + auxParams: Ls[ParamList], + parentPath: Opt[Path], + methods: Ls[FunDefn], + privateFields: Ls[TermSymbol], + publicFields: Ls[BlockMemberSymbol -> TermSymbol], + preCtor: Block, + ctor: Block, + companion: Opt[ClsLikeBody], + ) with + val innerSym = Some(isym) + class FunDefn( + owner: Opt[InnerSymbol], + sym: BlockMemberSymbol, + params: Ls[ParamList], + body: Block, + ) with + val innerSym = None + +// this is needed to convert the non-type selection to a type +type FunDefn = Defn.FunDefn + +class ClsLikeBody( + isym: MemberSymbol & InnerSymbol, + methods: Ls[FunDefn], + privateFields: Ls[TermSymbol], + publicFields: Ls[BlockMemberSymbol -> TermSymbol], + ctor: Block, +) + +class Block with + class Match(scrut: Path, arms: Ls[Case -> Block], dflt: Opt[Block], rest: Block) + class Return(res: Result, implct: Bool) + class Label(lavel: Local, body: Block, rest: Block) + class Define(defn: Defn, rest: Block) + // class HandleBlock( + // lhs: Local, + // rhs: Local, + // par: Path, + // args: Ls[Path], + // cls: ClassSymbol, + // handlers: Ls[Handler], + // body: Block, + // rest: Block, + // ) From becf900ab02e7cb47b7af84edc2d1310160774b4 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 22 Oct 2025 13:17:11 +0800 Subject: [PATCH 004/268] switch from List to Array --- .../src/test/mlscript-compile/Block.mls | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index d5c4bbaa8d..f54c4b8660 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -5,13 +5,12 @@ import "./Term.mls" open Predef open Option +module Block with... + type Opt[A] = Option[A] -type Ls[A] = List[A] // dependancies referenced in Block classes -class List[A] with - class Cons[A](head: A, tail: List[A]) - object Nil + // copying Tree.Ident => Str in Term.mls class Ident(name: Str) // translation of Tree.Ident class VarSymbol(id: Ident) @@ -34,11 +33,11 @@ class ParamListFlags(ctx: Bool) class FldFlags(_mut: Bool, spec: Bool, pat: Bool, isVal: Bool) class Modulefulness(msym: Opt[ModuleOrObjectSymbol]) class Param(flags: FldFlags, sym: VarSymbol, sign: Opt[Term.Term], modulefulness: Modulefulness) -class ParamList(flags: ParamListFlags, params: Ls[Param], restParam: Opt[Param]) +class ParamList(flags: ParamListFlags, params: Array[Param], restParam: Opt[Param]) // class Handler( // sym: BlockMemberSymbol, // resumeSym: VarSymbol, -// params: Ls[ParamList], +// params: Array[ParamList], // body: Block, // ) @@ -60,9 +59,9 @@ class Case with class Result with constructor TrivialResult - Call(_fun: Path, args: Ls[Arg])(isMlsFun: Bool, mayRaiseEffects: Bool) - Instantiate(_mut: Bool, cls: Path, args: Ls[Arg]) // may assume immutable - Tuple(_mut: Bool, elems: Ls[Arg]) // may assume immutable + Call(_fun: Path, args: Array[Arg])(isMlsFun: Bool, mayRaiseEffects: Bool) + Instantiate(_mut: Bool, cls: Path, args: Array[Arg]) // may assume immutable + Tuple(_mut: Bool, elems: Array[Arg]) // may assume immutable class Defn with class ValDefn( @@ -78,11 +77,11 @@ class Defn with sym: BlockMemberSymbol, k: ClsLikeKind, paramsOpt: Opt[ParamList], - auxParams: Ls[ParamList], + auxParams: Array[ParamList], parentPath: Opt[Path], - methods: Ls[FunDefn], - privateFields: Ls[TermSymbol], - publicFields: Ls[BlockMemberSymbol -> TermSymbol], + methods: Array[FunDefn], + privateFields: Array[TermSymbol], + publicFields: Array[BlockMemberSymbol -> TermSymbol], preCtor: Block, ctor: Block, companion: Opt[ClsLikeBody], @@ -91,7 +90,7 @@ class Defn with class FunDefn( owner: Opt[InnerSymbol], sym: BlockMemberSymbol, - params: Ls[ParamList], + params: Array[ParamList], body: Block, ) with val innerSym = None @@ -101,14 +100,14 @@ type FunDefn = Defn.FunDefn class ClsLikeBody( isym: MemberSymbol & InnerSymbol, - methods: Ls[FunDefn], - privateFields: Ls[TermSymbol], - publicFields: Ls[BlockMemberSymbol -> TermSymbol], + methods: Array[FunDefn], + privateFields: Array[TermSymbol], + publicFields: Array[BlockMemberSymbol -> TermSymbol], ctor: Block, ) class Block with - class Match(scrut: Path, arms: Ls[Case -> Block], dflt: Opt[Block], rest: Block) + class Match(scrut: Path, arms: Array[Case -> Block], dflt: Opt[Block], rest: Block) class Return(res: Result, implct: Bool) class Label(lavel: Local, body: Block, rest: Block) class Define(defn: Defn, rest: Block) @@ -116,9 +115,9 @@ class Block with // lhs: Local, // rhs: Local, // par: Path, - // args: Ls[Path], + // args: Array[Path], // cls: ClassSymbol, - // handlers: Ls[Handler], + // handlers: Array[Handler], // body: Block, // rest: Block, // ) From acc97a2711e8ac3adc981fa474d568411a0304ce Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 22 Oct 2025 13:27:04 +0800 Subject: [PATCH 005/268] make constructor fields public --- .../src/test/mlscript-compile/Block.mls | 145 ++++++++---------- 1 file changed, 65 insertions(+), 80 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index f54c4b8660..97e06bd44f 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -12,8 +12,8 @@ type Opt[A] = Option[A] // dependancies referenced in Block classes // copying Tree.Ident => Str in Term.mls -class Ident(name: Str) // translation of Tree.Ident -class VarSymbol(id: Ident) +class Ident(val name: Str) // translation of Tree.Ident +class VarSymbol(val id: Ident) type Local = Symbol // should these be replaced with just Symbol? type FieldSymbol = Symbol @@ -26,98 +26,83 @@ type ModuleOrObjectSymbol = Symbol type MemberSymbol = Symbol type Literal = null | undefined | Str | Int | Num | Bool -class Arg(spread: Opt[Bool], value: Path) +class Arg(val spread: Opt[Bool], val value: Path) -class ClsLikeKind(desc: Str) -class ParamListFlags(ctx: Bool) -class FldFlags(_mut: Bool, spec: Bool, pat: Bool, isVal: Bool) -class Modulefulness(msym: Opt[ModuleOrObjectSymbol]) -class Param(flags: FldFlags, sym: VarSymbol, sign: Opt[Term.Term], modulefulness: Modulefulness) -class ParamList(flags: ParamListFlags, params: Array[Param], restParam: Opt[Param]) -// class Handler( -// sym: BlockMemberSymbol, -// resumeSym: VarSymbol, -// params: Array[ParamList], -// body: Block, -// ) +class ClsLikeKind(val desc: Str) +class ParamListFlags(val ctx: Bool) +class FldFlags(val _mut: Bool, val spec: Bool, val pat: Bool, val isVal: Bool) +class Modulefulness(val msym: Opt[ModuleOrObjectSymbol]) +class Param(val flags: FldFlags, val sym: VarSymbol, val sign: Opt[Term.Term], val modulefulness: Modulefulness) +class ParamList(val flags: ParamListFlags, val params: Array[Param], val restParam: Opt[Param]) + +// Defined Classes for Block class Path with - class Select(qual: Path, name: Ident)(symcol: Opt[FieldSymbol]) - class Value with - constructor - Ref(l: Local) - Lit(lit: Literal) + constructor + Select(val qual: Path, val name: Ident)(symcol: Opt[FieldSymbol]) + ValueRef(val l: Local) + ValueLit(val lit: Literal) // TODO Tup class Case with constructor - CaseLit(lit: Literal) - Cls(cls: ClassLikeSymbol, path: Path) - Tup(len: Int, inf: Bool) - Field(name: Ident, safe: Bool) + CaseLit(val lit: Literal) + Cls(val cls: ClassLikeSymbol, val path: Path) + Tup(val len: Int, val inf: Bool) + Field(val name: Ident, val safe: Bool) class Result with constructor - TrivialResult - Call(_fun: Path, args: Array[Arg])(isMlsFun: Bool, mayRaiseEffects: Bool) - Instantiate(_mut: Bool, cls: Path, args: Array[Arg]) // may assume immutable - Tuple(_mut: Bool, elems: Array[Arg]) // may assume immutable +TrivialResult(val path: Path) // only Path extends TrivialResult + Call(val _fun: Path, val args: Array[Arg])(isMlsFun: Bool, mayRaiseEffects: Bool) + Instantiate(val _mut: Bool, val cls: Path, val args: Array[Arg]) // may assume immutable + Tuple(val _mut: Bool, val elems: Array[Arg]) // may assume immutable +// moved owner and innerSym into the argument to comply with `constructor` syntax class Defn with - class ValDefn( - tsym: TermSymbol, - sym: BlockMemberSymbol, - rhs: Path - ) with - val innerSym = Some(tsym) - val owner: Opt[InnerSymbol] = tsym.owner - class ClsLikeDefn( - owner: Opt[InnerSymbol], - isym: MemberSymbol & InnerSymbol, - sym: BlockMemberSymbol, - k: ClsLikeKind, - paramsOpt: Opt[ParamList], - auxParams: Array[ParamList], - parentPath: Opt[Path], - methods: Array[FunDefn], - privateFields: Array[TermSymbol], - publicFields: Array[BlockMemberSymbol -> TermSymbol], - preCtor: Block, - ctor: Block, - companion: Opt[ClsLikeBody], - ) with - val innerSym = Some(isym) - class FunDefn( - owner: Opt[InnerSymbol], - sym: BlockMemberSymbol, - params: Array[ParamList], - body: Block, - ) with - val innerSym = None - -// this is needed to convert the non-type selection to a type -type FunDefn = Defn.FunDefn + constructor + ValDefn( + val tsym: TermSymbol, + val sym: BlockMemberSymbol, + val rhs: Path, + val innerSym: Symbol = Some(tsym), + val owner: Opt[InnerSymbol] = tsym.owner, + ) + ClsLikeDefn( + val owner: Opt[InnerSymbol], + val isym: MemberSymbol & InnerSymbol, + val sym: BlockMemberSymbol, + val k: ClsLikeKind, + val paramsOpt: Opt[ParamList], + val auxParams: Array[ParamList], + val parentPath: Opt[Path], + val methods: Array[FunDefn], + val privateFields: Array[TermSymbol], + val publicFields: Array[BlockMemberSymbol -> TermSymbol], + val preCtor: Block, + val ctor: Block, + val companion: Opt[ClsLikeBody], + val innerSym: Symbol = Some(isym), + ) + FunDefn( + val owner: Opt[InnerSymbol], + val sym: BlockMemberSymbol, + val params: Array[ParamList], + val body: Block, + val innerSym: Symbol = None, + ) class ClsLikeBody( - isym: MemberSymbol & InnerSymbol, - methods: Array[FunDefn], - privateFields: Array[TermSymbol], - publicFields: Array[BlockMemberSymbol -> TermSymbol], - ctor: Block, + val isym: MemberSymbol & InnerSymbol, + val methods: Array[FunDefn], + val privateFields: Array[TermSymbol], + val publicFields: Array[BlockMemberSymbol -> TermSymbol], + val ctor: Block, ) class Block with - class Match(scrut: Path, arms: Array[Case -> Block], dflt: Opt[Block], rest: Block) - class Return(res: Result, implct: Bool) - class Label(lavel: Local, body: Block, rest: Block) - class Define(defn: Defn, rest: Block) - // class HandleBlock( - // lhs: Local, - // rhs: Local, - // par: Path, - // args: Array[Path], - // cls: ClassSymbol, - // handlers: Array[Handler], - // body: Block, - // rest: Block, - // ) + constructor +Match(val scrut: Path, val arms: Array[Case -> Block], val dflt: Opt[Block], val rest: Block) + Return(val res: Result, val implct: Bool) + Label(val lavel: Local, val body: Block, val rest: Block) + Define(val defn: Defn, val rest: Block) From c337fb37890c38774c5ad38bf709da85e20f1fb6 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 22 Oct 2025 13:37:40 +0800 Subject: [PATCH 006/268] remove type alias for Symbol --- .../src/test/mlscript-compile/Block.mls | 46 ++++++++----------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 97e06bd44f..7fe69ac278 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -14,16 +14,6 @@ type Opt[A] = Option[A] // copying Tree.Ident => Str in Term.mls class Ident(val name: Str) // translation of Tree.Ident class VarSymbol(val id: Ident) -type Local = Symbol -// should these be replaced with just Symbol? -type FieldSymbol = Symbol -type ClassSymbol = Symbol -type ClassLikeSymbol = Symbol -type TermSymbol = Symbol -type InnerSymbol = Symbol -type BlockMemberSymbol = Symbol -type ModuleOrObjectSymbol = Symbol -type MemberSymbol = Symbol type Literal = null | undefined | Str | Int | Num | Bool class Arg(val spread: Opt[Bool], val value: Path) @@ -31,7 +21,7 @@ class Arg(val spread: Opt[Bool], val value: Path) class ClsLikeKind(val desc: Str) class ParamListFlags(val ctx: Bool) class FldFlags(val _mut: Bool, val spec: Bool, val pat: Bool, val isVal: Bool) -class Modulefulness(val msym: Opt[ModuleOrObjectSymbol]) +class Modulefulness(val msym: Opt[Symbol]) class Param(val flags: FldFlags, val sym: VarSymbol, val sign: Opt[Term.Term], val modulefulness: Modulefulness) class ParamList(val flags: ParamListFlags, val params: Array[Param], val restParam: Opt[Param]) @@ -39,15 +29,15 @@ class ParamList(val flags: ParamListFlags, val params: Array[Param], val restPar class Path with constructor - Select(val qual: Path, val name: Ident)(symcol: Opt[FieldSymbol]) - ValueRef(val l: Local) + Select(val qual: Path, val name: Ident)(symcol: Opt[Symbol]) + ValueRef(val l: Symbol) ValueLit(val lit: Literal) // TODO Tup class Case with constructor CaseLit(val lit: Literal) - Cls(val cls: ClassLikeSymbol, val path: Path) + Cls(val cls: Symbol, val path: Path) Tup(val len: Int, val inf: Bool) Field(val name: Ident, val safe: Bool) @@ -62,41 +52,41 @@ TrivialResult(val path: Path) // only Path extends TrivialResult class Defn with constructor ValDefn( - val tsym: TermSymbol, - val sym: BlockMemberSymbol, + val tsym: Symbol, + val sym: Symbol, val rhs: Path, val innerSym: Symbol = Some(tsym), - val owner: Opt[InnerSymbol] = tsym.owner, + val owner: Opt[Symbol] = tsym.owner, ) ClsLikeDefn( - val owner: Opt[InnerSymbol], - val isym: MemberSymbol & InnerSymbol, - val sym: BlockMemberSymbol, + val owner: Opt[Symbol], + val isym: Symbol, + val sym: Symbol, val k: ClsLikeKind, val paramsOpt: Opt[ParamList], val auxParams: Array[ParamList], val parentPath: Opt[Path], val methods: Array[FunDefn], - val privateFields: Array[TermSymbol], - val publicFields: Array[BlockMemberSymbol -> TermSymbol], + val privateFields: Array[Symbol], + val publicFields: Array[Symbol -> Symbol], val preCtor: Block, val ctor: Block, val companion: Opt[ClsLikeBody], val innerSym: Symbol = Some(isym), ) FunDefn( - val owner: Opt[InnerSymbol], - val sym: BlockMemberSymbol, + val owner: Opt[Symbol], + val sym: Symbol, val params: Array[ParamList], val body: Block, val innerSym: Symbol = None, ) class ClsLikeBody( - val isym: MemberSymbol & InnerSymbol, + val isym: Symbol, val methods: Array[FunDefn], - val privateFields: Array[TermSymbol], - val publicFields: Array[BlockMemberSymbol -> TermSymbol], + val privateFields: Array[Symbol], + val publicFields: Array[Symbol -> Symbol], val ctor: Block, ) @@ -104,5 +94,5 @@ class Block with constructor Match(val scrut: Path, val arms: Array[Case -> Block], val dflt: Opt[Block], val rest: Block) Return(val res: Result, val implct: Bool) - Label(val lavel: Local, val body: Block, val rest: Block) + Label(val lavel: Symbol, val body: Block, val rest: Block) Define(val defn: Defn, val rest: Block) From 03e24d648ed55abd232adbd116021383e5c3d5de Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 22 Oct 2025 13:40:01 +0800 Subject: [PATCH 007/268] fix whitespace issues --- .../shared/src/test/mlscript-compile/Block.mls | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 7fe69ac278..8e9e2a9838 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -28,11 +28,11 @@ class ParamList(val flags: ParamListFlags, val params: Array[Param], val restPar // Defined Classes for Block class Path with - constructor - Select(val qual: Path, val name: Ident)(symcol: Opt[Symbol]) + constructor + Select(val qual: Path, val name: Ident)(symcol: Opt[Symbol]) ValueRef(val l: Symbol) - ValueLit(val lit: Literal) - // TODO Tup + ValueLit(val lit: Literal) + // TODO Tup class Case with constructor @@ -43,7 +43,7 @@ class Case with class Result with constructor -TrivialResult(val path: Path) // only Path extends TrivialResult + TrivialResult(val path: Path) // only Path extends TrivialResult Call(val _fun: Path, val args: Array[Arg])(isMlsFun: Bool, mayRaiseEffects: Bool) Instantiate(val _mut: Bool, val cls: Path, val args: Array[Arg]) // may assume immutable Tuple(val _mut: Bool, val elems: Array[Arg]) // may assume immutable @@ -92,7 +92,7 @@ class ClsLikeBody( class Block with constructor -Match(val scrut: Path, val arms: Array[Case -> Block], val dflt: Opt[Block], val rest: Block) - Return(val res: Result, val implct: Bool) - Label(val lavel: Symbol, val body: Block, val rest: Block) - Define(val defn: Defn, val rest: Block) + Match(val scrut: Path, val arms: Array[Case -> Block], val dflt: Opt[Block], val rest: Block) + Return(val res: Result, val implct: Bool) + Label(val lavel: Symbol, val body: Block, val rest: Block) + Define(val defn: Defn, val rest: Block) From 866d68c86ad0dd9564c257a53e3d9aafc0505c2a Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 23 Oct 2025 21:36:59 +0800 Subject: [PATCH 008/268] simplify ParamList representation --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 8e9e2a9838..0bd2af04b3 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -13,23 +13,21 @@ type Opt[A] = Option[A] // copying Tree.Ident => Str in Term.mls class Ident(val name: Str) // translation of Tree.Ident +class Symbol(val name: Str) class VarSymbol(val id: Ident) type Literal = null | undefined | Str | Int | Num | Bool class Arg(val spread: Opt[Bool], val value: Path) class ClsLikeKind(val desc: Str) -class ParamListFlags(val ctx: Bool) -class FldFlags(val _mut: Bool, val spec: Bool, val pat: Bool, val isVal: Bool) -class Modulefulness(val msym: Opt[Symbol]) -class Param(val flags: FldFlags, val sym: VarSymbol, val sign: Opt[Term.Term], val modulefulness: Modulefulness) -class ParamList(val flags: ParamListFlags, val params: Array[Param], val restParam: Opt[Param]) +// copying ParamList => Array[Symbol] in Term.mls +type ParamList = Array[Symbol] // Defined Classes for Block class Path with constructor - Select(val qual: Path, val name: Ident)(symcol: Opt[Symbol]) + Select(val qual: Path, val name: Ident)(symcol: Opt[Symbol]) // extra term unnecessary? ValueRef(val l: Symbol) ValueLit(val lit: Literal) // TODO Tup From abbb517a322dd0cfdb34b14e23090c8450c1a749 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 28 Oct 2025 23:12:26 +0800 Subject: [PATCH 009/268] add more constructors to Block.mls --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 0bd2af04b3..9d9e7c6042 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -28,13 +28,14 @@ type ParamList = Array[Symbol] class Path with constructor Select(val qual: Path, val name: Ident)(symcol: Opt[Symbol]) // extra term unnecessary? + DynSelect(val qual: Path, val fld: Path, arrayIdx: Bool) ValueRef(val l: Symbol) ValueLit(val lit: Literal) // TODO Tup class Case with constructor - CaseLit(val lit: Literal) + Lit(val lit: Literal) Cls(val cls: Symbol, val path: Path) Tup(val len: Int, val inf: Bool) Field(val name: Ident, val safe: Bool) @@ -92,5 +93,7 @@ class Block with constructor Match(val scrut: Path, val arms: Array[Case -> Block], val dflt: Opt[Block], val rest: Block) Return(val res: Result, val implct: Bool) - Label(val lavel: Symbol, val body: Block, val rest: Block) + Assign(val lhs: Symbol, val rhs: Result, val rest: Block) + Label(val lavel: Symbol, val body: Block, val rest: Block) // unused? Define(val defn: Defn, val rest: Block) + End() From 5c275d294aa1bacbcf6a276dec8ad8f2fc532faf Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 28 Oct 2025 23:13:05 +0800 Subject: [PATCH 010/268] remove unnecessary fields --- .../src/test/mlscript-compile/Block.mls | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 9d9e7c6042..57b674e27e 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -19,7 +19,7 @@ class VarSymbol(val id: Ident) type Literal = null | undefined | Str | Int | Num | Bool class Arg(val spread: Opt[Bool], val value: Path) -class ClsLikeKind(val desc: Str) +// class ClsLikeKind(val desc: Str) // copying ParamList => Array[Symbol] in Term.mls type ParamList = Array[Symbol] @@ -51,42 +51,42 @@ class Result with class Defn with constructor ValDefn( - val tsym: Symbol, + // val tsym: Symbol, val sym: Symbol, val rhs: Path, - val innerSym: Symbol = Some(tsym), - val owner: Opt[Symbol] = tsym.owner, + // val innerSym: Symbol = Some(tsym), + // val owner: Opt[Symbol] = tsym.owner, ) ClsLikeDefn( - val owner: Opt[Symbol], - val isym: Symbol, + // val owner: Opt[Symbol], + // val isym: Symbol, val sym: Symbol, - val k: ClsLikeKind, + // val k: ClsLikeKind, val paramsOpt: Opt[ParamList], - val auxParams: Array[ParamList], - val parentPath: Opt[Path], - val methods: Array[FunDefn], - val privateFields: Array[Symbol], - val publicFields: Array[Symbol -> Symbol], - val preCtor: Block, - val ctor: Block, + // val auxParams: Array[ParamList], + // val parentPath: Opt[Path], + // val methods: Array[FunDefn], + // val privateFields: Array[Symbol], + // val publicFields: Array[Symbol -> Symbol], + // val preCtor: Block, + // val ctor: Block, val companion: Opt[ClsLikeBody], - val innerSym: Symbol = Some(isym), + // val innerSym: Symbol = Some(isym), ) FunDefn( - val owner: Opt[Symbol], + // val owner: Opt[Symbol], val sym: Symbol, val params: Array[ParamList], val body: Block, - val innerSym: Symbol = None, + // val innerSym: Symbol = None, ) class ClsLikeBody( val isym: Symbol, val methods: Array[FunDefn], - val privateFields: Array[Symbol], + // val privateFields: Array[Symbol], val publicFields: Array[Symbol -> Symbol], - val ctor: Block, + // val ctor: Block, ) class Block with From 539bca3457942a03f5309e1c173f3c2440da6110 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 30 Oct 2025 00:03:54 +0800 Subject: [PATCH 011/268] Instrumentation progress following formalization --- .../scala/hkmc2/codegen/Instrumentation.scala | 217 ++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala new file mode 100644 index 0000000000..f3b1dd29dd --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -0,0 +1,217 @@ +package hkmc2 +package codegen + +import mlscript.utils.*, shorthands.* + +import semantics.* +import semantics.Elaborator.State + +import syntax.{Literal, Tree} + +enum Shape: + case Dyn + case Lit(l: Literal) + case Arr(length: Int, shapes: Ls[Shape]) + case Class(c: Symbol, shapes: Ls[Shape]) + case Unit + +import Shape.{Dyn, Lit => SLit, Arr => SArr, Class => SClass, Unit} + +// TODO: use FlatPattern instead? +enum Pattern: + case Lit(l: Literal) + case Class(c: Symbol) + case Arr(len: Int) + case Wildcard + +import Pattern.{Lit => PLit, Class => PClass, Arr => PArr, Wildcard} + +def isPrimitiveTypeOf(c: Symbol, l: SLit) = ??? + +def mrg2(s1: Shape, s2: Shape): Shape = (s1, s2) match + case (s1, s2) if s1 == s2 => s1 + case (l: SLit, s@SClass(c, _)) if isPrimitiveTypeOf(c, l) => s + case (SClass(c1, s1), SClass(c2, s2)) if c1 == c2 => + SClass(c1, s1 zip s2 map mrg2) + case (SArr(l1, s1), SArr(l2, s2)) if l1 == l2 => + SArr(l1, s1 zip s2 map mrg2) + case _ => Dyn + +def mrg(shapes: Ls[Shape]): Shape = + shapes.reduceRight(mrg2) + +def canMatch(s: Shape, p: Pattern): Opt[Bool] = (s, p) match + case (_, Wildcard) => Some(true) + case (SLit(l1), PLit(l2)) if l1 == l2 => S(true) + case (l: SLit, PClass(c)) if isPrimitiveTypeOf(c, l) => S(true) + case (SClass(c1, _), PClass(c2)) if c1 == c2 => S(true) + case (SArr(n1, s), PArr(n2)) if n1 == n2 => S(true) + case (Dyn, _) => None + case _ => Some(false) + +type BlockRet = (Block => Block, Shape, Value) +class Instrumentation(using State): + // use TempSymbol? + lazy val block = new BlockMemberSymbol("Block", Nil) + lazy val shape = new BlockMemberSymbol("Shape", Nil) + + def toArg(x: Path | Local): Arg = + x match + case p: Path => Arg(N, p) + case l: Local => Arg(N, Value.Ref(l)) + + // null and undefined are missing + def toValue(lit: Str | BigInt | BigDecimal | Bool): Value = + val l = lit match + case i: BigInt => Tree.IntLit(i) + case b: Bool => Tree.BoolLit(b) + case s: Str => Tree.StrLit(s) + case n: BigDecimal => Tree.DecLit(n) + Value.Lit(l) + + // continuation-passing style allows symbols defined in current function to be referenced later + + def assign(res: Result)(k: Local => BlockRet): BlockRet = + val tmp = new TempSymbol(N, "tmp") + val (rest, shape, value) = k(tmp) + (b => Assign(tmp, res, rest(b)), shape, value) + def assign2(res: Result)(k: Local => Block): Block = + val tmp = new TempSymbol(N, "tmp") + Assign(tmp, res, k(tmp)) + + // helper for staging the constructors in Block.scala to Block.mls + // automatically convert Ls[Path] into Ls[Arg]? + def stagedBlock(nme: String, args: Ls[Path | Local])(k: Local => BlockRet): BlockRet = + val s = Select(Value.Ref(block), Tree.Ident(nme))(N) + val res = args match + case Nil => s + case h :: t => Call(s, args.map(toArg))(false, false) + assign(res)(k) + def stagedBlock2(nme: String, args: Ls[Path | Local])(k: Local => Block): Block = + val s = Select(Value.Ref(block), Tree.Ident(nme))(N) + val res = args match + case Nil => s + case h :: t => Call(s, args.map(toArg))(false, false) + assign2(res)(k) + def stagedShape(nme: String, args: Ls[Arg])(k: Local => BlockRet): BlockRet = + val s = Select(Value.Ref(shape), Tree.Ident(nme))(N) + val res = args match + case Nil => s + case h :: t => Call(s, args)(false, false) + assign(res)(k) + + // helpers for staging constructors in Block.mls + + def stagedSymbol(nme: String)(k: Local => BlockRet): BlockRet = + stagedBlock("Symbol", Ls(toValue(nme)))(k) + + def stagedIdent(nme: String)(k: Local => BlockRet): BlockRet = + stagedBlock("Ident", Ls(toValue(nme)))(k) + + def stagedRef(l: Symbol)(k: Local => BlockRet): BlockRet = + stagedSymbol(l.nme): l => + stagedBlock("ValueRef", Ls(l))(k) + + // note that this is for Block.ValueLit, not Shape.Lit + def stagedBLit(l: Literal)(k: Local => BlockRet): BlockRet = + stagedBlock("ValueLit", Ls(Value.Lit(l)))(k) + + def stagedSelect(qual: Path, name: Str)(k: Local => BlockRet): BlockRet = + stagedPath(qual): p => + stagedIdent(name): i => + stagedBlock("Select", Ls(p, i))(k) + + def stagedDynSelect(qual: Path, fld: Path, arrayIdx: Bool)(k: Local => BlockRet): BlockRet = + stagedPath(qual): q => + stagedPath(fld): f => + stagedBlock("DynSelect", Ls(q, f, toValue(arrayIdx)))(k) + + def stagedPath(p: Path)(k: Local => BlockRet): BlockRet = p match + case Select(qual, tree) => stagedSelect(qual, tree.name)(k) + case DynSelect(qual, fld, arrayIdx) => stagedDynSelect(qual, fld, arrayIdx)(k) + case Value.Ref(l) => stagedRef(l)(k) + case Value.Lit(lit) => stagedBLit(lit)(k) + case _ => ??? + + def stagedTuple(mut: Bool, elems: Ls[Arg])(k: Local => BlockRet): BlockRet = + // TODO: staging array + stagedBlock("Tuple", Ls(toValue(mut), ???))(k) + + // helpers to create and access the components of a staged value + def returnStagedValue(shape: Local, value: Local): Block = + stagedBlock2("Tuple", Ls(shape, value)): z => + stagedBlock2("Return", Ls(z, toValue(false))): _ => + End() + def getShape(l: Local)(k: Local => BlockRet): BlockRet = + stagedSelect(Value.Ref(l), "0")(k) + def getBlock(l: Local)(k: Local => BlockRet): BlockRet = + stagedSelect(Value.Ref(l), "1")(k) + + // functions that perform the instrumentation + + def ruleLit(l: Literal): BlockRet = + (id, SLit(l), Value.Lit(l)) + + def ruleVar(x: (Shape, Value.Ref)): BlockRet = + stagedBlock("ValueRef", Ls(x._2)): block => + (id, x._1, Value.Ref(block)) + + def ruleArr(ps: Ls[Path]): BlockRet = + // ps match + // case head :: next => next.foldRight(stagedPath(head)(b))() + // case Nil => (id, ) + + val (bs, ss, vs) = ps.map(stagedPath).unzip3 + (b => bs.foldRight(b)(_(_)), SArr(ps.length, ss), ???) + + def ruleReturn(r: Return): BlockRet = + val (b, s, v) = stagedResult(r.res) + stagedBlock("Return", Ls(v, toValue(r.implct))): ret => + (b, s, Value.Ref(ret)) + + def ruleInst(i: Instantiate): BlockRet = + val Instantiate(mut, cls, args) = i + assert(!mut) + // args.reduceRightOption[BlockRet]((arg, x) => + // val (b, ss, vs) = x + // ??? + // ).getOrElse(???) + val (bs, ss, vs) = args.map(stagedArg).unzip3 + // turn path to symbol somehow + val sym: Symbol = ??? + val s = SClass(???, ss) + stagedSelect(cls, "class"): sel => + stagedBlock("Tuple", Ls(toValue(false), ???)): _ => + ??? + // stagedBlock("Instantiate", Ls(toValue(false), sym, ???).map(toArg)): inst => + // ??? + + def ruleEnd(): BlockRet = + stagedBlock("End", Ls()): end => + (id, Unit, Value.Ref(end)) + + // todo functions that fills out the holes in the functions above + + def stagedResult(res: Result): BlockRet = res match + case Call(fun, args) => ??? + case res: Instantiate => ruleInst(res) + case Lambda(params, body) => ??? + case Tuple(mut, elems) => ??? + case Record(mut, elems) => ??? + case Select(qual, name) => ??? + case DynSelect(qual, fld, arrayIdx) => ??? + case Value.Ref(l) => ??? + case Value.Lit(lit) => ??? + case _ => ??? + + def stagedPath(p: Path): BlockRet = p match + case Select(qual, name) => ??? + case DynSelect(qual, fld, arrayIdx) => ??? + case Value.Ref(l) => ??? + case Value.Lit(lit) => ??? + case _ => ??? + + def stagedArg(a: Arg): BlockRet = ??? + + + \ No newline at end of file From 9298f36f9f97c645ab5b10c9290325c0e60ca7d0 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 31 Oct 2025 20:10:32 +0800 Subject: [PATCH 012/268] add Block.mls --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript-compile/Block.mls diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls new file mode 100644 index 0000000000..e69de29bb2 From 4796cad5172ba4724aae521e30f8e8f550ca3de3 Mon Sep 17 00:00:00 2001 From: TYeung Date: Tue, 28 Oct 2025 09:59:28 +0800 Subject: [PATCH 013/268] Add Block.mls into DiffMaker and prepare the function for lowering --- .../main/scala/hkmc2/codegen/Lowering.scala | 55 +++++++++++-------- .../src/test/scala/hkmc2/MLsDiffMaker.scala | 7 +++ 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index 273c473ec6..8e24e7bad4 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -62,7 +62,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): tl.trace[Term](s"Expanding term ${r}", post = t => s"~> ${t}"): r.expanded case t => t - + val lowerHandlers: Bool = config.effectHandlers.isDefined val lift: Bool = config.liftDefns.isDefined @@ -168,28 +168,34 @@ class Lowering()(using Config, TL, Raise, State, Ctx): case N => // abstract declarations have no lowering blockImpl(stats, res)(k) case S(bod) => - td.k match - case knd: syntax.Val => - assert(td.params.isEmpty) - subTerm_nonTail(bod)(r => - // Assign(td.sym, r, - // term(st.Blk(stats, res))(k))) - Define(ValDefn(td.tsym, td.sym, r), - blockImpl(stats, res)(k))) - case syntax.Fun => - val (paramLists, bodyBlock) = setupFunctionOrByNameDef(td.params, bod, S(td.sym.nme)) - Define(FunDefn(td.owner, td.sym, paramLists, bodyBlock), - blockImpl(stats, res)(k)) - case syntax.Ins => - // Implicit instances are not parameterized for now. - assert(td.params.isEmpty) - subTerm(bod)(r => - Define(ValDefn(td.tsym, td.sym, r), - blockImpl(stats, res)(k))) - case syntax.LetBind | syntax.ParamBind | syntax.HandlerBind => fail: - ErrorReport( - msg"Unexpected declaration kind '${td.k.str}' in lowering" -> td.toLoc :: Nil, - source = Diagnostic.Source.Compilation) + val isStaged: Bool = td.extraAnnotations.exists: + case Annot.Modifier(syntax.Keyword.`staged`) => true + case _ => false + if isStaged then + stage(d)(k) + else + td.k match + case knd: syntax.Val => + assert(td.params.isEmpty) + subTerm_nonTail(bod)(r => + // Assign(td.sym, r, + // term(st.Blk(stats, res))(k))) + Define(ValDefn(td.tsym, td.sym, r), + blockImpl(stats, res)(k))) + case syntax.Fun => + val (paramLists, bodyBlock) = setupFunctionOrByNameDef(td.params, bod, S(td.sym.nme)) + Define(FunDefn(td.owner, td.sym, paramLists, bodyBlock), + blockImpl(stats, res)(k)) + case syntax.Ins => + // Implicit instances are not parameterized for now. + assert(td.params.isEmpty) + subTerm(bod)(r => + Define(ValDefn(td.tsym, td.sym, r), + blockImpl(stats, res)(k))) + case syntax.LetBind | syntax.ParamBind | syntax.HandlerBind => fail: + ErrorReport( + msg"Unexpected declaration kind '${td.k.str}' in lowering" -> td.toLoc :: Nil, + source = Diagnostic.Source.Compilation) case cls: ClassLikeDef if cls.sym.defn.exists(_.hasDeclareModifier.isDefined) => // * Declarations have no lowering blockImpl(stats, res)(k) @@ -900,6 +906,8 @@ class Lowering()(using Config, TL, Raise, State, Ctx): source = Diagnostic.Source.Compilation ) + def stage(t: Declaration)(k: Result => Block)(using Subst): Block = ??? + def gatherMembers(clsBody: ObjBody)(using Subst) : (Ls[FunDefn], Ls[BlockMemberSymbol -> TermSymbol], Ls[TermSymbol], Block) = val mtds = clsBody.methods @@ -1053,6 +1061,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): def reportAnnotations(target: Statement, annotations: Ls[Annot]): Unit = annotations.foreach: case Annot.Untyped => () + case Annot.Modifier(syntax.Keyword("staged")) => () case annot => raise: WarningReport(msg"This annotation has no effect." -> annot.toLoc :: Nil) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index 3e59ea626a..c96b7829d8 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -20,6 +20,7 @@ abstract class MLsDiffMaker extends DiffMaker: val predefFile: os.Path // * Contains MLscript standard library definitions val runtimeFile: os.Path = predefFile/os.up/"Runtime.mjs" // * Contains MLscript runtime definitions val termFile: os.Path = predefFile/os.up/"Term.mjs" // * Contains MLscript runtime term definitions + val blockFile: os.Path = predefFile/os.up/"Block.mjs" // * Contains MLscript runtime block definitions val wd = file / os.up @@ -63,6 +64,7 @@ abstract class MLsDiffMaker extends DiffMaker: val stackSafe = Command("stackSafe")(_.trim) val liftDefns = NullaryCommand("lift") val importQQ = NullaryCommand("qq") + val staging = NullaryCommand("staging") def mkConfig: Config = import Config.* @@ -150,6 +152,11 @@ abstract class MLsDiffMaker extends DiffMaker: given Config = mkConfig processTrees( PrefixApp(Keywrd(`import`), StrLit(termFile.toString)) :: Nil) + if staging.isSet then + given Config = mkConfig + processTrees( + PrefixApp(Keywrd(`import`), StrLit(blockFile.toString)) :: Nil) + super.init() From b072e4aba60f1bca8391fa5d4b8b23e33c1aca8b Mon Sep 17 00:00:00 2001 From: TYeung Date: Thu, 30 Oct 2025 21:46:59 +0800 Subject: [PATCH 014/268] add block.mjs also in MLsCompiler --- .../src/main/scala/hkmc2/MLsCompiler.scala | 6 +- .../main/scala/hkmc2/codegen/Lowering.scala | 55 ++++++++----------- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala b/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala index 86eef96736..63ef6a6832 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala @@ -41,6 +41,7 @@ class MLsCompiler(preludeFile: os.Path, mkOutput: ((Str => Unit) => Unit) => Uni val runtimeFile: os.Path = preludeFile/os.up/os.up/os.up/"mlscript-compile"/"Runtime.mjs" val termFile: os.Path = preludeFile/os.up/os.up/os.up/"mlscript-compile"/"Term.mjs" + val blockFile: os.Path = preludeFile/os.up/os.up/os.up/"mlscript-compile"/"Block.mjs" val report = ReportFormatter: outputConsumer => @@ -85,7 +86,10 @@ class MLsCompiler(preludeFile: os.Path, mkOutput: ((Str => Unit) => Unit) => Uni val resolver = Resolver(rtl) resolver.traverseBlock(blk0)(using Resolver.ICtx.empty) val blk = new semantics.Term.Blk( - semantics.Import(State.runtimeSymbol, runtimeFile.toString) :: semantics.Import(State.termSymbol, termFile.toString) :: blk0.stats, + semantics.Import(State.runtimeSymbol, runtimeFile.toString, runtimeFile) + :: semantics.Import(State.termSymbol, termFile.toString, termFile) + :: semantics.Import(State.termSymbol, termFile.toString, blockFile) // TODO: always include this? + :: blk0.stats, blk0.res ) val low = ltl.givenIn: diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index 8e24e7bad4..5afa6d7d7a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -168,34 +168,28 @@ class Lowering()(using Config, TL, Raise, State, Ctx): case N => // abstract declarations have no lowering blockImpl(stats, res)(k) case S(bod) => - val isStaged: Bool = td.extraAnnotations.exists: - case Annot.Modifier(syntax.Keyword.`staged`) => true - case _ => false - if isStaged then - stage(d)(k) - else - td.k match - case knd: syntax.Val => - assert(td.params.isEmpty) - subTerm_nonTail(bod)(r => - // Assign(td.sym, r, - // term(st.Blk(stats, res))(k))) - Define(ValDefn(td.tsym, td.sym, r), - blockImpl(stats, res)(k))) - case syntax.Fun => - val (paramLists, bodyBlock) = setupFunctionOrByNameDef(td.params, bod, S(td.sym.nme)) - Define(FunDefn(td.owner, td.sym, paramLists, bodyBlock), - blockImpl(stats, res)(k)) - case syntax.Ins => - // Implicit instances are not parameterized for now. - assert(td.params.isEmpty) - subTerm(bod)(r => - Define(ValDefn(td.tsym, td.sym, r), - blockImpl(stats, res)(k))) - case syntax.LetBind | syntax.ParamBind | syntax.HandlerBind => fail: - ErrorReport( - msg"Unexpected declaration kind '${td.k.str}' in lowering" -> td.toLoc :: Nil, - source = Diagnostic.Source.Compilation) + td.k match + case knd: syntax.Val => + assert(td.params.isEmpty) + subTerm_nonTail(bod)(r => + // Assign(td.sym, r, + // term(st.Blk(stats, res))(k))) + Define(ValDefn(td.tsym, td.sym, r), + blockImpl(stats, res)(k))) + case syntax.Fun => + val (paramLists, bodyBlock) = setupFunctionOrByNameDef(td.params, bod, S(td.sym.nme)) + Define(FunDefn(td.owner, td.sym, paramLists, bodyBlock), + blockImpl(stats, res)(k)) + case syntax.Ins => + // Implicit instances are not parameterized for now. + assert(td.params.isEmpty) + subTerm(bod)(r => + Define(ValDefn(td.tsym, td.sym, r), + blockImpl(stats, res)(k))) + case syntax.LetBind | syntax.ParamBind | syntax.HandlerBind => fail: + ErrorReport( + msg"Unexpected declaration kind '${td.k.str}' in lowering" -> td.toLoc :: Nil, + source = Diagnostic.Source.Compilation) case cls: ClassLikeDef if cls.sym.defn.exists(_.hasDeclareModifier.isDefined) => // * Declarations have no lowering blockImpl(stats, res)(k) @@ -906,8 +900,6 @@ class Lowering()(using Config, TL, Raise, State, Ctx): source = Diagnostic.Source.Compilation ) - def stage(t: Declaration)(k: Result => Block)(using Subst): Block = ??? - def gatherMembers(clsBody: ObjBody)(using Subst) : (Ls[FunDefn], Ls[BlockMemberSymbol -> TermSymbol], Ls[TermSymbol], Block) = val mtds = clsBody.methods @@ -1061,7 +1053,8 @@ class Lowering()(using Config, TL, Raise, State, Ctx): def reportAnnotations(target: Statement, annotations: Ls[Annot]): Unit = annotations.foreach: case Annot.Untyped => () - case Annot.Modifier(syntax.Keyword("staged")) => () + case annot @ Annot.Modifier(syntax.Keyword("staged")) => raise: + WarningReport(msg"staged annotation has no effect." -> annot.toLoc :: Nil) case annot => raise: WarningReport(msg"This annotation has no effect." -> annot.toLoc :: Nil) From 35106c08e5faf1726c141bacdf64251336c58723 Mon Sep 17 00:00:00 2001 From: TYeung Date: Fri, 31 Oct 2025 01:17:04 +0800 Subject: [PATCH 015/268] lower 'staged' annotations to Block and add display of 'staged' annotation during diff testing --- .../src/main/scala/hkmc2/codegen/Block.scala | 8 ++ .../main/scala/hkmc2/codegen/Lowering.scala | 8 +- .../main/scala/hkmc2/codegen/Printer.scala | 8 +- .../src/test/mlscript/staging/Syntax.mls | 94 ++++++++++++------- .../test/scala/hkmc2/JSBackendDiffMaker.scala | 2 +- 5 files changed, 81 insertions(+), 39 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala index c8b9ccd103..b622df8e5e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala @@ -340,6 +340,14 @@ final case class FunDefn( body: Block, ) extends Defn: val innerSym = N + var staged = false + + +object FunDefn: + def apply(owner: Opt[InnerSymbol], sym: BlockMemberSymbol, params: Ls[ParamList], body: Block, staged: Boolean): FunDefn = + var f = new FunDefn(owner, sym, params, body) + f.staged = staged + f final case class ValDefn( diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index 5afa6d7d7a..b448598f6d 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -163,6 +163,9 @@ class Lowering()(using Config, TL, Raise, State, Ctx): case (d: Declaration) :: stats => d match case td: TermDefinition => + val isStaged = td.extraAnnotations.exists: + case Annot.Modifier(syntax.Keyword.`staged`) => true + case _ => false reportAnnotations(td, td.extraAnnotations) td.body match case N => // abstract declarations have no lowering @@ -178,7 +181,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): blockImpl(stats, res)(k))) case syntax.Fun => val (paramLists, bodyBlock) = setupFunctionOrByNameDef(td.params, bod, S(td.sym.nme)) - Define(FunDefn(td.owner, td.sym, paramLists, bodyBlock), + Define(FunDefn(td.owner, td.sym, paramLists, bodyBlock, isStaged), blockImpl(stats, res)(k)) case syntax.Ins => // Implicit instances are not parameterized for now. @@ -1053,8 +1056,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): def reportAnnotations(target: Statement, annotations: Ls[Annot]): Unit = annotations.foreach: case Annot.Untyped => () - case annot @ Annot.Modifier(syntax.Keyword("staged")) => raise: - WarningReport(msg"staged annotation has no effect." -> annot.toLoc :: Nil) + case annot @ Annot.Modifier(syntax.Keyword("staged")) => () case annot => raise: WarningReport(msg"This annotation has no effect." -> annot.toLoc :: Nil) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index 20963e8629..86d47fd502 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -60,10 +60,12 @@ object Printer: case _ => TODO(blk) def mkDocument(defn: Defn)(using Raise, Scope): Document = defn match - case FunDefn(own, sym, params, body) => - val docParams = doc"${own.fold("")(_.toString+"::")}${params.map(_.params.map(x => summon[Scope].allocateName(x.sym)).mkString("(", ", ", ")")).mkString}" + case fd @ FunDefn(own, sym, params, body) => + val docParams = doc"${own.fold("")(_.toString+"::")}${params.map(_.params.map(x => summon[Scope].allocateName(x.sym)).mkDocument("(", ", ", ")")).mkDocument("")}" val docBody = mkDocument(body) - doc"fun ${sym.nme}${docParams} { #{ # ${docBody} #} # }" + // doc"fun ${sym.nme}${docParams} { #{ # ${docBody} #} # }" + val docInstr = if fd.staged then doc" staged" else doc"" + doc"fun ${sym.nme}${docParams}${docInstr} { #{ # ${docBody} #} # }" case ValDefn(tsym, sym, rhs) => doc"val ${tsym.nme} = ${mkDocument(rhs)}" case ClsLikeDefn(own, _, sym, k, paramsOpt, auxParams, parentSym, methods, diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index c0baf4c1b3..547488ebd0 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -7,22 +7,22 @@ module A with //│ Elab block List(TypeDef(Mod,InfixApp(Ident(A),keyword 'with',Block(List(TermDef(Fun,App(Ident(f),Tup(List(Ident[...] LocalScope(block:3) //│ | Processing module/object definition Ident(A) //│ | | Companion: None -//│ | | Elab block List(TermDef(Fun,App(Ident(f),Tup(List(Ident(x)))),Some(Ident(x)))) InnerScope(module:A‹537›) +//│ | | Elab block List(TermDef(Fun,App(Ident(f),Tup(List(Ident(x)))),Some(Ident(x)))) InnerScope(module:A‹592›) //│ | | | Processing term definition App(Ident(f),Tup(List(Ident(x)))) //│ | | | Elaborating ParamTree: ParamTree(‹›,Ident(x),None,None,Set()) //│ | | | Elab term Ident(x) //│ | | | | Elab subterm Ident(x) -//│ | | | | ~> Ref(x‹539›) -//│ | | | ~> Ref(x‹539›) -//│ | | ~> Blk(List(TermDefinition(Fun,member:f‹535›,module:A‹537›.f,List(ParamList(‹›,List(Param(‹›,x‹539›,None,Modulefulness(None))),None)),None,None,Some(Ref(x‹539›)),‹result of member:f‹535››‹541›,‹›,Modulefulness(None),List(),None)),Lit(UnitLit(false))) -//│ ~> Blk(List(ModuleOrObjectDef(None,module:A‹537›,member:A‹536›,List(),None,List(),None,Mod,{ fun member:f‹535›(x‹539›) = x‹539›#666; },None,List())),Lit(UnitLit(false))) +//│ | | | | ~> Ref(x‹594›) +//│ | | | ~> Ref(x‹594›) +//│ | | ~> Blk(List(TermDefinition(Fun,member:f‹590›,module:A‹592›.f,List(ParamList(‹›,List(Param(‹›,x‹594›,None,Modulefulness(None))),None)),None,None,Some(Ref(x‹594›)),‹result of member:f‹590››‹596›,‹›,Modulefulness(None),List(),None)),Lit(UnitLit(false))) +//│ ~> Blk(List(ModuleOrObjectDef(None,module:A‹592›,member:A‹591›,List(),None,List(),None,Mod,{ fun member:f‹590›(x‹594›) = x‹594›#666; },None,List())),Lit(UnitLit(false))) //│ Elaborated tree: //│ Blk: //│ stats = Ls of //│ ModuleOrObjectDef: //│ owner = N -//│ sym = module:A‹537› -//│ bsym = member:A‹536› +//│ sym = module:A‹592› +//│ bsym = member:A‹591› //│ tparams = Nil //│ paramsOpt = N //│ auxParams = Nil @@ -32,22 +32,22 @@ module A with //│ stats = Ls of //│ TermDefinition: //│ k = Fun -//│ sym = member:f‹535› -//│ tsym = module:A‹537›.f +//│ sym = member:f‹590› +//│ tsym = module:A‹592›.f //│ params = Ls of //│ ParamList: //│ flags = () //│ params = Ls of //│ Param: //│ flags = () -//│ sym = x‹539› +//│ sym = x‹594› //│ sign = N //│ modulefulness = Modulefulness of N //│ restParam = N //│ tparams = N //│ sign = N -//│ body = S of Ref{sym=x‹539›} of x‹539› -//│ resSym = ‹result of member:f‹535››‹541› +//│ body = S of Ref{sym=x‹594›} of x‹594› +//│ resSym = ‹result of member:f‹590››‹596› //│ flags = () //│ modulefulness = Modulefulness of N //│ annotations = Nil @@ -62,36 +62,36 @@ B.f(1) //│ Elab block List(Annotated(Keywrd(keyword 'staged'),TypeDef(Mod,InfixApp(Ident(B),keyword 'with',Block(List(Term[...] LocalScope(block:4) //│ | Processing module/object definition Ident(B) //│ | | Companion: None -//│ | | Elab block List(TermDef(Fun,App(Ident(f),Tup(List(Ident(x)))),Some(Ident(x)))) InnerScope(module:B‹545›) +//│ | | Elab block List(TermDef(Fun,App(Ident(f),Tup(List(Ident(x)))),Some(Ident(x)))) InnerScope(module:B‹600›) //│ | | | Processing term definition App(Ident(f),Tup(List(Ident(x)))) //│ | | | Elaborating ParamTree: ParamTree(‹›,Ident(x),None,None,Set()) //│ | | | Elab term Ident(x) //│ | | | | Elab subterm Ident(x) -//│ | | | | ~> Ref(x‹547›) -//│ | | | ~> Ref(x‹547›) -//│ | | ~> Blk(List(TermDefinition(Fun,member:f‹543›,module:B‹545›.f,List(ParamList(‹›,List(Param(‹›,x‹547›,None,Modulefulness(None))),None)),None,None,Some(Ref(x‹547›)),‹result of member:f‹543››‹549›,‹›,Modulefulness(None),List(),None)),Lit(UnitLit(false))) +//│ | | | | ~> Ref(x‹602›) +//│ | | | ~> Ref(x‹602›) +//│ | | ~> Blk(List(TermDefinition(Fun,member:f‹598›,module:B‹600›.f,List(ParamList(‹›,List(Param(‹›,x‹602›,None,Modulefulness(None))),None)),None,None,Some(Ref(x‹602›)),‹result of member:f‹598››‹604›,‹›,Modulefulness(None),List(),None)),Lit(UnitLit(false))) //│ | Elab term App(Sel(Ident(B),Ident(f)),Tup(List(IntLit(1)))) //│ | | Elab subterm App(Sel(Ident(B),Ident(f)),Tup(List(IntLit(1)))) //│ | | | Elab subterm Sel(Ident(B),Ident(f)) //│ | | | | Elab subterm Ident(B) -//│ | | | | ~> Ref(member:B‹544›) -//│ | | | ~> Sel(Ref(member:B‹544›),Ident(f)) +//│ | | | | ~> Ref(member:B‹599›) +//│ | | | ~> Sel(Ref(member:B‹599›),Ident(f)) //│ | | | Elab subterm Tup(List(IntLit(1))) //│ | | | | Elab term IntLit(1) //│ | | | | | Elab subterm IntLit(1) //│ | | | | | ~> Lit(IntLit(1)) //│ | | | | ~> Lit(IntLit(1)) //│ | | | ~> Tup(List(Fld(‹›,Lit(IntLit(1)),None))) -//│ | | ~> App(Sel(Ref(member:B‹544›),Ident(f)),Tup(List(Fld(‹›,Lit(IntLit(1)),None)))) -//│ | ~> App(Sel(Ref(member:B‹544›),Ident(f)),Tup(List(Fld(‹›,Lit(IntLit(1)),None)))) -//│ ~> Blk(List(ModuleOrObjectDef(None,module:B‹545›,member:B‹544›,List(),None,List(),None,Mod,{ fun member:f‹543›(x‹547›) = x‹547›#666; },None,List(Modifier(keyword 'staged')))),App(Sel(Ref(member:B‹544›),Ident(f)),Tup(List(Fld(‹›,Lit(IntLit(1)),None))))) +//│ | | ~> App(Sel(Ref(member:B‹599›),Ident(f)),Tup(List(Fld(‹›,Lit(IntLit(1)),None)))) +//│ | ~> App(Sel(Ref(member:B‹599›),Ident(f)),Tup(List(Fld(‹›,Lit(IntLit(1)),None)))) +//│ ~> Blk(List(ModuleOrObjectDef(None,module:B‹600›,member:B‹599›,List(),None,List(),None,Mod,{ fun member:f‹598›(x‹602›) = x‹602›#666; },None,List(Modifier(keyword 'staged')))),App(Sel(Ref(member:B‹599›),Ident(f)),Tup(List(Fld(‹›,Lit(IntLit(1)),None))))) //│ Elaborated tree: //│ Blk: //│ stats = Ls of //│ ModuleOrObjectDef: //│ owner = N -//│ sym = module:B‹545› -//│ bsym = member:B‹544› +//│ sym = module:B‹600› +//│ bsym = member:B‹599› //│ tparams = Nil //│ paramsOpt = N //│ auxParams = Nil @@ -101,22 +101,22 @@ B.f(1) //│ stats = Ls of //│ TermDefinition: //│ k = Fun -//│ sym = member:f‹543› -//│ tsym = module:B‹545›.f +//│ sym = member:f‹598› +//│ tsym = module:B‹600›.f //│ params = Ls of //│ ParamList: //│ flags = () //│ params = Ls of //│ Param: //│ flags = () -//│ sym = x‹547› +//│ sym = x‹602› //│ sign = N //│ modulefulness = Modulefulness of N //│ restParam = N //│ tparams = N //│ sign = N -//│ body = S of Ref{sym=x‹547›} of x‹547› -//│ resSym = ‹result of member:f‹543››‹549› +//│ body = S of Ref{sym=x‹602›} of x‹602› +//│ resSym = ‹result of member:f‹598››‹604› //│ flags = () //│ modulefulness = Modulefulness of N //│ annotations = Nil @@ -126,8 +126,8 @@ B.f(1) //│ annotations = Ls of //│ Modifier of keyword 'staged' //│ res = App: -//│ lhs = Sel{sym=member:f‹543›}: -//│ prefix = Ref{sym=member:B‹544›} of member:B‹544› +//│ lhs = Sel{sym=member:f‹598›}: +//│ prefix = Ref{sym=member:B‹599›} of member:B‹599› //│ nme = Ident of "f" //│ rhs = Tup of Ls of //│ Fld: @@ -142,7 +142,7 @@ staged object Foo //│ Elab block List(Annotated(Keywrd(keyword 'staged'),TypeDef(Obj,Ident(Foo),None))) LocalScope(block:5) //│ | Processing module/object definition Ident(Foo) //│ | | Companion: None -//│ ~> Blk(List(ModuleOrObjectDef(None,object:Foo‹553›,member:Foo‹552›,List(),None,List(),None,Obj,{ },None,List(Modifier(keyword 'staged')))),Lit(UnitLit(false))) +//│ ~> Blk(List(ModuleOrObjectDef(None,object:Foo‹608›,member:Foo‹607›,List(),None,List(),None,Obj,{ },None,List(Modifier(keyword 'staged')))),Lit(UnitLit(false))) :de :pe @@ -157,4 +157,34 @@ staged fun f() = 0 //│ | | Elab subterm IntLit(0) //│ | | ~> Lit(IntLit(0)) //│ | ~> Lit(IntLit(0)) -//│ ~> Blk(List(TermDefinition(Fun,member:f‹555›,.f,List(ParamList(‹›,List(),None)),None,None,Some(Lit(IntLit(0))),‹result of member:f‹555››‹557›,‹›,Modulefulness(None),List(Modifier(keyword 'staged')),None)),Lit(UnitLit(false))) +//│ ~> Blk(List(TermDefinition(Fun,member:f‹610›,.f,List(ParamList(‹›,List(),None)),None,None,Some(Lit(IntLit(0))),‹result of member:f‹610››‹612›,‹›,Modulefulness(None),List(Modifier(keyword 'staged')),None)),Lit(UnitLit(false))) + + +:js +:lot +:slot +staged fun f() = 0 +//│ FAILURE: Unexpected warning +//│ FAILURE LOCATION: reportAnnotations (Lowering.scala:1102) +//│ ═══[WARNING] staged annotation detected. +//│ Lowered: +//│ Program: +//│ imports = Nil +//│ main = Define: +//│ defn = FunDefn (staged=true): +//│ owner = N +//│ sym = member:f +//│ params = Ls of +//│ ParamList: +//│ flags = () +//│ params = Nil +//│ restParam = N +//│ body = Return: +//│ res = Lit of IntLit of 0 +//│ implct = false +//│ rest = Assign: \ +//│ lhs = $block$res +//│ rhs = Lit of UnitLit of false +//│ rest = End of "" +//│ Pretty Lowered: +//│ define fun f() staged { return 0 } in set block$res = undefined in end diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala index 1adcd726b3..6fd0ddc9c1 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala @@ -113,7 +113,7 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: ) if showLoweredTree.isSet then output(s"Lowered:") - output(le.showAsTree) + output(le.showAsTree(using { case fd : hkmc2.codegen.FunDefn => s"staged=${fd.staged}" case _ => ""})) // * We used to do this to avoid needlessly generating new variable names in separate blocks: // val nestedScp = baseScp.nest From 4efccdfb153b1bc97829e1771a5ab4901f92c045 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 31 Oct 2025 20:36:15 +0800 Subject: [PATCH 016/268] amend! Add Block.mls into DiffMaker and prepare the function for lowering Add Block.mls into DiffMaker and prepare the function for lowering Use older Import syntax for now --- hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala b/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala index 63ef6a6832..886bcc66d0 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala @@ -86,9 +86,9 @@ class MLsCompiler(preludeFile: os.Path, mkOutput: ((Str => Unit) => Unit) => Uni val resolver = Resolver(rtl) resolver.traverseBlock(blk0)(using Resolver.ICtx.empty) val blk = new semantics.Term.Blk( - semantics.Import(State.runtimeSymbol, runtimeFile.toString, runtimeFile) - :: semantics.Import(State.termSymbol, termFile.toString, termFile) - :: semantics.Import(State.termSymbol, termFile.toString, blockFile) // TODO: always include this? + semantics.Import(State.runtimeSymbol, runtimeFile.toString) + :: semantics.Import(State.termSymbol, termFile.toString) + :: semantics.Import(State.termSymbol, termFile.toString) // TODO: always include this? :: blk0.stats, blk0.res ) From f9ad6120ba6263447d47e4cfc5d67cabc5b9aee5 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 31 Oct 2025 20:50:01 +0800 Subject: [PATCH 017/268] clean up Syntax.mls --- .../src/test/mlscript/staging/Syntax.mls | 208 +++++------------- 1 file changed, 53 insertions(+), 155 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index 547488ebd0..f965622a29 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -1,172 +1,70 @@ -import "./../../mlscript-compile/Predef.mjs" -:de -:elt -module A with +:pt +staged module A with fun f(x) = x -//│ Elab block List(TypeDef(Mod,InfixApp(Ident(A),keyword 'with',Block(List(TermDef(Fun,App(Ident(f),Tup(List(Ident[...] LocalScope(block:3) -//│ | Processing module/object definition Ident(A) -//│ | | Companion: None -//│ | | Elab block List(TermDef(Fun,App(Ident(f),Tup(List(Ident(x)))),Some(Ident(x)))) InnerScope(module:A‹592›) -//│ | | | Processing term definition App(Ident(f),Tup(List(Ident(x)))) -//│ | | | Elaborating ParamTree: ParamTree(‹›,Ident(x),None,None,Set()) -//│ | | | Elab term Ident(x) -//│ | | | | Elab subterm Ident(x) -//│ | | | | ~> Ref(x‹594›) -//│ | | | ~> Ref(x‹594›) -//│ | | ~> Blk(List(TermDefinition(Fun,member:f‹590›,module:A‹592›.f,List(ParamList(‹›,List(Param(‹›,x‹594›,None,Modulefulness(None))),None)),None,None,Some(Ref(x‹594›)),‹result of member:f‹590››‹596›,‹›,Modulefulness(None),List(),None)),Lit(UnitLit(false))) -//│ ~> Blk(List(ModuleOrObjectDef(None,module:A‹592›,member:A‹591›,List(),None,List(),None,Mod,{ fun member:f‹590›(x‹594›) = x‹594›#666; },None,List())),Lit(UnitLit(false))) -//│ Elaborated tree: -//│ Blk: -//│ stats = Ls of -//│ ModuleOrObjectDef: -//│ owner = N -//│ sym = module:A‹592› -//│ bsym = member:A‹591› -//│ tparams = Nil -//│ paramsOpt = N -//│ auxParams = Nil -//│ ext = N -//│ kind = Mod -//│ body = ObjBody of Blk: -//│ stats = Ls of -//│ TermDefinition: -//│ k = Fun -//│ sym = member:f‹590› -//│ tsym = module:A‹592›.f -//│ params = Ls of -//│ ParamList: -//│ flags = () -//│ params = Ls of -//│ Param: -//│ flags = () -//│ sym = x‹594› -//│ sign = N -//│ modulefulness = Modulefulness of N -//│ restParam = N -//│ tparams = N -//│ sign = N -//│ body = S of Ref{sym=x‹594›} of x‹594› -//│ resSym = ‹result of member:f‹590››‹596› -//│ flags = () -//│ modulefulness = Modulefulness of N -//│ annotations = Nil -//│ companion = N -//│ res = Lit of UnitLit of false -//│ companion = N -//│ annotations = Nil -//│ res = Lit of UnitLit of false -staged module B with - fun f(x) = x -B.f(1) -//│ Elab block List(Annotated(Keywrd(keyword 'staged'),TypeDef(Mod,InfixApp(Ident(B),keyword 'with',Block(List(Term[...] LocalScope(block:4) -//│ | Processing module/object definition Ident(B) -//│ | | Companion: None -//│ | | Elab block List(TermDef(Fun,App(Ident(f),Tup(List(Ident(x)))),Some(Ident(x)))) InnerScope(module:B‹600›) -//│ | | | Processing term definition App(Ident(f),Tup(List(Ident(x)))) -//│ | | | Elaborating ParamTree: ParamTree(‹›,Ident(x),None,None,Set()) -//│ | | | Elab term Ident(x) -//│ | | | | Elab subterm Ident(x) -//│ | | | | ~> Ref(x‹602›) -//│ | | | ~> Ref(x‹602›) -//│ | | ~> Blk(List(TermDefinition(Fun,member:f‹598›,module:B‹600›.f,List(ParamList(‹›,List(Param(‹›,x‹602›,None,Modulefulness(None))),None)),None,None,Some(Ref(x‹602›)),‹result of member:f‹598››‹604›,‹›,Modulefulness(None),List(),None)),Lit(UnitLit(false))) -//│ | Elab term App(Sel(Ident(B),Ident(f)),Tup(List(IntLit(1)))) -//│ | | Elab subterm App(Sel(Ident(B),Ident(f)),Tup(List(IntLit(1)))) -//│ | | | Elab subterm Sel(Ident(B),Ident(f)) -//│ | | | | Elab subterm Ident(B) -//│ | | | | ~> Ref(member:B‹599›) -//│ | | | ~> Sel(Ref(member:B‹599›),Ident(f)) -//│ | | | Elab subterm Tup(List(IntLit(1))) -//│ | | | | Elab term IntLit(1) -//│ | | | | | Elab subterm IntLit(1) -//│ | | | | | ~> Lit(IntLit(1)) -//│ | | | | ~> Lit(IntLit(1)) -//│ | | | ~> Tup(List(Fld(‹›,Lit(IntLit(1)),None))) -//│ | | ~> App(Sel(Ref(member:B‹599›),Ident(f)),Tup(List(Fld(‹›,Lit(IntLit(1)),None)))) -//│ | ~> App(Sel(Ref(member:B‹599›),Ident(f)),Tup(List(Fld(‹›,Lit(IntLit(1)),None)))) -//│ ~> Blk(List(ModuleOrObjectDef(None,module:B‹600›,member:B‹599›,List(),None,List(),None,Mod,{ fun member:f‹598›(x‹602›) = x‹602›#666; },None,List(Modifier(keyword 'staged')))),App(Sel(Ref(member:B‹599›),Ident(f)),Tup(List(Fld(‹›,Lit(IntLit(1)),None))))) -//│ Elaborated tree: -//│ Blk: -//│ stats = Ls of -//│ ModuleOrObjectDef: -//│ owner = N -//│ sym = module:B‹600› -//│ bsym = member:B‹599› -//│ tparams = Nil -//│ paramsOpt = N -//│ auxParams = Nil -//│ ext = N -//│ kind = Mod -//│ body = ObjBody of Blk: -//│ stats = Ls of -//│ TermDefinition: -//│ k = Fun -//│ sym = member:f‹598› -//│ tsym = module:B‹600›.f -//│ params = Ls of -//│ ParamList: -//│ flags = () -//│ params = Ls of -//│ Param: -//│ flags = () -//│ sym = x‹602› -//│ sign = N -//│ modulefulness = Modulefulness of N -//│ restParam = N -//│ tparams = N -//│ sign = N -//│ body = S of Ref{sym=x‹602›} of x‹602› -//│ resSym = ‹result of member:f‹598››‹604› -//│ flags = () -//│ modulefulness = Modulefulness of N -//│ annotations = Nil -//│ companion = N -//│ res = Lit of UnitLit of false -//│ companion = N -//│ annotations = Ls of -//│ Modifier of keyword 'staged' -//│ res = App: -//│ lhs = Sel{sym=member:f‹598›}: -//│ prefix = Ref{sym=member:B‹599›} of member:B‹599› -//│ nme = Ident of "f" -//│ rhs = Tup of Ls of -//│ Fld: -//│ flags = () -//│ term = Lit of IntLit of 1 -//│ asc = N +A.f(1) +//│ Parsed tree: +//│ Modified: +//│ modifier = Keywrd of keyword 'staged' +//│ body = TypeDef: +//│ k = Mod +//│ head = InfixApp: +//│ lhs = Ident of "A" +//│ kw = keyword 'with' +//│ rhs = Block of Ls of +//│ TermDef: +//│ k = Fun +//│ head = App: +//│ lhs = Ident of "f" +//│ rhs = Tup of Ls of +//│ Ident of "x" +//│ rhs = S of Ident of "x" +//│ rhs = N +//│ App: +//│ lhs = Sel: +//│ prefix = Ident of "A" +//│ name = Ident of "f" +//│ rhs = Tup of Ls of +//│ IntLit of 1 // should reject these annotations -:de -// :pe +:pt staged object Foo -//│ Elab block List(Annotated(Keywrd(keyword 'staged'),TypeDef(Obj,Ident(Foo),None))) LocalScope(block:5) -//│ | Processing module/object definition Ident(Foo) -//│ | | Companion: None -//│ ~> Blk(List(ModuleOrObjectDef(None,object:Foo‹608›,member:Foo‹607›,List(),None,List(),None,Obj,{ },None,List(Modifier(keyword 'staged')))),Lit(UnitLit(false))) +//│ Parsed tree: +//│ Modified: +//│ modifier = Keywrd of keyword 'staged' +//│ body = TypeDef: +//│ k = Obj +//│ head = Ident of "Foo" +//│ rhs = N -:de -:pe -// staged class Foo +:pt +staged class Foo +//│ Parsed tree: +//│ Modified: +//│ modifier = Keywrd of keyword 'staged' +//│ body = TypeDef: +//│ k = Cls +//│ head = Ident of "Foo" +//│ rhs = N -:de -// :pe +:pt staged fun f() = 0 -//│ Elab block List(Annotated(Keywrd(keyword 'staged'),TermDef(Fun,App(Ident(f),Tup(List())),Some(IntLit(0))))) LocalScope(block:6) -//│ | Processing term definition App(Ident(f),Tup(List())) -//│ | Elab term IntLit(0) -//│ | | Elab subterm IntLit(0) -//│ | | ~> Lit(IntLit(0)) -//│ | ~> Lit(IntLit(0)) -//│ ~> Blk(List(TermDefinition(Fun,member:f‹610›,.f,List(ParamList(‹›,List(),None)),None,None,Some(Lit(IntLit(0))),‹result of member:f‹610››‹612›,‹›,Modulefulness(None),List(Modifier(keyword 'staged')),None)),Lit(UnitLit(false))) +//│ Parsed tree: +//│ Modified: +//│ modifier = Keywrd of keyword 'staged' +//│ body = TermDef: +//│ k = Fun +//│ head = App: +//│ lhs = Ident of "f" +//│ rhs = Tup of Nil +//│ rhs = S of IntLit of 0 :js :lot :slot staged fun f() = 0 -//│ FAILURE: Unexpected warning -//│ FAILURE LOCATION: reportAnnotations (Lowering.scala:1102) -//│ ═══[WARNING] staged annotation detected. //│ Lowered: //│ Program: //│ imports = Nil From f763b03b107f91b335de2b6b553e2717a7cee0c2 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 31 Oct 2025 20:59:25 +0800 Subject: [PATCH 018/268] fiddle with printing staged keyword in FunDefn --- hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala | 5 ++--- hkmc2/shared/src/test/mlscript/staging/Syntax.mls | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index 86d47fd502..ebfbeb3201 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -63,9 +63,8 @@ object Printer: case fd @ FunDefn(own, sym, params, body) => val docParams = doc"${own.fold("")(_.toString+"::")}${params.map(_.params.map(x => summon[Scope].allocateName(x.sym)).mkDocument("(", ", ", ")")).mkDocument("")}" val docBody = mkDocument(body) - // doc"fun ${sym.nme}${docParams} { #{ # ${docBody} #} # }" - val docInstr = if fd.staged then doc" staged" else doc"" - doc"fun ${sym.nme}${docParams}${docInstr} { #{ # ${docBody} #} # }" + val docInstr = if fd.staged then doc"staged " else doc"" + doc"${docInstr}fun ${sym.nme}${docParams} { #{ # ${docBody} #} # }" case ValDefn(tsym, sym, rhs) => doc"val ${tsym.nme} = ${mkDocument(rhs)}" case ClsLikeDefn(own, _, sym, k, paramsOpt, auxParams, parentSym, methods, diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index f965622a29..c24dfc0a3a 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -27,7 +27,7 @@ A.f(1) //│ rhs = Tup of Ls of //│ IntLit of 1 -// should reject these annotations +// TODO: reject these annotations :pt staged object Foo //│ Parsed tree: @@ -60,7 +60,6 @@ staged fun f() = 0 //│ rhs = Tup of Nil //│ rhs = S of IntLit of 0 - :js :lot :slot @@ -85,4 +84,4 @@ staged fun f() = 0 //│ rhs = Lit of UnitLit of false //│ rest = End of "" //│ Pretty Lowered: -//│ define fun f() staged { return 0 } in set block$res = undefined in end +//│ define staged fun f() { return 0 } in set block$res = undefined in end From 85f86c3a5fa8f94186025fc83a5d2596a3ec198f Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 31 Oct 2025 21:12:58 +0800 Subject: [PATCH 019/268] revert whitespace --- hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala | 2 +- hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index facf91b308..8bd6975e1d 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -1335,7 +1335,7 @@ extends Importer: ctx.withMembers(members).givenIn: go(blk.desugStmts, Nil, Nil) - + def mkBlk(acc: Ls[Statement], res: Opt[Term], hasResult: Bool): Blk | Rcd = // TODO forbid certain kinds of terms in records diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index c96b7829d8..6c292f2534 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -156,7 +156,6 @@ abstract class MLsDiffMaker extends DiffMaker: given Config = mkConfig processTrees( PrefixApp(Keywrd(`import`), StrLit(blockFile.toString)) :: Nil) - super.init() From a39765e30068f17d1b7da61ed5498d991bc46efe Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 31 Oct 2025 21:21:38 +0800 Subject: [PATCH 020/268] revert change to printing --- hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index ebfbeb3201..f6375b22d9 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -61,7 +61,7 @@ object Printer: def mkDocument(defn: Defn)(using Raise, Scope): Document = defn match case fd @ FunDefn(own, sym, params, body) => - val docParams = doc"${own.fold("")(_.toString+"::")}${params.map(_.params.map(x => summon[Scope].allocateName(x.sym)).mkDocument("(", ", ", ")")).mkDocument("")}" + val docParams = doc"${own.fold("")(_.toString+"::")}${params.map(_.params.map(x => summon[Scope].allocateName(x.sym)).mkString("(", ", ", ")")).mkString("")}" val docBody = mkDocument(body) val docInstr = if fd.staged then doc"staged " else doc"" doc"${docInstr}fun ${sym.nme}${docParams} { #{ # ${docBody} #} # }" From ee681c900a3662cf758394ffac7bba5f0dab14f2 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 31 Oct 2025 21:22:07 +0800 Subject: [PATCH 021/268] move isStaged inside Fun --- hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index b448598f6d..f244436184 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -163,9 +163,6 @@ class Lowering()(using Config, TL, Raise, State, Ctx): case (d: Declaration) :: stats => d match case td: TermDefinition => - val isStaged = td.extraAnnotations.exists: - case Annot.Modifier(syntax.Keyword.`staged`) => true - case _ => false reportAnnotations(td, td.extraAnnotations) td.body match case N => // abstract declarations have no lowering @@ -181,6 +178,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): blockImpl(stats, res)(k))) case syntax.Fun => val (paramLists, bodyBlock) = setupFunctionOrByNameDef(td.params, bod, S(td.sym.nme)) + val isStaged = td.extraAnnotations.contains(Annot.Modifier(syntax.Keyword.`staged`)) Define(FunDefn(td.owner, td.sym, paramLists, bodyBlock, isStaged), blockImpl(stats, res)(k)) case syntax.Ins => From f77c44c88b1ea4b91bc65bf430e419abed829210 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 31 Oct 2025 21:32:35 +0800 Subject: [PATCH 022/268] more formatting fixes --- hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index f244436184..5b2109f482 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -1054,7 +1054,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): def reportAnnotations(target: Statement, annotations: Ls[Annot]): Unit = annotations.foreach: case Annot.Untyped => () - case annot @ Annot.Modifier(syntax.Keyword("staged")) => () + case Annot.Modifier(syntax.Keyword("staged")) => () case annot => raise: WarningReport(msg"This annotation has no effect." -> annot.toLoc :: Nil) From 9c4c754fd1dd59445cb975688bd8d09882addfa6 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 31 Oct 2025 21:49:50 +0800 Subject: [PATCH 023/268] add new symbols to Elaborator --- hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index 6c06363a31..74b5da556b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -233,6 +233,8 @@ object Elaborator: val definitionMetadataSymbol = TempSymbol(N, "definitionMetadata") val prettyPrintSymbol = TempSymbol(N, "prettyPrint") val termSymbol = TempSymbol(N, "Term") + val blockSymbol = TempSymbol(N, "Block") + val shapeSymbol = TempSymbol(N, "Shape") val wasmSymbol = TempSymbol(N, "wasm") val effectSigSymbol = ClassSymbol(DummyTypeDef(syntax.Cls), Ident("EffectSig")) val nonLocalRetHandlerTrm = From 4e5b28132d3cd6b4334d7ced2bc3129217e1eb19 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 31 Oct 2025 21:56:11 +0800 Subject: [PATCH 024/268] remove Shape and Pattern --- .../scala/hkmc2/codegen/Instrumentation.scala | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index f3b1dd29dd..add43a22a1 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -8,47 +8,6 @@ import semantics.Elaborator.State import syntax.{Literal, Tree} -enum Shape: - case Dyn - case Lit(l: Literal) - case Arr(length: Int, shapes: Ls[Shape]) - case Class(c: Symbol, shapes: Ls[Shape]) - case Unit - -import Shape.{Dyn, Lit => SLit, Arr => SArr, Class => SClass, Unit} - -// TODO: use FlatPattern instead? -enum Pattern: - case Lit(l: Literal) - case Class(c: Symbol) - case Arr(len: Int) - case Wildcard - -import Pattern.{Lit => PLit, Class => PClass, Arr => PArr, Wildcard} - -def isPrimitiveTypeOf(c: Symbol, l: SLit) = ??? - -def mrg2(s1: Shape, s2: Shape): Shape = (s1, s2) match - case (s1, s2) if s1 == s2 => s1 - case (l: SLit, s@SClass(c, _)) if isPrimitiveTypeOf(c, l) => s - case (SClass(c1, s1), SClass(c2, s2)) if c1 == c2 => - SClass(c1, s1 zip s2 map mrg2) - case (SArr(l1, s1), SArr(l2, s2)) if l1 == l2 => - SArr(l1, s1 zip s2 map mrg2) - case _ => Dyn - -def mrg(shapes: Ls[Shape]): Shape = - shapes.reduceRight(mrg2) - -def canMatch(s: Shape, p: Pattern): Opt[Bool] = (s, p) match - case (_, Wildcard) => Some(true) - case (SLit(l1), PLit(l2)) if l1 == l2 => S(true) - case (l: SLit, PClass(c)) if isPrimitiveTypeOf(c, l) => S(true) - case (SClass(c1, _), PClass(c2)) if c1 == c2 => S(true) - case (SArr(n1, s), PArr(n2)) if n1 == n2 => S(true) - case (Dyn, _) => None - case _ => Some(false) - type BlockRet = (Block => Block, Shape, Value) class Instrumentation(using State): // use TempSymbol? From d3aa471f517d85995eb449db055472c18d5c3045 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 31 Oct 2025 22:13:47 +0800 Subject: [PATCH 025/268] rework function signatures --- .../scala/hkmc2/codegen/Instrumentation.scala | 148 ++++-------------- 1 file changed, 33 insertions(+), 115 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index add43a22a1..4dbb4320a1 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -8,169 +8,87 @@ import semantics.Elaborator.State import syntax.{Literal, Tree} -type BlockRet = (Block => Block, Shape, Value) class Instrumentation(using State): - // use TempSymbol? - lazy val block = new BlockMemberSymbol("Block", Nil) - lazy val shape = new BlockMemberSymbol("Shape", Nil) - - def toArg(x: Path | Local): Arg = + def toArg(x: Path | Symbol): Arg = x match case p: Path => Arg(N, p) - case l: Local => Arg(N, Value.Ref(l)) + case l: Symbol => Arg(N, l.asPath) // null and undefined are missing - def toValue(lit: Str | BigInt | BigDecimal | Bool): Value = + def toValue(lit: Str | Int | BigDecimal | Bool): Value = val l = lit match - case i: BigInt => Tree.IntLit(i) + case i: Int => Tree.IntLit(i) case b: Bool => Tree.BoolLit(b) case s: Str => Tree.StrLit(s) case n: BigDecimal => Tree.DecLit(n) Value.Lit(l) - // continuation-passing style allows symbols defined in current function to be referenced later - - def assign(res: Result)(k: Local => BlockRet): BlockRet = - val tmp = new TempSymbol(N, "tmp") - val (rest, shape, value) = k(tmp) - (b => Assign(tmp, res, rest(b)), shape, value) - def assign2(res: Result)(k: Local => Block): Block = - val tmp = new TempSymbol(N, "tmp") - Assign(tmp, res, k(tmp)) + def end(l: Path): Block = Return(l, false) + def assign(res: Result, name: String = "tmp")(k: Path => Block): Block = + val tmp = new TempSymbol(N, name) + Assign(tmp, res, k(tmp.asPath)) // helper for staging the constructors in Block.scala to Block.mls - // automatically convert Ls[Path] into Ls[Arg]? - def stagedBlock(nme: String, args: Ls[Path | Local])(k: Local => BlockRet): BlockRet = - val s = Select(Value.Ref(block), Tree.Ident(nme))(N) - val res = args match - case Nil => s - case h :: t => Call(s, args.map(toArg))(false, false) - assign(res)(k) - def stagedBlock2(nme: String, args: Ls[Path | Local])(k: Local => Block): Block = - val s = Select(Value.Ref(block), Tree.Ident(nme))(N) - val res = args match - case Nil => s - case h :: t => Call(s, args.map(toArg))(false, false) - assign2(res)(k) - def stagedShape(nme: String, args: Ls[Arg])(k: Local => BlockRet): BlockRet = - val s = Select(Value.Ref(shape), Tree.Ident(nme))(N) - val res = args match - case Nil => s - case h :: t => Call(s, args)(false, false) - assign(res)(k) + + def stagedBlock(nme: String, args: Ls[Path | Symbol])(k: Path => Block): Block = + val s = summon[State].blockSymbol.asPath.selSN(nme) + assign(Instantiate(false, s, args.map(toArg)))(k) + def stagedShape(nme: String, args: Ls[Path | Symbol])(k: Path => Block): Block = + val s = summon[State].shapeSymbol.asPath.selSN(nme) + assign(Instantiate(false, s, args.map(toArg)))(k) // helpers for staging constructors in Block.mls - def stagedSymbol(nme: String)(k: Local => BlockRet): BlockRet = + def stagedSymbol(nme: String)(k: Path => Block): Block = stagedBlock("Symbol", Ls(toValue(nme)))(k) - def stagedIdent(nme: String)(k: Local => BlockRet): BlockRet = + def stagedIdent(nme: String)(k: Path => Block): Block = stagedBlock("Ident", Ls(toValue(nme)))(k) - def stagedRef(l: Symbol)(k: Local => BlockRet): BlockRet = + def stagedRef(l: Symbol)(k: Path => Block): Block = stagedSymbol(l.nme): l => stagedBlock("ValueRef", Ls(l))(k) // note that this is for Block.ValueLit, not Shape.Lit - def stagedBLit(l: Literal)(k: Local => BlockRet): BlockRet = + def stagedBLit(l: Literal)(k: Path => Block): Block = stagedBlock("ValueLit", Ls(Value.Lit(l)))(k) - def stagedSelect(qual: Path, name: Str)(k: Local => BlockRet): BlockRet = + def stagedSelect(qual: Path, name: Str)(k: Path => Block): Block = stagedPath(qual): p => stagedIdent(name): i => stagedBlock("Select", Ls(p, i))(k) - def stagedDynSelect(qual: Path, fld: Path, arrayIdx: Bool)(k: Local => BlockRet): BlockRet = + def stagedDynSelect(qual: Path, fld: Path, arrayIdx: Bool)(k: Path => Block): Block = stagedPath(qual): q => stagedPath(fld): f => stagedBlock("DynSelect", Ls(q, f, toValue(arrayIdx)))(k) - def stagedPath(p: Path)(k: Local => BlockRet): BlockRet = p match + def stagedPath(p: Path)(k: Path => Block): Block = p match case Select(qual, tree) => stagedSelect(qual, tree.name)(k) case DynSelect(qual, fld, arrayIdx) => stagedDynSelect(qual, fld, arrayIdx)(k) case Value.Ref(l) => stagedRef(l)(k) case Value.Lit(lit) => stagedBLit(lit)(k) case _ => ??? - def stagedTuple(mut: Bool, elems: Ls[Arg])(k: Local => BlockRet): BlockRet = + def stagedTuple(elems: Ls[Symbol | Path])(k: Path => Block): Block = // TODO: staging array - stagedBlock("Tuple", Ls(toValue(mut), ???))(k) + stagedBlock("Tuple", Ls(toValue(false), ???))(k) // helpers to create and access the components of a staged value - def returnStagedValue(shape: Local, value: Local): Block = - stagedBlock2("Tuple", Ls(shape, value)): z => - stagedBlock2("Return", Ls(z, toValue(false))): _ => - End() - def getShape(l: Local)(k: Local => BlockRet): BlockRet = - stagedSelect(Value.Ref(l), "0")(k) - def getBlock(l: Local)(k: Local => BlockRet): BlockRet = - stagedSelect(Value.Ref(l), "1")(k) - - // functions that perform the instrumentation - - def ruleLit(l: Literal): BlockRet = - (id, SLit(l), Value.Lit(l)) - - def ruleVar(x: (Shape, Value.Ref)): BlockRet = - stagedBlock("ValueRef", Ls(x._2)): block => - (id, x._1, Value.Ref(block)) - - def ruleArr(ps: Ls[Path]): BlockRet = - // ps match - // case head :: next => next.foldRight(stagedPath(head)(b))() - // case Nil => (id, ) - - val (bs, ss, vs) = ps.map(stagedPath).unzip3 - (b => bs.foldRight(b)(_(_)), SArr(ps.length, ss), ???) + def returnStagedValue(shape: Path, value: Path)(k: Path => Block): Block = + assign(Tuple(true, Ls(shape, value).map(toArg)))(k) + def getShape(l: Symbol)(k: Path => Block): Block = + assign(DynSelect(Value.Ref(l), toValue(0), false))(k) + def getBlock(l: Symbol)(k: Path => Block): Block = + assign(DynSelect(Value.Ref(l), toValue(1), false))(k) - def ruleReturn(r: Return): BlockRet = - val (b, s, v) = stagedResult(r.res) - stagedBlock("Return", Ls(v, toValue(r.implct))): ret => - (b, s, Value.Ref(ret)) - - def ruleInst(i: Instantiate): BlockRet = - val Instantiate(mut, cls, args) = i - assert(!mut) - // args.reduceRightOption[BlockRet]((arg, x) => - // val (b, ss, vs) = x - // ??? - // ).getOrElse(???) - val (bs, ss, vs) = args.map(stagedArg).unzip3 - // turn path to symbol somehow - val sym: Symbol = ??? - val s = SClass(???, ss) - stagedSelect(cls, "class"): sel => - stagedBlock("Tuple", Ls(toValue(false), ???)): _ => - ??? - // stagedBlock("Instantiate", Ls(toValue(false), sym, ???).map(toArg)): inst => - // ??? - - def ruleEnd(): BlockRet = - stagedBlock("End", Ls()): end => - (id, Unit, Value.Ref(end)) - // todo functions that fills out the holes in the functions above - def stagedResult(res: Result): BlockRet = res match + def stagedResult(res: Result)(k: Block => Block): Block = res match case Call(fun, args) => ??? - case res: Instantiate => ruleInst(res) + case res: Instantiate => ??? case Lambda(params, body) => ??? case Tuple(mut, elems) => ??? case Record(mut, elems) => ??? - case Select(qual, name) => ??? - case DynSelect(qual, fld, arrayIdx) => ??? - case Value.Ref(l) => ??? - case Value.Lit(lit) => ??? - case _ => ??? - - def stagedPath(p: Path): BlockRet = p match - case Select(qual, name) => ??? - case DynSelect(qual, fld, arrayIdx) => ??? - case Value.Ref(l) => ??? - case Value.Lit(lit) => ??? - case _ => ??? - - def stagedArg(a: Arg): BlockRet = ??? - + case p: Path => stagedPath(p) - \ No newline at end of file From b251526e18c37ccb79678c358ca3135a96f2a368 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 31 Oct 2025 22:32:36 +0800 Subject: [PATCH 026/268] clean up Block.mls --- .../scala/hkmc2/codegen/Instrumentation.scala | 2 +- .../src/test/mlscript-compile/Block.mls | 34 +++---------------- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 4dbb4320a1..13811e9211 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -72,7 +72,7 @@ class Instrumentation(using State): def stagedTuple(elems: Ls[Symbol | Path])(k: Path => Block): Block = // TODO: staging array - stagedBlock("Tuple", Ls(toValue(false), ???))(k) + stagedBlock("Tuple", Ls(???))(k) // helpers to create and access the components of a staged value def returnStagedValue(shape: Path, value: Path)(k: Path => Block): Block = diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 57b674e27e..5e5eedcc87 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -9,29 +9,24 @@ module Block with... type Opt[A] = Option[A] -// dependancies referenced in Block classes +// dependancies referenced in Block classes, referencing implementation in Term.mls -// copying Tree.Ident => Str in Term.mls class Ident(val name: Str) // translation of Tree.Ident class Symbol(val name: Str) -class VarSymbol(val id: Ident) type Literal = null | undefined | Str | Int | Num | Bool class Arg(val spread: Opt[Bool], val value: Path) -// class ClsLikeKind(val desc: Str) -// copying ParamList => Array[Symbol] in Term.mls type ParamList = Array[Symbol] -// Defined Classes for Block +// Classes defined in Block.scala class Path with constructor - Select(val qual: Path, val name: Ident)(symcol: Opt[Symbol]) // extra term unnecessary? + Select(val qual: Path, val name: Ident) DynSelect(val qual: Path, val fld: Path, arrayIdx: Bool) ValueRef(val l: Symbol) ValueLit(val lit: Literal) - // TODO Tup class Case with constructor @@ -44,49 +39,30 @@ class Result with constructor TrivialResult(val path: Path) // only Path extends TrivialResult Call(val _fun: Path, val args: Array[Arg])(isMlsFun: Bool, mayRaiseEffects: Bool) - Instantiate(val _mut: Bool, val cls: Path, val args: Array[Arg]) // may assume immutable - Tuple(val _mut: Bool, val elems: Array[Arg]) // may assume immutable + Instantiate(val cls: Path, val args: Array[Arg]) // assume immutable + Tuple(val elems: Array[Arg]) // assume immutable -// moved owner and innerSym into the argument to comply with `constructor` syntax class Defn with constructor ValDefn( - // val tsym: Symbol, val sym: Symbol, val rhs: Path, - // val innerSym: Symbol = Some(tsym), - // val owner: Opt[Symbol] = tsym.owner, ) ClsLikeDefn( - // val owner: Opt[Symbol], - // val isym: Symbol, val sym: Symbol, - // val k: ClsLikeKind, val paramsOpt: Opt[ParamList], - // val auxParams: Array[ParamList], - // val parentPath: Opt[Path], - // val methods: Array[FunDefn], - // val privateFields: Array[Symbol], - // val publicFields: Array[Symbol -> Symbol], - // val preCtor: Block, - // val ctor: Block, val companion: Opt[ClsLikeBody], - // val innerSym: Symbol = Some(isym), ) FunDefn( - // val owner: Opt[Symbol], val sym: Symbol, val params: Array[ParamList], val body: Block, - // val innerSym: Symbol = None, ) class ClsLikeBody( val isym: Symbol, val methods: Array[FunDefn], - // val privateFields: Array[Symbol], val publicFields: Array[Symbol -> Symbol], - // val ctor: Block, ) class Block with From 84730bf90fb6e427e0471b7b68673d04901ac458 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 31 Oct 2025 23:31:52 +0800 Subject: [PATCH 027/268] add Shape.mls --- .../src/test/mlscript-compile/Shape.mls | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 hkmc2/shared/src/test/mlscript-compile/Shape.mls diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls new file mode 100644 index 0000000000..058ec92344 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -0,0 +1,90 @@ +import "./Predef.mls" +import "./Option.mls" + +open Predef +open Option + +type Literal = null | undefined | Str | Int | Num | Bool +type Opt[A] = Option[A] + +module Shape with... + +class Shape with + constructor + Dyn + Lit(val l: Literal) + Arr(val length: Int, val shapes: Array[Shape]) + // TODO: change sym to accept multiple possible class symbols + Class(val sym: Symbol, val shapes: Array[Shape]) + Unit + +fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = + if [sym, l] is + ["Str", l] and l is Str then true + ["Int", i] and i is Int then true + ["Num", n] and n is Num then true + ["Bool", b] and b is Bool then true + _ then false + +// TODO: look at how Array is used +fun mrg2(s1: Shape, s2: Shape) = if s1 + == s2 then s1 + is Lit(l) and s2 is Class(sym, shapes) + and isPrimitiveTypeOf(sym, l) then Class(sym, shapes) + is Class(sym1, shapes1) and s2 is Class(sym2, shapes2) + and sym1 == sym2 then Class(sym1, ???) + is Arr(l1, s1) and s2 is Arr(l2, s2) + and l1 == l2 then Arr(l1, ???) + else ??? + +fun mrg(s1: Array[Shape]) = ??? + +fun sel(s1: Shape, s2: Shape) = + if [s1, s2] is + [Class(c, shapes), Lit(n)] // n_i ? + and n is Int then shapes.n + [Dyn, Lit(n)] // n_i ? + and n is Int then Dyn + [Arr(l, shapes), Lit(n)] + and n is Int then shapes.n + [Dyn, Lit(n)] + and n is Int then Dyn + [Dyn, Dyn] then Dyn + _ then ??? + +fun static(s: Shape) = + if s is + Lit then true + Class | Dyn then false // c vs c() ? + _ then ??? + +module Pattern with... + +class Pattern with + constructor + Lit(val lit: Literal) + Class(val sym: Symbol) + Arr(val size: Int) + Wildcard + +fun silh(p: Pattern): Shape = if p is + Lit(l) then Shape.Lit(l) + // where to store size of argument array? + Class(sym) then Shape.Class(sym, ???) + // how to initialize array of Dyn? + Arr(n) then Shape.Arr(???) + Wildcard then Dyn + +fun match(s: Shape, p: Pattern): Option[Bool] = + if [s, p] is + [Shape.Lit(l1), Lit(l2)] then Some(true) + [Shape.Lit(l), Class(c)] and isPrimitiveTypeOf(c, l) then Some(true) + [Shape.Class(c1, _), Class(c2)] and c1 == c2 then Some(true) + [Shape.Arr(n1, _), Arr(n2)] and n1 == n2 then Some(true) + [_, Wildcard] then Some(true) + [Shape.Dyn, _] then None + _ then Some(false) + +fun det(s: Shape, ps: Array[Pattern]): Option[Bool] = + val a = ps.map(p => match(s, p) is Some(true)) + return ??? From f44b1675d23bb3430a92febf57aa23f082013265 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 1 Nov 2025 00:06:20 +0800 Subject: [PATCH 028/268] copy over more rules --- .../scala/hkmc2/codegen/Instrumentation.scala | 86 +++++++++++++------ 1 file changed, 62 insertions(+), 24 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 13811e9211..77686397ff 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -22,38 +22,44 @@ class Instrumentation(using State): case s: Str => Tree.StrLit(s) case n: BigDecimal => Tree.DecLit(n) Value.Lit(l) - + + // helper for staging the constructors + def end(l: Path): Block = Return(l, false) - def assign(res: Result, name: String = "tmp")(k: Path => Block): Block = + + def assign(res: Result, name: String = "tmp")(k: Path => Block): Block = val tmp = new TempSymbol(N, name) Assign(tmp, res, k(tmp.asPath)) - - // helper for staging the constructors in Block.scala to Block.mls - + + def extractResult(b: Block)(k: Path => Block): Block = + b.mapTail match + case Return(r, _) => assign(r)(k) + case _ => ??? // impossible + def stagedBlock(nme: String, args: Ls[Path | Symbol])(k: Path => Block): Block = val s = summon[State].blockSymbol.asPath.selSN(nme) assign(Instantiate(false, s, args.map(toArg)))(k) - def stagedShape(nme: String, args: Ls[Path | Symbol])(k: Path => Block): Block = + def stagedShape(nme: String, args: Ls[Path | Symbol])(k: Path => Block): Block = val s = summon[State].shapeSymbol.asPath.selSN(nme) assign(Instantiate(false, s, args.map(toArg)))(k) - // helpers for staging constructors in Block.mls + // helpers corresponding to constructors def stagedSymbol(nme: String)(k: Path => Block): Block = stagedBlock("Symbol", Ls(toValue(nme)))(k) - - def stagedIdent(nme: String)(k: Path => Block): Block = + + def stagedIdent(nme: String)(k: Path => Block): Block = stagedBlock("Ident", Ls(toValue(nme)))(k) - + def stagedRef(l: Symbol)(k: Path => Block): Block = stagedSymbol(l.nme): l => stagedBlock("ValueRef", Ls(l))(k) - + // note that this is for Block.ValueLit, not Shape.Lit def stagedBLit(l: Literal)(k: Path => Block): Block = stagedBlock("ValueLit", Ls(Value.Lit(l)))(k) - def stagedSelect(qual: Path, name: Str)(k: Path => Block): Block = + def stagedSelect(qual: Path, name: Str)(k: Path => Block): Block = stagedPath(qual): p => stagedIdent(name): i => stagedBlock("Select", Ls(p, i))(k) @@ -71,24 +77,56 @@ class Instrumentation(using State): case _ => ??? def stagedTuple(elems: Ls[Symbol | Path])(k: Path => Block): Block = - // TODO: staging array - stagedBlock("Tuple", Ls(???))(k) - + // is this the same as "Ls of"? + assign(Tuple(false, elems.map(toArg))): tup => + stagedBlock("Tuple", Ls(tup))(k) + // helpers to create and access the components of a staged value - def returnStagedValue(shape: Path, value: Path)(k: Path => Block): Block = - assign(Tuple(true, Ls(shape, value).map(toArg)))(k) - def getShape(l: Symbol)(k: Path => Block): Block = - assign(DynSelect(Value.Ref(l), toValue(0), false))(k) - def getBlock(l: Symbol)(k: Path => Block): Block = - assign(DynSelect(Value.Ref(l), toValue(1), false))(k) - + def returnPair(shape: Path, value: Path): Block = + assign(Tuple(true, Ls(shape, value).map(toArg)))(end) + def getShape(p: Path)(k: Path => Block): Block = assign(getShape2(p))(k) + def getCode(p: Path)(k: Path => Block): Block = assign(getCode2(p))(k) + def getShape2(p: Path): Path = DynSelect(p, toValue(0), false) + def getCode2(p: Path): Path = DynSelect(p, toValue(1), false) + // todo functions that fills out the holes in the functions above - + def stagedResult(res: Result)(k: Block => Block): Block = res match - case Call(fun, args) => ??? + case Call(fun, args) => ??? case res: Instantiate => ??? case Lambda(params, body) => ??? case Tuple(mut, elems) => ??? case Record(mut, elems) => ??? case p: Path => stagedPath(p) + def stagedArg(arg: Arg)(k: Path => Block): Block = + val stagedSpread = arg.spread match + case Some(value) => stagedBlock("Some", Ls(toValue(value))) + case None => stagedBlock("None", Ls()) + stagedSpread: s => + stagedPath(arg.value): v => + stagedTuple(Ls(s, v))(k) + + // functions that perform the instrumentation + + def ruleLit(l: Literal): Block = + stagedShape("Lit", Ls(Value.Lit(l))): sp => + stagedBlock("Lit", Ls(Value.Lit(l))): cde => + returnPair(sp, cde) + + def ruleVar(r: Value.Ref): Block = + // why not just use getShape2? + getShape(r): sp => + // why not just use r? + stagedBlock("ValueRef", Ls(toValue(r.l.nme))): cde => + returnPair(sp, cde) + + def ruleReturn(r: Return): Block = + transformResult(r.res): b => + extractResult(b): tmp => + getShape(tmp): sp => + stagedBlock("Return", Ls(getCode2(tmp))): cde => + returnPair(sp, cde) + + def transformResult(r: Result)(k: Block => Block): Block = + ??? From dcb0ed674c6dde0dec273049bc4db962064de8c4 Mon Sep 17 00:00:00 2001 From: TYeung Date: Sat, 1 Nov 2025 00:32:11 +0800 Subject: [PATCH 029/268] remove import of block inside MLsCompiler --- hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala | 1 - hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala b/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala index 886bcc66d0..95aedda0ec 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala @@ -88,7 +88,6 @@ class MLsCompiler(preludeFile: os.Path, mkOutput: ((Str => Unit) => Unit) => Uni val blk = new semantics.Term.Blk( semantics.Import(State.runtimeSymbol, runtimeFile.toString) :: semantics.Import(State.termSymbol, termFile.toString) - :: semantics.Import(State.termSymbol, termFile.toString) // TODO: always include this? :: blk0.stats, blk0.res ) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index f6375b22d9..a93b8f0fc3 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -63,8 +63,8 @@ object Printer: case fd @ FunDefn(own, sym, params, body) => val docParams = doc"${own.fold("")(_.toString+"::")}${params.map(_.params.map(x => summon[Scope].allocateName(x.sym)).mkString("(", ", ", ")")).mkString("")}" val docBody = mkDocument(body) - val docInstr = if fd.staged then doc"staged " else doc"" - doc"${docInstr}fun ${sym.nme}${docParams} { #{ # ${docBody} #} # }" + val docStaged = if fd.staged then doc"staged " else doc"" + doc"${docStaged}fun ${sym.nme}${docParams} { #{ # ${docBody} #} # }" case ValDefn(tsym, sym, rhs) => doc"val ${tsym.nme} = ${mkDocument(rhs)}" case ClsLikeDefn(own, _, sym, k, paramsOpt, auxParams, parentSym, methods, From bfac96d02261bd6aed5617afcdb6ceddf18f6e7c Mon Sep 17 00:00:00 2001 From: TYeung Date: Sat, 1 Nov 2025 00:33:50 +0800 Subject: [PATCH 030/268] update diff test result (for the staged annotation) --- hkmc2/shared/src/test/mlscript/codegen/FieldSymbols.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript/codegen/FieldSymbols.mls b/hkmc2/shared/src/test/mlscript/codegen/FieldSymbols.mls index 702afdc8d7..867c672bcf 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/FieldSymbols.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/FieldSymbols.mls @@ -90,7 +90,7 @@ case //│ Program: //│ imports = Nil //│ main = Define: -//│ defn = FunDefn: +//│ defn = FunDefn (staged=false): //│ owner = N //│ sym = member:lambda //│ params = Ls of From a81c0e9e1a464f41df3703fafc091284995e52f5 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:05:16 +0800 Subject: [PATCH 031/268] fix importing for Block.mls --- hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala | 1 + hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala | 1 + hkmc2/shared/src/test/mlscript-compile/Predef.mjs | 1 + hkmc2/shared/src/test/mlscript-compile/Runtime.mjs | 1 + 4 files changed, 4 insertions(+) diff --git a/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala b/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala index 95aedda0ec..54007a0df9 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala @@ -88,6 +88,7 @@ class MLsCompiler(preludeFile: os.Path, mkOutput: ((Str => Unit) => Unit) => Uni val blk = new semantics.Term.Blk( semantics.Import(State.runtimeSymbol, runtimeFile.toString) :: semantics.Import(State.termSymbol, termFile.toString) + :: semantics.Import(State.blockSymbol, blockFile.toString) :: blk0.stats, blk0.res ) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index 8bd6975e1d..cf1d8f2064 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -223,6 +223,7 @@ object Elaborator: val definitionMetadataSymbol = TempSymbol(N, "definitionMetadata") val prettyPrintSymbol = TempSymbol(N, "prettyPrint") val termSymbol = TempSymbol(N, "Term") + val blockSymbol = TempSymbol(N, "Block") val effectSigSymbol = ClassSymbol(DummyTypeDef(syntax.Cls), Ident("EffectSig")) val nonLocalRetHandlerTrm = val id = new Ident("NonLocalReturn") diff --git a/hkmc2/shared/src/test/mlscript-compile/Predef.mjs b/hkmc2/shared/src/test/mlscript-compile/Predef.mjs index d1a8d1fb79..c43f0fdf6d 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Predef.mjs +++ b/hkmc2/shared/src/test/mlscript-compile/Predef.mjs @@ -2,6 +2,7 @@ const definitionMetadata = globalThis.Symbol.for("mlscript.definitionMetadata"); const prettyPrint = globalThis.Symbol.for("mlscript.prettyPrint"); import runtime from "./Runtime.mjs"; import Term from "./Term.mjs"; +import Block from "./Block.mjs"; import RuntimeJS from "./RuntimeJS.mjs"; import Runtime from "./Runtime.mjs"; import Rendering from "./Rendering.mjs"; diff --git a/hkmc2/shared/src/test/mlscript-compile/Runtime.mjs b/hkmc2/shared/src/test/mlscript-compile/Runtime.mjs index 7b1c3e8013..250868463e 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Runtime.mjs +++ b/hkmc2/shared/src/test/mlscript-compile/Runtime.mjs @@ -2,6 +2,7 @@ const definitionMetadata = globalThis.Symbol.for("mlscript.definitionMetadata"); const prettyPrint = globalThis.Symbol.for("mlscript.prettyPrint"); import runtime from "./Runtime.mjs"; import Term from "./Term.mjs"; +import Block from "./Block.mjs"; import RuntimeJS from "./RuntimeJS.mjs"; import Rendering from "./Rendering.mjs"; import LazyArray from "./LazyArray.mjs"; From 4b0fa4529e3660eade4d1b316b0a43b3307dcdd5 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 1 Nov 2025 17:53:05 +0800 Subject: [PATCH 032/268] draft ruleInst --- .../scala/hkmc2/codegen/Instrumentation.scala | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 77686397ff..354be38b58 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -128,5 +128,50 @@ class Instrumentation(using State): stagedBlock("Return", Ls(getCode2(tmp))): cde => returnPair(sp, cde) + def ruleInst(i: Instantiate): Block = + val Instantiate(mut, cls, args) = i + assert(!mut) + // the problem here is i can't accumulate the results? + val a0 = (f: List[Path] => Block) => + (transformArg(args(0)): + _.mapTail { + case Return(r, _) => + assign(r): p => + f(Ls(p)) + case _ => ??? + } + ) + + val a1 = (f: List[Path] => Block) => + a0: ls => + transformArg(args(1)): + _.mapTail { + case Return(r, _) => + assign(r): p => + f(p :: ls) + case _ => ??? + } + + val a2 = (f: List[Path] => Block) => + a1: ls => + transformArg(args(2)): + _.mapTail { + case Return(r, _) => + assign(r): p => + f(p :: ls) + case _ => ??? + } + + val res = a2(ls => Return(Tuple(false, ls.reverse.map(toArg)), false)) + ??? + + val as = args.map(transformArg) + // collect paths from each transformed arg + + ??? + def transformResult(r: Result)(k: Block => Block): Block = ??? + + def transformArg(p: Arg)(k: Block => Block): Block = + ??? From 3761d19afeef9a5b3483ec44b4b258dbc401f6cf Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 1 Nov 2025 17:54:30 +0800 Subject: [PATCH 033/268] generalize recursion --- .../scala/hkmc2/codegen/Instrumentation.scala | 47 +++++-------------- 1 file changed, 12 insertions(+), 35 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 354be38b58..44b9b9c26b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -131,42 +131,19 @@ class Instrumentation(using State): def ruleInst(i: Instantiate): Block = val Instantiate(mut, cls, args) = i assert(!mut) - // the problem here is i can't accumulate the results? - val a0 = (f: List[Path] => Block) => - (transformArg(args(0)): - _.mapTail { - case Return(r, _) => - assign(r): p => - f(Ls(p)) - case _ => ??? - } - ) - - val a1 = (f: List[Path] => Block) => - a0: ls => - transformArg(args(1)): - _.mapTail { - case Return(r, _) => - assign(r): p => - f(p :: ls) - case _ => ??? - } - - val a2 = (f: List[Path] => Block) => - a1: ls => - transformArg(args(2)): - _.mapTail { - case Return(r, _) => - assign(r): p => - f(p :: ls) - case _ => ??? - } - - val res = a2(ls => Return(Tuple(false, ls.reverse.map(toArg)), false)) - ??? - val as = args.map(transformArg) - // collect paths from each transformed arg + def rec(f: List[Path] => Block, a: Arg, rest: Ls[Path]) = + transformArg(a): b => + extractResult(b): p => + f(p :: rest) + + // collect up path for all args into a list + val a = args.foldRight((f: List[Path] => Block) => f(Nil))((a, acc) => f => acc(rec(f, a, _))) + val b = a: args => + ??? + + // val as = args.map(transformArg) + // collect paths from each transformed arg ??? From 3ca8a988ca9dd638f1db526267fe69ac513cdcdb Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 00:00:55 +0800 Subject: [PATCH 034/268] add more rules --- .../scala/hkmc2/codegen/Instrumentation.scala | 75 ++++++++++++++++--- 1 file changed, 63 insertions(+), 12 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 44b9b9c26b..00ebcddc16 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -98,7 +98,10 @@ class Instrumentation(using State): case Tuple(mut, elems) => ??? case Record(mut, elems) => ??? case p: Path => stagedPath(p) - + + // probably wrong signature + def stagedPath(p: Path): Block = ??? + def stagedArg(arg: Arg)(k: Path => Block): Block = val stagedSpread = arg.spread match case Some(value) => stagedBlock("Some", Ls(toValue(value))) @@ -121,6 +124,17 @@ class Instrumentation(using State): stagedBlock("ValueRef", Ls(toValue(r.l.nme))): cde => returnPair(sp, cde) + def ruleSel(s: Select): Block = + val Select(p, Tree.Ident(a)) = s + transformPath(p): b => + extractResult(b): x => + // TODO: how to format a? + val sel = ??? + val n = ??? + assign(Call(sel, Ls(getShape2(x), n).map(toArg))(true, false)): sp => + stagedSelect(getCode2(x), a): cde => + returnPair(sp, cde) + def ruleReturn(r: Return): Block = transformResult(r.res): b => extractResult(b): tmp => @@ -132,23 +146,60 @@ class Instrumentation(using State): val Instantiate(mut, cls, args) = i assert(!mut) - def rec(f: List[Path] => Block, a: Arg, rest: Ls[Path]) = + // collect (shape, code) pair for each arg + def rec(f: List[(Path, Path)] => Block, a: Arg, rest: Ls[(Path, Path)]) = transformArg(a): b => extractResult(b): p => - f(p :: rest) - + getShape(p): sh => + getCode(p): cde => + f((sh, cde) :: rest) + + // // can you collect element wise? + // val paths = args.map(a => + // (k: Path => Block) => + // transformArg(a): b => + // extractResult(b)(k) + // ) // collect up path for all args into a list - val a = args.foldRight((f: List[Path] => Block) => f(Nil))((a, acc) => f => acc(rec(f, a, _))) - val b = a: args => - ??? - - // val as = args.map(transformArg) - // collect paths from each transformed arg - - ??? + args.foldRight((f: List[(Path, Path)] => Block) => f(Nil))((a, acc) => + f => acc(rest => rec(f, a, rest)) + ): ps => + val (shapes, codes) = ps.unzip + stagedTuple(shapes): shapes => + stagedTuple(codes): codes => + stagedShape("Class", Ls(cls, shapes)): sp => + stagedBlock("Instantiate", Ls(cls, codes)): cde => + returnPair(sp, cde) + + def ruleVal(defn: ValDefn, rest: Block): Block = + val ValDefn(_, sym, rhs) = defn + transformPath(rhs): b => + extractResult(b): y => + transformBlock(rest): b => + extractResult(b): z => + // TODO: valdefn needs to be before code blocks? + Define( + ValDefn(???, sym, y), + getShape(z): sp => + stagedSymbol("x"): x => + stagedBlock("ValDefn", Ls(x, getCode2(y))): df => + stagedBlock("Define", Ls(df, getCode2(z))): cde => + returnPair(sp, cde) + ) + + def transformPath(p: Path)(k: Block => Block): Block = + p match + // case Select(p, ident) => ??? + // case DynSelect(qual, fld, arrayIdx) => ??? + case r: Value.Ref => ruleVar(r) + case Value.Lit(lit) => ruleLit(lit) + case _ => ??? def transformResult(r: Result)(k: Block => Block): Block = ??? def transformArg(p: Arg)(k: Block => Block): Block = ??? + + def transformBlock(b: Block)(k: Block => Block): Block = ??? + From 71d5df3521c1e3d56918df0ba2f3907e78fed326 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 00:16:46 +0800 Subject: [PATCH 035/268] remove length parameter from Shape.Arr --- hkmc2/shared/src/test/mlscript-compile/Shape.mls | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index 058ec92344..df9304d468 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -13,7 +13,7 @@ class Shape with constructor Dyn Lit(val l: Literal) - Arr(val length: Int, val shapes: Array[Shape]) + Arr(val shapes: Array[Shape]) // is length parameter needed? // TODO: change sym to accept multiple possible class symbols Class(val sym: Symbol, val shapes: Array[Shape]) Unit @@ -33,8 +33,8 @@ fun mrg2(s1: Shape, s2: Shape) = if s1 and isPrimitiveTypeOf(sym, l) then Class(sym, shapes) is Class(sym1, shapes1) and s2 is Class(sym2, shapes2) and sym1 == sym2 then Class(sym1, ???) - is Arr(l1, s1) and s2 is Arr(l2, s2) - and l1 == l2 then Arr(l1, ???) + is Arr(s1) and s2 is Arr(s2) + and s1.length == s2.length then Arr(???) else ??? fun mrg(s1: Array[Shape]) = ??? @@ -45,7 +45,7 @@ fun sel(s1: Shape, s2: Shape) = and n is Int then shapes.n [Dyn, Lit(n)] // n_i ? and n is Int then Dyn - [Arr(l, shapes), Lit(n)] + [Arr(shapes), Lit(n)] and n is Int then shapes.n [Dyn, Lit(n)] and n is Int then Dyn @@ -80,7 +80,7 @@ fun match(s: Shape, p: Pattern): Option[Bool] = [Shape.Lit(l1), Lit(l2)] then Some(true) [Shape.Lit(l), Class(c)] and isPrimitiveTypeOf(c, l) then Some(true) [Shape.Class(c1, _), Class(c2)] and c1 == c2 then Some(true) - [Shape.Arr(n1, _), Arr(n2)] and n1 == n2 then Some(true) + [Shape.Arr(ls), Arr(n)] and ls.length == n then Some(true) [_, Wildcard] then Some(true) [Shape.Dyn, _] then None _ then Some(false) From cca32c62ca2ee90759167745ae8120d4e85cc04b Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 00:29:46 +0800 Subject: [PATCH 036/268] stub all current rules --- .../scala/hkmc2/codegen/Instrumentation.scala | 131 ++++++++++++------ 1 file changed, 86 insertions(+), 45 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 00ebcddc16..24831f01ab 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -28,6 +28,7 @@ class Instrumentation(using State): def end(l: Path): Block = Return(l, false) def assign(res: Result, name: String = "tmp")(k: Path => Block): Block = + // TODO: skip assignment if res: Path? val tmp = new TempSymbol(N, name) Assign(tmp, res, k(tmp.asPath)) @@ -82,33 +83,38 @@ class Instrumentation(using State): stagedBlock("Tuple", Ls(tup))(k) // helpers to create and access the components of a staged value + // use getCode2 for spliced result, and getCode for code def returnPair(shape: Path, value: Path): Block = assign(Tuple(true, Ls(shape, value).map(toArg)))(end) def getShape(p: Path)(k: Path => Block): Block = assign(getShape2(p))(k) def getCode(p: Path)(k: Path => Block): Block = assign(getCode2(p))(k) + // can we just use getShape2 everywhere? def getShape2(p: Path): Path = DynSelect(p, toValue(0), false) def getCode2(p: Path): Path = DynSelect(p, toValue(1), false) + // simplifies transform-extract code + def extract(k: (Block => Block) => Block)(rest: Path => Block): Block = + k(extractResult(_)(rest)) // todo functions that fills out the holes in the functions above - def stagedResult(res: Result)(k: Block => Block): Block = res match - case Call(fun, args) => ??? - case res: Instantiate => ??? - case Lambda(params, body) => ??? - case Tuple(mut, elems) => ??? - case Record(mut, elems) => ??? - case p: Path => stagedPath(p) - - // probably wrong signature - def stagedPath(p: Path): Block = ??? - - def stagedArg(arg: Arg)(k: Path => Block): Block = - val stagedSpread = arg.spread match - case Some(value) => stagedBlock("Some", Ls(toValue(value))) - case None => stagedBlock("None", Ls()) - stagedSpread: s => - stagedPath(arg.value): v => - stagedTuple(Ls(s, v))(k) + // def stagedResult(res: Result)(k: Block => Block): Block = res match + // case Call(fun, args) => ??? + // case res: Instantiate => ??? + // case Lambda(params, body) => ??? + // case Tuple(mut, elems) => ??? + // case Record(mut, elems) => ??? + // case p: Path => stagedPath(p) + + // // probably wrong signature + // def stagedPath(p: Path): Block = ??? + + // def stagedArg(arg: Arg)(k: Path => Block): Block = + // val stagedSpread = arg.spread match + // case Some(value) => stagedBlock("Some", Ls(toValue(value))) + // case None => stagedBlock("None", Ls()) + // stagedSpread: s => + // stagedPath(arg.value): v => + // stagedTuple(Ls(s, v))(k) // functions that perform the instrumentation @@ -124,6 +130,16 @@ class Instrumentation(using State): stagedBlock("ValueRef", Ls(toValue(r.l.nme))): cde => returnPair(sp, cde) + def ruleTup(t: Tuple): Block = + val Tuple(mut, elems) = t + assert(!mut) + + transformArgs(elems): (shapes, codes) => + stagedTuple(shapes): shapes => + stagedShape("Arr", Ls(shapes)): sp => + assign(Tuple(false, codes.map(toArg))): cde => + returnPair(sp, cde) + def ruleSel(s: Select): Block = val Select(p, Tree.Ident(a)) = s transformPath(p): b => @@ -135,42 +151,39 @@ class Instrumentation(using State): stagedSelect(getCode2(x), a): cde => returnPair(sp, cde) - def ruleReturn(r: Return): Block = - transformResult(r.res): b => - extractResult(b): tmp => - getShape(tmp): sp => - stagedBlock("Return", Ls(getCode2(tmp))): cde => - returnPair(sp, cde) + def ruleDynSel(d: DynSelect): Block = ??? + + def ruleRefinedPath(p: Path): Block = ??? + + def ruleApp(c: Call): Block = ??? def ruleInst(i: Instantiate): Block = val Instantiate(mut, cls, args) = i assert(!mut) - // collect (shape, code) pair for each arg - def rec(f: List[(Path, Path)] => Block, a: Arg, rest: Ls[(Path, Path)]) = - transformArg(a): b => - extractResult(b): p => - getShape(p): sh => - getCode(p): cde => - f((sh, cde) :: rest) - - // // can you collect element wise? - // val paths = args.map(a => - // (k: Path => Block) => - // transformArg(a): b => - // extractResult(b)(k) - // ) - // collect up path for all args into a list - args.foldRight((f: List[(Path, Path)] => Block) => f(Nil))((a, acc) => - f => acc(rest => rec(f, a, rest)) - ): ps => - val (shapes, codes) = ps.unzip + transformArgs(args): (shapes, codes) => stagedTuple(shapes): shapes => stagedTuple(codes): codes => stagedShape("Class", Ls(cls, shapes)): sp => stagedBlock("Instantiate", Ls(cls, codes)): cde => returnPair(sp, cde) + def ruleReturn(r: Return): Block = + transformResult(r.res): b => + extractResult(b): tmp => + getShape(tmp): sp => + stagedBlock("Return", Ls(getCode2(tmp))): cde => + returnPair(sp, cde) + + def ruleMatch(m: Match): Block = ??? + + def ruleAssign(a: Assign): Block = ??? + + def ruleEnd(): Block = + stagedShape("Unit", Ls()): sp => + stagedBlock("End", Ls()): cde => + returnPair(sp, cde) + def ruleVal(defn: ValDefn, rest: Block): Block = val ValDefn(_, sym, rhs) = defn transformPath(rhs): b => @@ -187,6 +200,12 @@ class Instrumentation(using State): returnPair(sp, cde) ) + def ruleBlk(b: Block): Block = ??? + + def ruleCls(c: ClassLikeDef, rest: Block): Block = ??? + + // functions for instrumentation + def transformPath(p: Path)(k: Block => Block): Block = p match // case Select(p, ident) => ??? @@ -198,8 +217,30 @@ class Instrumentation(using State): def transformResult(r: Result)(k: Block => Block): Block = ??? - def transformArg(p: Arg)(k: Block => Block): Block = + def transformArg(a: Arg)(k: Block => Block): Block = ??? - def transformBlock(b: Block)(k: Block => Block): Block = ??? + // provides list of shapes and list of codes to continuation + def transformArgs(args: List[Arg])(k: (Ls[Path], Ls[Path]) => Block): Block = + // collect (shape, code) pair for each arg + def rec(f: List[(Path, Path)] => Block, a: Arg, rest: Ls[(Path, Path)]) = + transformArg(a): b => + extractResult(b): p => + getShape(p): sh => + getCode(p): cde => + f((sh, cde) :: rest) + + // can you collect element wise instead? + // val paths = args.map(a => + // (k: Path => Block) => + // transformArg(a): b => + // extractResult(b)(k) + // ) + // collect up path for all args into a list + args.foldRight((f: List[(Path, Path)] => Block) => f(Nil))((a, acc) => + f => acc(rest => rec(f, a, rest)) + ): ps => + val (shapes, codes) = ps.unzip + k(shapes, codes) + def transformBlock(b: Block)(k: Block => Block): Block = ??? From ea13fe3917fc0b145675596388afe58831b3828c Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 00:39:53 +0800 Subject: [PATCH 037/268] change transform* signature --- .../scala/hkmc2/codegen/Instrumentation.scala | 65 +++++++++---------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 24831f01ab..c5ab27ab48 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -142,14 +142,13 @@ class Instrumentation(using State): def ruleSel(s: Select): Block = val Select(p, Tree.Ident(a)) = s - transformPath(p): b => - extractResult(b): x => - // TODO: how to format a? - val sel = ??? - val n = ??? - assign(Call(sel, Ls(getShape2(x), n).map(toArg))(true, false)): sp => - stagedSelect(getCode2(x), a): cde => - returnPair(sp, cde) + transformPath(p): x => + // TODO: how to format a? + val sel = ??? + val n = ??? + assign(Call(sel, Ls(getShape2(x), n).map(toArg))(true, false)): sp => + stagedSelect(getCode2(x), a): cde => + returnPair(sp, cde) def ruleDynSel(d: DynSelect): Block = ??? @@ -169,11 +168,10 @@ class Instrumentation(using State): returnPair(sp, cde) def ruleReturn(r: Return): Block = - transformResult(r.res): b => - extractResult(b): tmp => - getShape(tmp): sp => - stagedBlock("Return", Ls(getCode2(tmp))): cde => - returnPair(sp, cde) + transformResult(r.res): x => + getShape(x): sp => + stagedBlock("Return", Ls(getCode2(x))): cde => + returnPair(sp, cde) def ruleMatch(m: Match): Block = ??? @@ -186,19 +184,17 @@ class Instrumentation(using State): def ruleVal(defn: ValDefn, rest: Block): Block = val ValDefn(_, sym, rhs) = defn - transformPath(rhs): b => - extractResult(b): y => - transformBlock(rest): b => - extractResult(b): z => - // TODO: valdefn needs to be before code blocks? - Define( - ValDefn(???, sym, y), - getShape(z): sp => - stagedSymbol("x"): x => - stagedBlock("ValDefn", Ls(x, getCode2(y))): df => - stagedBlock("Define", Ls(df, getCode2(z))): cde => - returnPair(sp, cde) - ) + transformPath(rhs): y => + transformBlock(rest): z => + // TODO: valdefn needs to be before code blocks? + Define( + ValDefn(???, sym, y), + getShape(z): sp => + stagedSymbol("x"): x => + stagedBlock("ValDefn", Ls(x, getCode2(y))): df => + stagedBlock("Define", Ls(df, getCode2(z))): cde => + returnPair(sp, cde) + ) def ruleBlk(b: Block): Block = ??? @@ -206,7 +202,7 @@ class Instrumentation(using State): // functions for instrumentation - def transformPath(p: Path)(k: Block => Block): Block = + def transformPath(p: Path)(k: Path => Block): Block = p match // case Select(p, ident) => ??? // case DynSelect(qual, fld, arrayIdx) => ??? @@ -214,21 +210,20 @@ class Instrumentation(using State): case Value.Lit(lit) => ruleLit(lit) case _ => ??? - def transformResult(r: Result)(k: Block => Block): Block = + def transformResult(r: Result)(k: Path => Block): Block = ??? - def transformArg(a: Arg)(k: Block => Block): Block = + def transformArg(a: Arg)(k: Path => Block): Block = ??? // provides list of shapes and list of codes to continuation def transformArgs(args: List[Arg])(k: (Ls[Path], Ls[Path]) => Block): Block = // collect (shape, code) pair for each arg def rec(f: List[(Path, Path)] => Block, a: Arg, rest: Ls[(Path, Path)]) = - transformArg(a): b => - extractResult(b): p => - getShape(p): sh => - getCode(p): cde => - f((sh, cde) :: rest) + transformArg(a): p => + getShape(p): sh => + getCode(p): cde => + f((sh, cde) :: rest) // can you collect element wise instead? // val paths = args.map(a => @@ -243,4 +238,4 @@ class Instrumentation(using State): val (shapes, codes) = ps.unzip k(shapes, codes) - def transformBlock(b: Block)(k: Block => Block): Block = ??? + def transformBlock(b: Block)(k: Path => Block): Block = ??? From 47919c47cbba39aaa42ed552a4c2e9cf0f7f7d27 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 00:51:58 +0800 Subject: [PATCH 038/268] change staged* to mls* --- .../scala/hkmc2/codegen/Instrumentation.scala | 116 +++++------------- 1 file changed, 30 insertions(+), 86 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index c5ab27ab48..b59fac6005 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -37,50 +37,25 @@ class Instrumentation(using State): case Return(r, _) => assign(r)(k) case _ => ??? // impossible - def stagedBlock(nme: String, args: Ls[Path | Symbol])(k: Path => Block): Block = + def mlsBlock(nme: String, args: Ls[Path | Symbol])(k: Path => Block): Block = val s = summon[State].blockSymbol.asPath.selSN(nme) assign(Instantiate(false, s, args.map(toArg)))(k) - def stagedShape(nme: String, args: Ls[Path | Symbol])(k: Path => Block): Block = + def mlsShape(nme: String, args: Ls[Path | Symbol])(k: Path => Block): Block = val s = summon[State].shapeSymbol.asPath.selSN(nme) assign(Instantiate(false, s, args.map(toArg)))(k) // helpers corresponding to constructors - def stagedSymbol(nme: String)(k: Path => Block): Block = - stagedBlock("Symbol", Ls(toValue(nme)))(k) + def mlsSymbol(nme: String)(k: Path => Block): Block = + mlsBlock("Symbol", Ls(toValue(nme)))(k) - def stagedIdent(nme: String)(k: Path => Block): Block = - stagedBlock("Ident", Ls(toValue(nme)))(k) + def mlsSelect(qual: Path, ident: Tree.Ident)(k: Path => Block): Block = + // unnecessary assignment? + assign(Select(qual, ident)(N))(k) - def stagedRef(l: Symbol)(k: Path => Block): Block = - stagedSymbol(l.nme): l => - stagedBlock("ValueRef", Ls(l))(k) - - // note that this is for Block.ValueLit, not Shape.Lit - def stagedBLit(l: Literal)(k: Path => Block): Block = - stagedBlock("ValueLit", Ls(Value.Lit(l)))(k) - - def stagedSelect(qual: Path, name: Str)(k: Path => Block): Block = - stagedPath(qual): p => - stagedIdent(name): i => - stagedBlock("Select", Ls(p, i))(k) - - def stagedDynSelect(qual: Path, fld: Path, arrayIdx: Bool)(k: Path => Block): Block = - stagedPath(qual): q => - stagedPath(fld): f => - stagedBlock("DynSelect", Ls(q, f, toValue(arrayIdx)))(k) - - def stagedPath(p: Path)(k: Path => Block): Block = p match - case Select(qual, tree) => stagedSelect(qual, tree.name)(k) - case DynSelect(qual, fld, arrayIdx) => stagedDynSelect(qual, fld, arrayIdx)(k) - case Value.Ref(l) => stagedRef(l)(k) - case Value.Lit(lit) => stagedBLit(lit)(k) - case _ => ??? - - def stagedTuple(elems: Ls[Symbol | Path])(k: Path => Block): Block = + def mlsTuple(elems: Ls[Symbol | Path])(k: Path => Block): Block = // is this the same as "Ls of"? - assign(Tuple(false, elems.map(toArg))): tup => - stagedBlock("Tuple", Ls(tup))(k) + assign(Tuple(false, elems.map(toArg)))(k) // helpers to create and access the components of a staged value // use getCode2 for spliced result, and getCode for code @@ -91,43 +66,19 @@ class Instrumentation(using State): // can we just use getShape2 everywhere? def getShape2(p: Path): Path = DynSelect(p, toValue(0), false) def getCode2(p: Path): Path = DynSelect(p, toValue(1), false) - // simplifies transform-extract code - def extract(k: (Block => Block) => Block)(rest: Path => Block): Block = - k(extractResult(_)(rest)) - - // todo functions that fills out the holes in the functions above - - // def stagedResult(res: Result)(k: Block => Block): Block = res match - // case Call(fun, args) => ??? - // case res: Instantiate => ??? - // case Lambda(params, body) => ??? - // case Tuple(mut, elems) => ??? - // case Record(mut, elems) => ??? - // case p: Path => stagedPath(p) - - // // probably wrong signature - // def stagedPath(p: Path): Block = ??? - - // def stagedArg(arg: Arg)(k: Path => Block): Block = - // val stagedSpread = arg.spread match - // case Some(value) => stagedBlock("Some", Ls(toValue(value))) - // case None => stagedBlock("None", Ls()) - // stagedSpread: s => - // stagedPath(arg.value): v => - // stagedTuple(Ls(s, v))(k) // functions that perform the instrumentation def ruleLit(l: Literal): Block = - stagedShape("Lit", Ls(Value.Lit(l))): sp => - stagedBlock("Lit", Ls(Value.Lit(l))): cde => + mlsShape("Lit", Ls(Value.Lit(l))): sp => + mlsBlock("Lit", Ls(Value.Lit(l))): cde => returnPair(sp, cde) def ruleVar(r: Value.Ref): Block = // why not just use getShape2? getShape(r): sp => // why not just use r? - stagedBlock("ValueRef", Ls(toValue(r.l.nme))): cde => + mlsBlock("ValueRef", Ls(toValue(r.l.nme))): cde => returnPair(sp, cde) def ruleTup(t: Tuple): Block = @@ -135,19 +86,19 @@ class Instrumentation(using State): assert(!mut) transformArgs(elems): (shapes, codes) => - stagedTuple(shapes): shapes => - stagedShape("Arr", Ls(shapes)): sp => + mlsTuple(shapes): shapes => + mlsShape("Arr", Ls(shapes)): sp => assign(Tuple(false, codes.map(toArg))): cde => returnPair(sp, cde) def ruleSel(s: Select): Block = - val Select(p, Tree.Ident(a)) = s + val Select(p, i) = s transformPath(p): x => // TODO: how to format a? val sel = ??? val n = ??? assign(Call(sel, Ls(getShape2(x), n).map(toArg))(true, false)): sp => - stagedSelect(getCode2(x), a): cde => + mlsSelect(getCode2(x), i): cde => returnPair(sp, cde) def ruleDynSel(d: DynSelect): Block = ??? @@ -161,16 +112,16 @@ class Instrumentation(using State): assert(!mut) transformArgs(args): (shapes, codes) => - stagedTuple(shapes): shapes => - stagedTuple(codes): codes => - stagedShape("Class", Ls(cls, shapes)): sp => - stagedBlock("Instantiate", Ls(cls, codes)): cde => + mlsTuple(shapes): shapes => + mlsTuple(codes): codes => + mlsShape("Class", Ls(cls, shapes)): sp => + mlsBlock("Instantiate", Ls(cls, codes)): cde => returnPair(sp, cde) def ruleReturn(r: Return): Block = transformResult(r.res): x => getShape(x): sp => - stagedBlock("Return", Ls(getCode2(x))): cde => + mlsBlock("Return", Ls(getCode2(x))): cde => returnPair(sp, cde) def ruleMatch(m: Match): Block = ??? @@ -178,23 +129,21 @@ class Instrumentation(using State): def ruleAssign(a: Assign): Block = ??? def ruleEnd(): Block = - stagedShape("Unit", Ls()): sp => - stagedBlock("End", Ls()): cde => + mlsShape("Unit", Ls()): sp => + mlsBlock("End", Ls()): cde => returnPair(sp, cde) def ruleVal(defn: ValDefn, rest: Block): Block = - val ValDefn(_, sym, rhs) = defn + val ValDefn(tsym, sym, rhs) = defn transformPath(rhs): y => transformBlock(rest): z => - // TODO: valdefn needs to be before code blocks? - Define( - ValDefn(???, sym, y), + // TODO: valdefn needs to be before code blocks somehow? + (rest => Define(ValDefn(tsym, sym, y), rest)): getShape(z): sp => - stagedSymbol("x"): x => - stagedBlock("ValDefn", Ls(x, getCode2(y))): df => - stagedBlock("Define", Ls(df, getCode2(z))): cde => + mlsSymbol("x"): x => + mlsBlock("ValDefn", Ls(x, getCode2(y))): df => + mlsBlock("Define", Ls(df, getCode2(z))): cde => returnPair(sp, cde) - ) def ruleBlk(b: Block): Block = ??? @@ -225,13 +174,8 @@ class Instrumentation(using State): getCode(p): cde => f((sh, cde) :: rest) - // can you collect element wise instead? - // val paths = args.map(a => - // (k: Path => Block) => - // transformArg(a): b => - // extractResult(b)(k) - // ) // collect up path for all args into a list + // can you collect element wise instead? args.foldRight((f: List[(Path, Path)] => Block) => f(Nil))((a, acc) => f => acc(rest => rec(f, a, rest)) ): ps => From 217fb90b83e2ce5738d420c0e4ddb58b36324da2 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 01:03:34 +0800 Subject: [PATCH 039/268] simplify getShape, getCode --- .../scala/hkmc2/codegen/Instrumentation.scala | 50 ++++++++----------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index b59fac6005..6d0530bbf5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -60,12 +60,9 @@ class Instrumentation(using State): // helpers to create and access the components of a staged value // use getCode2 for spliced result, and getCode for code def returnPair(shape: Path, value: Path): Block = - assign(Tuple(true, Ls(shape, value).map(toArg)))(end) - def getShape(p: Path)(k: Path => Block): Block = assign(getShape2(p))(k) - def getCode(p: Path)(k: Path => Block): Block = assign(getCode2(p))(k) - // can we just use getShape2 everywhere? - def getShape2(p: Path): Path = DynSelect(p, toValue(0), false) - def getCode2(p: Path): Path = DynSelect(p, toValue(1), false) + mlsTuple(Ls(shape, value))(end) + def getShape(p: Path): Path = DynSelect(p, toValue(0), false) + def getCode(p: Path): Path = DynSelect(p, toValue(1), false) // functions that perform the instrumentation @@ -75,11 +72,9 @@ class Instrumentation(using State): returnPair(sp, cde) def ruleVar(r: Value.Ref): Block = - // why not just use getShape2? - getShape(r): sp => - // why not just use r? - mlsBlock("ValueRef", Ls(toValue(r.l.nme))): cde => - returnPair(sp, cde) + // why not just use r? + mlsBlock("ValueRef", Ls(toValue(r.l.nme))): cde => + returnPair(getShape(r), cde) def ruleTup(t: Tuple): Block = val Tuple(mut, elems) = t @@ -97,8 +92,8 @@ class Instrumentation(using State): // TODO: how to format a? val sel = ??? val n = ??? - assign(Call(sel, Ls(getShape2(x), n).map(toArg))(true, false)): sp => - mlsSelect(getCode2(x), i): cde => + assign(Call(sel, Ls(getShape(x), n).map(toArg))(true, false)): sp => + mlsSelect(getCode(x), i): cde => returnPair(sp, cde) def ruleDynSel(d: DynSelect): Block = ??? @@ -120,9 +115,8 @@ class Instrumentation(using State): def ruleReturn(r: Return): Block = transformResult(r.res): x => - getShape(x): sp => - mlsBlock("Return", Ls(getCode2(x))): cde => - returnPair(sp, cde) + mlsBlock("Return", Ls(getCode(x))): cde => + returnPair(getShape(x), cde) def ruleMatch(m: Match): Block = ??? @@ -138,12 +132,11 @@ class Instrumentation(using State): transformPath(rhs): y => transformBlock(rest): z => // TODO: valdefn needs to be before code blocks somehow? - (rest => Define(ValDefn(tsym, sym, y), rest)): - getShape(z): sp => - mlsSymbol("x"): x => - mlsBlock("ValDefn", Ls(x, getCode2(y))): df => - mlsBlock("Define", Ls(df, getCode2(z))): cde => - returnPair(sp, cde) + (Define(ValDefn(tsym, sym, y), _)): + mlsSymbol("x"): x => + mlsBlock("ValDefn", Ls(x, getCode(y))): df => + mlsBlock("Define", Ls(df, getCode(z))): cde => + returnPair(getShape(z), cde) def ruleBlk(b: Block): Block = ??? @@ -170,16 +163,13 @@ class Instrumentation(using State): // collect (shape, code) pair for each arg def rec(f: List[(Path, Path)] => Block, a: Arg, rest: Ls[(Path, Path)]) = transformArg(a): p => - getShape(p): sh => - getCode(p): cde => - f((sh, cde) :: rest) + f((getShape(p), getCode(p)) :: rest) // collect up path for all args into a list // can you collect element wise instead? - args.foldRight((f: List[(Path, Path)] => Block) => f(Nil))((a, acc) => - f => acc(rest => rec(f, a, rest)) - ): ps => - val (shapes, codes) = ps.unzip - k(shapes, codes) + args.foldRight((f: List[(Path, Path)] => Block) => f(Nil))((a, acc) => f => acc(rec(f, a, _))): + ps => + val (shapes, codes) = ps.unzip + k(shapes, codes) def transformBlock(b: Block)(k: Path => Block): Block = ??? From 3827db5ba43052747e25703ee2f57176b4bc23d2 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 13:29:56 +0800 Subject: [PATCH 040/268] reword transformArgs --- .../scala/hkmc2/codegen/Instrumentation.scala | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 6d0530bbf5..1ec69b8a9a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -160,16 +160,17 @@ class Instrumentation(using State): // provides list of shapes and list of codes to continuation def transformArgs(args: List[Arg])(k: (Ls[Path], Ls[Path]) => Block): Block = - // collect (shape, code) pair for each arg - def rec(f: List[(Path, Path)] => Block, a: Arg, rest: Ls[(Path, Path)]) = - transformArg(a): p => - f((getShape(p), getCode(p)) :: rest) - - // collect up path for all args into a list - // can you collect element wise instead? - args.foldRight((f: List[(Path, Path)] => Block) => f(Nil))((a, acc) => f => acc(rec(f, a, _))): - ps => - val (shapes, codes) = ps.unzip + args + .map(transformArg) + // defer applying k while prepending new paths to the list + .foldRight((_: List[Path] => Block)(Nil))((pathCont, restCont) => + k => + pathCont: p => + restCont: rest => + k(p :: rest) + ): ps => + // collect (shape, code) pair for each arg + val (shapes, codes) = ps.map(p => (getShape(p), getCode(p))).unzip k(shapes, codes) def transformBlock(b: Block)(k: Path => Block): Block = ??? From 2d9c3d2e2296048a259f3d56e413b181988eb63d Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 15:47:21 +0800 Subject: [PATCH 041/268] remove extractResult --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 5 ----- 1 file changed, 5 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 1ec69b8a9a..3bbd518c19 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -32,11 +32,6 @@ class Instrumentation(using State): val tmp = new TempSymbol(N, name) Assign(tmp, res, k(tmp.asPath)) - def extractResult(b: Block)(k: Path => Block): Block = - b.mapTail match - case Return(r, _) => assign(r)(k) - case _ => ??? // impossible - def mlsBlock(nme: String, args: Ls[Path | Symbol])(k: Path => Block): Block = val s = summon[State].blockSymbol.asPath.selSN(nme) assign(Instantiate(false, s, args.map(toArg)))(k) From c5be8eccffb6f32ec4a89e670e2c799bd0652b43 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 16:47:23 +0800 Subject: [PATCH 042/268] introduce StagedPath --- .../scala/hkmc2/codegen/Instrumentation.scala | 114 ++++++++++-------- 1 file changed, 66 insertions(+), 48 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 3bbd518c19..d91c13e91b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -25,8 +25,6 @@ class Instrumentation(using State): // helper for staging the constructors - def end(l: Path): Block = Return(l, false) - def assign(res: Result, name: String = "tmp")(k: Path => Block): Block = // TODO: skip assignment if res: Path? val tmp = new TempSymbol(N, name) @@ -53,51 +51,61 @@ class Instrumentation(using State): assign(Tuple(false, elems.map(toArg)))(k) // helpers to create and access the components of a staged value - // use getCode2 for spliced result, and getCode for code - def returnPair(shape: Path, value: Path): Block = - mlsTuple(Ls(shape, value))(end) - def getShape(p: Path): Path = DynSelect(p, toValue(0), false) - def getCode(p: Path): Path = DynSelect(p, toValue(1), false) + class StagedPath(val p: Path): + def shape: Path = DynSelect(p, toValue(0), false) + def code: Path = DynSelect(p, toValue(1), false) + + object StagedPath: + def mk(shape: Path, code: Path)(k: StagedPath => Block): Block = + mlsTuple(Ls(shape, code))(p => k(StagedPath(p))) + // in some cases this can reduce the indentation level + def mk(shapeCont: (Path => Block) => Block, codeCont: (Path => Block) => Block)(k: StagedPath => Block): Block = + shapeCont: shape => + codeCont: code => + mk(shape, code)(k) + def end(sp: StagedPath): Block = Return(sp.p, false) // functions that perform the instrumentation - def ruleLit(l: Literal): Block = + def ruleLit(l: Literal)(k: StagedPath => Block): Block = mlsShape("Lit", Ls(Value.Lit(l))): sp => mlsBlock("Lit", Ls(Value.Lit(l))): cde => - returnPair(sp, cde) + StagedPath.mk(sp, cde)(k) - def ruleVar(r: Value.Ref): Block = - // why not just use r? + def ruleVar(r: Value.Ref)(k: StagedPath => Block): Block = + // why assume it is already staged? + val sp = StagedPath(r) + // why not just use sp.code? mlsBlock("ValueRef", Ls(toValue(r.l.nme))): cde => - returnPair(getShape(r), cde) + StagedPath.mk(sp.shape, cde)(k) - def ruleTup(t: Tuple): Block = + def ruleTup(t: Tuple)(k: StagedPath => Block): Block = val Tuple(mut, elems) = t assert(!mut) transformArgs(elems): (shapes, codes) => mlsTuple(shapes): shapes => mlsShape("Arr", Ls(shapes)): sp => - assign(Tuple(false, codes.map(toArg))): cde => - returnPair(sp, cde) + mlsTuple(codes): cde => // is Tuple quotes as well? + StagedPath.mk(sp, cde)(k) - def ruleSel(s: Select): Block = + def ruleSel(s: Select)(k: StagedPath => Block): Block = val Select(p, i) = s transformPath(p): x => // TODO: how to format a? val sel = ??? val n = ??? - assign(Call(sel, Ls(getShape(x), n).map(toArg))(true, false)): sp => - mlsSelect(getCode(x), i): cde => - returnPair(sp, cde) + assign(Call(sel, Ls(x.shape, n).map(toArg))(true, false)): sp => + mlsSelect(x.code, i): cde => + StagedPath.mk(sp, cde)(k) - def ruleDynSel(d: DynSelect): Block = ??? + def ruleDynSel(d: DynSelect)(k: StagedPath => Block): Block = ??? - def ruleRefinedPath(p: Path): Block = ??? + def ruleRefinedPath(p: Path)(k: StagedPath => Block): Block = ??? - def ruleApp(c: Call): Block = ??? + def ruleApp(c: Call)(k: StagedPath => Block): Block = ??? - def ruleInst(i: Instantiate): Block = + def ruleInst(i: Instantiate)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i assert(!mut) @@ -106,66 +114,76 @@ class Instrumentation(using State): mlsTuple(codes): codes => mlsShape("Class", Ls(cls, shapes)): sp => mlsBlock("Instantiate", Ls(cls, codes)): cde => - returnPair(sp, cde) + StagedPath.mk(sp, cde)(k) - def ruleReturn(r: Return): Block = + def ruleReturn(r: Return)(k: StagedPath => Block): Block = transformResult(r.res): x => - mlsBlock("Return", Ls(getCode(x))): cde => - returnPair(getShape(x), cde) + mlsBlock("Return", Ls(x.code)): cde => + StagedPath.mk(x.shape, cde)(k) - def ruleMatch(m: Match): Block = ??? + def ruleMatch(m: Match)(k: StagedPath => Block): Block = ??? - def ruleAssign(a: Assign): Block = ??? + def ruleAssign(a: Assign)(k: StagedPath => Block): Block = ??? - def ruleEnd(): Block = + def ruleEnd()(k: StagedPath => Block): Block = mlsShape("Unit", Ls()): sp => mlsBlock("End", Ls()): cde => - returnPair(sp, cde) + StagedPath.mk(sp, cde)(k) - def ruleVal(defn: ValDefn, rest: Block): Block = + def ruleVal(defn: ValDefn, rest: Block)(k: StagedPath => Block): Block = val ValDefn(tsym, sym, rhs) = defn transformPath(rhs): y => transformBlock(rest): z => // TODO: valdefn needs to be before code blocks somehow? - (Define(ValDefn(tsym, sym, y), _)): + // y is StagedPath, not Path? + (Define(ValDefn(tsym, sym, y.p), _)): mlsSymbol("x"): x => - mlsBlock("ValDefn", Ls(x, getCode(y))): df => - mlsBlock("Define", Ls(df, getCode(z))): cde => - returnPair(getShape(z), cde) + mlsBlock("ValDefn", Ls(x, y.code)): df => + mlsBlock("Define", Ls(df, z.code)): cde => + StagedPath.mk(z.shape, cde)(k) - def ruleBlk(b: Block): Block = ??? + def ruleBlk(b: Block)(k: StagedPath => Block): Block = ??? - def ruleCls(c: ClassLikeDef, rest: Block): Block = ??? + def ruleCls(c: ClassLikeDef, rest: Block)(k: StagedPath => Block): Block = ??? // functions for instrumentation - def transformPath(p: Path)(k: Path => Block): Block = + def transformPath(p: Path)(k: StagedPath => Block): Block = p match // case Select(p, ident) => ??? // case DynSelect(qual, fld, arrayIdx) => ??? - case r: Value.Ref => ruleVar(r) - case Value.Lit(lit) => ruleLit(lit) + case r: Value.Ref => ruleVar(r)(k) + case Value.Lit(lit) => ruleLit(lit)(k) case _ => ??? - def transformResult(r: Result)(k: Path => Block): Block = - ??? + def transformResult(r: Result)(k: StagedPath => Block): Block = + r match + case Call(name, args) => ??? + case Instantiate(mut, cls, args) => ??? + case Lambda(params, body) => ??? + case Tuple(mut, elems) => ??? + case Record(mut, elems) => ??? + case p: Path => transformPath(p)(k) + + def transformArg(a: Arg)(k: StagedPath => Block): Block = + val Arg(spread, value) = a + ??? // arg has no shape of its own? - def transformArg(a: Arg)(k: Path => Block): Block = - ??? + transformPath(value)(k) // provides list of shapes and list of codes to continuation def transformArgs(args: List[Arg])(k: (Ls[Path], Ls[Path]) => Block): Block = args .map(transformArg) // defer applying k while prepending new paths to the list - .foldRight((_: List[Path] => Block)(Nil))((pathCont, restCont) => + .foldRight((_: List[StagedPath] => Block)(Nil))((pathCont, restCont) => k => pathCont: p => restCont: rest => k(p :: rest) ): ps => // collect (shape, code) pair for each arg - val (shapes, codes) = ps.map(p => (getShape(p), getCode(p))).unzip + val (shapes, codes) = ps.map(p => (p.shape, p.code)).unzip k(shapes, codes) - def transformBlock(b: Block)(k: Path => Block): Block = ??? + def transformBlock(b: Block)(k: StagedPath => Block): Block = ??? From b4eaf5c5e311cc649f0555336c7fa0acd18e1d91 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 17:38:47 +0800 Subject: [PATCH 043/268] introduce Shape --- .../scala/hkmc2/codegen/Instrumentation.scala | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index d91c13e91b..4c2b8c6d82 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -9,10 +9,13 @@ import semantics.Elaborator.State import syntax.{Literal, Tree} class Instrumentation(using State): - def toArg(x: Path | Symbol): Arg = + type PathLike = Path | Symbol | Shape + + def asArg(x: PathLike): Arg = x match - case p: Path => Arg(N, p) - case l: Symbol => Arg(N, l.asPath) + case p: Path => p.asArg + case l: Symbol => l.asPath.asArg + case Shape(p) => p.asArg // null and undefined are missing def toValue(lit: Str | Int | BigDecimal | Bool): Value = @@ -30,12 +33,12 @@ class Instrumentation(using State): val tmp = new TempSymbol(N, name) Assign(tmp, res, k(tmp.asPath)) - def mlsBlock(nme: String, args: Ls[Path | Symbol])(k: Path => Block): Block = + def mlsBlock(nme: String, args: Ls[PathLike])(k: Path => Block): Block = val s = summon[State].blockSymbol.asPath.selSN(nme) - assign(Instantiate(false, s, args.map(toArg)))(k) - def mlsShape(nme: String, args: Ls[Path | Symbol])(k: Path => Block): Block = + assign(Instantiate(false, s, args.map(asArg)))(k) + def mlsShape(nme: String, args: Ls[PathLike])(k: Shape => Block): Block = val s = summon[State].shapeSymbol.asPath.selSN(nme) - assign(Instantiate(false, s, args.map(toArg)))(k) + assign(Instantiate(false, s, args.map(asArg)))(p => k(Shape(p))) // helpers corresponding to constructors @@ -46,20 +49,24 @@ class Instrumentation(using State): // unnecessary assignment? assign(Select(qual, ident)(N))(k) - def mlsTuple(elems: Ls[Symbol | Path])(k: Path => Block): Block = + def mlsTuple(elems: Ls[PathLike])(k: Path => Block): Block = // is this the same as "Ls of"? - assign(Tuple(false, elems.map(toArg)))(k) + assign(Tuple(false, elems.map(asArg)))(k) + def mrg(shapes: Ls[Shape]) = () + // helpers to create and access the components of a staged value + case class Shape(val p: Path) + class StagedPath(val p: Path): - def shape: Path = DynSelect(p, toValue(0), false) + def shape: Shape = Shape(DynSelect(p, toValue(0), false)) def code: Path = DynSelect(p, toValue(1), false) object StagedPath: - def mk(shape: Path, code: Path)(k: StagedPath => Block): Block = - mlsTuple(Ls(shape, code))(p => k(StagedPath(p))) + def mk(shape: Shape, code: Path)(k: StagedPath => Block): Block = + mlsTuple(Ls(shape.p, code))(p => k(StagedPath(p))) // in some cases this can reduce the indentation level - def mk(shapeCont: (Path => Block) => Block, codeCont: (Path => Block) => Block)(k: StagedPath => Block): Block = + def mk(shapeCont: (Shape => Block) => Block, codeCont: (Path => Block) => Block)(k: StagedPath => Block): Block = shapeCont: shape => codeCont: code => mk(shape, code)(k) @@ -92,12 +99,15 @@ class Instrumentation(using State): def ruleSel(s: Select)(k: StagedPath => Block): Block = val Select(p, i) = s transformPath(p): x => + // TODO: how to format a? val sel = ??? val n = ??? - assign(Call(sel, Ls(x.shape, n).map(toArg))(true, false)): sp => - mlsSelect(x.code, i): cde => - StagedPath.mk(sp, cde)(k) + // can use shape.p? + // assign(Call(sel, Ls(x.shape, n).map(toArg))(true, false)): sp => + // mlsSelect(x.code, i): cde => + // StagedPath.mk(sp, cde)(k) + ??? def ruleDynSel(d: DynSelect)(k: StagedPath => Block): Block = ??? @@ -172,11 +182,11 @@ class Instrumentation(using State): transformPath(value)(k) // provides list of shapes and list of codes to continuation - def transformArgs(args: List[Arg])(k: (Ls[Path], Ls[Path]) => Block): Block = + def transformArgs(args: Ls[Arg])(k: (Ls[Shape], Ls[Path]) => Block): Block = args .map(transformArg) // defer applying k while prepending new paths to the list - .foldRight((_: List[StagedPath] => Block)(Nil))((pathCont, restCont) => + .foldRight((_: Ls[StagedPath] => Block)(Nil))((pathCont, restCont) => k => pathCont: p => restCont: rest => From 2563eca03682c68dfe55785a742041b60584c7e1 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 23:18:36 +0800 Subject: [PATCH 044/268] link to functions in Shape.mls --- .../scala/hkmc2/codegen/Instrumentation.scala | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 4c2b8c6d82..aaeafe5307 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -28,7 +28,8 @@ class Instrumentation(using State): // helper for staging the constructors - def assign(res: Result, name: String = "tmp")(k: Path => Block): Block = + // could use `using` to allow passthrough of names + def assign(res: Result, name: String = "tmp")(k: Path => Block): Assign = // TODO: skip assignment if res: Path? val tmp = new TempSymbol(N, name) Assign(tmp, res, k(tmp.asPath)) @@ -53,8 +54,9 @@ class Instrumentation(using State): // is this the same as "Ls of"? assign(Tuple(false, elems.map(asArg)))(k) - def mrg(shapes: Ls[Shape]) = () - + def mlsCall(fun: Path, args: Ls[PathLike], isMlsFun: Bool)(k: Path => Block): Block = + assign(Call(fun, args.map(asArg))(isMlsFun, false))(k) + // helpers to create and access the components of a staged value case class Shape(val p: Path) @@ -72,6 +74,28 @@ class Instrumentation(using State): mk(shape, code)(k) def end(sp: StagedPath): Block = Return(sp.p, false) + // linking functions defined in MLscipt + val mrgSymbol = new TempSymbol(N, "mrg") + val silhSymbol = new TempSymbol(N, "silh") + val matchSymbol = new TempSymbol(N, "match") + val selSymbol = new TempSymbol(N, "sel") + val staticSymbol = new TempSymbol(N, "static") + val compileSymbol = new TempSymbol(N, "compile") + + def fnMrg(shapes: Ls[Shape])(k: Shape => Block): Block = + mlsCall(mrgSymbol.asPath, shapes, true)(s => k(Shape(s))) + // TODO: make fnSilh take in a wrapped Path type + def fnSilh(pattern: Path)(k: Shape => Block) = + mlsCall(silhSymbol.asPath, Ls(pattern), true)(s => k(Shape(s))) + def fnMatch(s: Shape, pat: Path)(k: Path => Block) = + mlsCall(matchSymbol.asPath, Ls(s, pat), true)(k) + def fnSel(s1: Shape, s2: Shape)(k: Shape => Block): Block = + mlsCall(selSymbol.asPath, Ls(s1, s2), true)(s => k(Shape(s))) + def fnStatic(s: Shape)(k: Path => Block) = + mlsCall(staticSymbol.asPath, Ls(s), true)(k) + def fnCompile(x: Path)(k: StagedPath => Block): Block = + mlsCall(compileSymbol.asPath, Ls(x), true)(p => k(StagedPath(p))) + // functions that perform the instrumentation def ruleLit(l: Literal)(k: StagedPath => Block): Block = From edd7436acbc21bfef37252172424d686d0e27f1b Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 23:19:13 +0800 Subject: [PATCH 045/268] move function --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index aaeafe5307..490b11bc16 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -58,11 +58,13 @@ class Instrumentation(using State): assign(Call(fun, args.map(asArg))(isMlsFun, false))(k) // helpers to create and access the components of a staged value - case class Shape(val p: Path) + case class Shape(p: Path) + // A StagedPath is a path that points to a (shape, code) tuple class StagedPath(val p: Path): def shape: Shape = Shape(DynSelect(p, toValue(0), false)) def code: Path = DynSelect(p, toValue(1), false) + def end: Block = Return(p, false) object StagedPath: def mk(shape: Shape, code: Path)(k: StagedPath => Block): Block = @@ -72,7 +74,6 @@ class Instrumentation(using State): shapeCont: shape => codeCont: code => mk(shape, code)(k) - def end(sp: StagedPath): Block = Return(sp.p, false) // linking functions defined in MLscipt val mrgSymbol = new TempSymbol(N, "mrg") From c17c3e1a5a52d07e23672a95d87505957114eb42 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 23:19:52 +0800 Subject: [PATCH 046/268] implement more rules --- .../scala/hkmc2/codegen/Instrumentation.scala | 84 +++++++++++++------ 1 file changed, 58 insertions(+), 26 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 490b11bc16..fcc9465b72 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -122,19 +122,22 @@ class Instrumentation(using State): StagedPath.mk(sp, cde)(k) def ruleSel(s: Select)(k: StagedPath => Block): Block = - val Select(p, i) = s + val Select(p, i @ Tree.Ident(name)) = s transformPath(p): x => - - // TODO: how to format a? - val sel = ??? + // stage? there isn't a correct constructor for it though + // val n = Shape(Value.Ref(new TempSymbol(N, name))) val n = ??? - // can use shape.p? - // assign(Call(sel, Ls(x.shape, n).map(toArg))(true, false)): sp => - // mlsSelect(x.code, i): cde => - // StagedPath.mk(sp, cde)(k) - ??? - - def ruleDynSel(d: DynSelect)(k: StagedPath => Block): Block = ??? + fnSel(x.shape, n): sp => + mlsSelect(x.code, i): cde => + StagedPath.mk(sp, cde)(k) + + def ruleDynSel(d: DynSelect)(k: StagedPath => Block): Block = + val DynSelect(qual, path, arrayIdx) = d + transformPath(qual): x => + transformPath(path): y => + fnSel(x.shape, y.shape): sp => + mlsBlock("DynSelect", Ls(x.code, y.code, toValue(arrayIdx))): cde => + StagedPath.mk(sp, cde)(k) def ruleRefinedPath(p: Path)(k: StagedPath => Block): Block = ??? @@ -156,9 +159,19 @@ class Instrumentation(using State): mlsBlock("Return", Ls(x.code)): cde => StagedPath.mk(x.shape, cde)(k) - def ruleMatch(m: Match)(k: StagedPath => Block): Block = ??? + def ruleMatch(m: Match)(k: StagedPath => Block): Block = + val Match(p, arms, dflt, b) = m + transformPath(p): x => + ??? - def ruleAssign(a: Assign)(k: StagedPath => Block): Block = ??? + def ruleAssign(a: Assign)(k: StagedPath => Block): Block = + val Assign(x, r, b) = a + transformResult(r): y => + (Assign(x, y.p, _)): + transformBlock(b): z => + // need to wrap x with Symbol? + mlsBlock("Assign", Ls(x, y.code, z.code)): cde => + StagedPath.mk(z.shape, cde)(k) def ruleEnd()(k: StagedPath => Block): Block = mlsShape("Unit", Ls()): sp => @@ -177,37 +190,42 @@ class Instrumentation(using State): mlsBlock("Define", Ls(df, z.code)): cde => StagedPath.mk(z.shape, cde)(k) - def ruleBlk(b: Block)(k: StagedPath => Block): Block = ??? + def ruleBlk(b: Block)(k: StagedPath => Block): Block = + transformBlock(b): x => + fnCompile(x.code)(k) - def ruleCls(c: ClassLikeDef, rest: Block)(k: StagedPath => Block): Block = ??? + // g is Program? + def ruleCls(c: Program, rest: Block)(k: StagedPath => Block): Block = + // val ClsLikeDefn(_, _, ) + ??? // functions for instrumentation def transformPath(p: Path)(k: StagedPath => Block): Block = p match - // case Select(p, ident) => ??? - // case DynSelect(qual, fld, arrayIdx) => ??? + case s: Select => ruleSel(s)(k) + case d: DynSelect => ruleDynSel(d)(k) case r: Value.Ref => ruleVar(r)(k) case Value.Lit(lit) => ruleLit(lit)(k) - case _ => ??? + case _ => ??? // not supported def transformResult(r: Result)(k: StagedPath => Block): Block = r match - case Call(name, args) => ??? - case Instantiate(mut, cls, args) => ??? - case Lambda(params, body) => ??? - case Tuple(mut, elems) => ??? - case Record(mut, elems) => ??? + case c: Call => ruleApp(c)(k) + case i: Instantiate => ruleInst(i)(k) + case t: Tuple => ruleTup(t)(k) case p: Path => transformPath(p)(k) + case _ : Lambda | _: Record => ??? // not supported def transformArg(a: Arg)(k: StagedPath => Block): Block = val Arg(spread, value) = a - ??? // arg has no shape of its own? + ??? // arg has no shape of its own? it's just a wrapper for Path transformPath(value)(k) // provides list of shapes and list of codes to continuation def transformArgs(args: Ls[Arg])(k: (Ls[Shape], Ls[Path]) => Block): Block = + // TODO: use BlockTransformer.applyListOf? args .map(transformArg) // defer applying k while prepending new paths to the list @@ -220,5 +238,19 @@ class Instrumentation(using State): // collect (shape, code) pair for each arg val (shapes, codes) = ps.map(p => (p.shape, p.code)).unzip k(shapes, codes) - - def transformBlock(b: Block)(k: StagedPath => Block): Block = ??? + + def transformDefine(d: Define)(k: StagedPath => Block): Block = + d.defn match + case f: FunDefn => ??? + case v: ValDefn => ruleVal(v, d.rest)(k) + case c: ClsLikeDefn => ??? + + def transformBlock(b: Block)(k: StagedPath => Block): Block = + b match + case m: Match => ruleMatch(m)(k) + case r: Return => ruleReturn(r)(k) + case a: Assign => ruleAssign(a)(k) + case d: Define => transformDefine(d)(k) + case End(_) => ruleEnd()(k) + case l: Label => ??? + case _ => ??? // not supported From 369195f537a751669bc64eb9764e9479280ae5f4 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 23:51:51 +0800 Subject: [PATCH 047/268] add stubs for function instrumentation --- .../scala/hkmc2/codegen/Instrumentation.scala | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index fcc9465b72..66859262c2 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -76,6 +76,7 @@ class Instrumentation(using State): mk(shape, code)(k) // linking functions defined in MLscipt + val mrgSymbol = new TempSymbol(N, "mrg") val silhSymbol = new TempSymbol(N, "silh") val matchSymbol = new TempSymbol(N, "match") @@ -97,7 +98,26 @@ class Instrumentation(using State): def fnCompile(x: Path)(k: StagedPath => Block): Block = mlsCall(compileSymbol.asPath, Ls(x), true)(p => k(StagedPath(p))) - // functions that perform the instrumentation + // helpers for instrumenting functions + + def inst(f: StagedPath, args: Ls[StagedPath]): StagedPath = + if ??? then + // non-staged function + ??? + else + // staged function + ??? + + def instGlobal(f: StagedPath, args: Ls[StagedPath])(k: StagedPath => Block): Block = + def isFunction(p: Path) = ??? + if isFunction(f.p) then + k(inst(???, args)) + else + mlsShape("Dyn", Ls()): sp => + mlsCall(f.p, args.map(_.p), ???): cde => + StagedPath.mk(sp, cde)(k) + + // instrumentation rules def ruleLit(l: Literal)(k: StagedPath => Block): Block = mlsShape("Lit", Ls(Value.Lit(l))): sp => @@ -199,7 +219,7 @@ class Instrumentation(using State): // val ClsLikeDefn(_, _, ) ??? - // functions for instrumentation + // transformations of Block def transformPath(p: Path)(k: StagedPath => Block): Block = p match From ded726045f26bb53264ad3016989b01f48b30c0b Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 2 Nov 2025 23:53:38 +0800 Subject: [PATCH 048/268] add instrumentation context --- .../scala/hkmc2/codegen/Instrumentation.scala | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 66859262c2..d283e99a6e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -1,6 +1,8 @@ package hkmc2 package codegen +import scala.collection.mutable.HashMap + import mlscript.utils.*, shorthands.* import semantics.* @@ -8,9 +10,23 @@ import semantics.Elaborator.State import syntax.{Literal, Tree} +// TODO: I didn't use BlockTransformer here, because in some cases it constrains the type of the continuation +// but it seems some logic should be deferred to it to dedup code + +// it should be possible to convert to the BlockTransformer signatures, +// but it would require re-extracting and re-assigning StagedPath from the output. + +// the continuation would basically be solely dedicated to staging then? +// like, we do a transformation on DynSelect where we keep the fields inteact, then perform staging in the DynSelect => Block continuation? +// the previous blocks created by the fields are handled by BlockTransformer's continuation code + class Instrumentation(using State): + // A PathLike type is a type that can be turned into an Arg type PathLike = Path | Symbol | Shape + // is Elaborator.Ctx relevant? + type Context = HashMap[Path, Shape] + def asArg(x: PathLike): Arg = x match case p: Path => p.asArg From 5e08d178b7feb42ff5548bce0ed3b5968a2340e2 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 3 Nov 2025 00:11:51 +0800 Subject: [PATCH 049/268] refactor transformArgs --- .../scala/hkmc2/codegen/Instrumentation.scala | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index d283e99a6e..3327fe2d0a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -151,10 +151,10 @@ class Instrumentation(using State): val Tuple(mut, elems) = t assert(!mut) - transformArgs(elems): (shapes, codes) => - mlsTuple(shapes): shapes => + transformArgs(elems): xs => + mlsTuple(xs.map(_.shape)): shapes => mlsShape("Arr", Ls(shapes)): sp => - mlsTuple(codes): cde => // is Tuple quotes as well? + mlsTuple(xs.map(_.code)): cde => // is Tuple quotes as well? StagedPath.mk(sp, cde)(k) def ruleSel(s: Select)(k: StagedPath => Block): Block = @@ -177,15 +177,20 @@ class Instrumentation(using State): def ruleRefinedPath(p: Path)(k: StagedPath => Block): Block = ??? + // .apply is Call? def ruleApp(c: Call)(k: StagedPath => Block): Block = ??? + val Call(fun, args) = c + transformPath(fun): f => + transformArgs(args): xs => + instGlobal(f, xs)(k) def ruleInst(i: Instantiate)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i assert(!mut) - transformArgs(args): (shapes, codes) => - mlsTuple(shapes): shapes => - mlsTuple(codes): codes => + transformArgs(args): xs => + mlsTuple(xs.map(_.shape)): shapes => + mlsTuple(xs.map(_.code)): codes => mlsShape("Class", Ls(cls, shapes)): sp => mlsBlock("Instantiate", Ls(cls, codes)): cde => StagedPath.mk(sp, cde)(k) @@ -260,7 +265,7 @@ class Instrumentation(using State): transformPath(value)(k) // provides list of shapes and list of codes to continuation - def transformArgs(args: Ls[Arg])(k: (Ls[Shape], Ls[Path]) => Block): Block = + def transformArgs(args: Ls[Arg])(k: Ls[StagedPath] => Block): Block = // TODO: use BlockTransformer.applyListOf? args .map(transformArg) @@ -270,10 +275,7 @@ class Instrumentation(using State): pathCont: p => restCont: rest => k(p :: rest) - ): ps => - // collect (shape, code) pair for each arg - val (shapes, codes) = ps.map(p => (p.shape, p.code)).unzip - k(shapes, codes) + )(k) def transformDefine(d: Define)(k: StagedPath => Block): Block = d.defn match From 3de464348aba4e62f05678af5f05948fded5e487 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 3 Nov 2025 00:37:25 +0800 Subject: [PATCH 050/268] add Context to some functions --- .../scala/hkmc2/codegen/Instrumentation.scala | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 3327fe2d0a..0feaf8cb0e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -147,7 +147,7 @@ class Instrumentation(using State): mlsBlock("ValueRef", Ls(toValue(r.l.nme))): cde => StagedPath.mk(sp.shape, cde)(k) - def ruleTup(t: Tuple)(k: StagedPath => Block): Block = + def ruleTup(t: Tuple)(using Context)(k: StagedPath => Block): Block = val Tuple(mut, elems) = t assert(!mut) @@ -157,7 +157,7 @@ class Instrumentation(using State): mlsTuple(xs.map(_.code)): cde => // is Tuple quotes as well? StagedPath.mk(sp, cde)(k) - def ruleSel(s: Select)(k: StagedPath => Block): Block = + def ruleSel(s: Select)(using Context)(k: StagedPath => Block): Block = val Select(p, i @ Tree.Ident(name)) = s transformPath(p): x => // stage? there isn't a correct constructor for it though @@ -167,7 +167,7 @@ class Instrumentation(using State): mlsSelect(x.code, i): cde => StagedPath.mk(sp, cde)(k) - def ruleDynSel(d: DynSelect)(k: StagedPath => Block): Block = + def ruleDynSel(d: DynSelect)(using Context)(k: StagedPath => Block): Block = val DynSelect(qual, path, arrayIdx) = d transformPath(qual): x => transformPath(path): y => @@ -175,16 +175,16 @@ class Instrumentation(using State): mlsBlock("DynSelect", Ls(x.code, y.code, toValue(arrayIdx))): cde => StagedPath.mk(sp, cde)(k) - def ruleRefinedPath(p: Path)(k: StagedPath => Block): Block = ??? + def ruleRefinedPath(p: Path)(using ctx: Context)(k: StagedPath => Block): Block = ??? // .apply is Call? - def ruleApp(c: Call)(k: StagedPath => Block): Block = ??? + def ruleApp(c: Call)(using Context)(k: StagedPath => Block): Block = val Call(fun, args) = c transformPath(fun): f => transformArgs(args): xs => instGlobal(f, xs)(k) - def ruleInst(i: Instantiate)(k: StagedPath => Block): Block = + def ruleInst(i: Instantiate)(using Context)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i assert(!mut) @@ -195,17 +195,17 @@ class Instrumentation(using State): mlsBlock("Instantiate", Ls(cls, codes)): cde => StagedPath.mk(sp, cde)(k) - def ruleReturn(r: Return)(k: StagedPath => Block): Block = + def ruleReturn(r: Return)(using Context)(k: StagedPath => Block): Block = transformResult(r.res): x => mlsBlock("Return", Ls(x.code)): cde => StagedPath.mk(x.shape, cde)(k) - def ruleMatch(m: Match)(k: StagedPath => Block): Block = + def ruleMatch(m: Match)(using Context)(k: StagedPath => Block): Block = val Match(p, arms, dflt, b) = m transformPath(p): x => ??? - def ruleAssign(a: Assign)(k: StagedPath => Block): Block = + def ruleAssign(a: Assign)(using Context)(k: StagedPath => Block): Block = val Assign(x, r, b) = a transformResult(r): y => (Assign(x, y.p, _)): @@ -219,7 +219,7 @@ class Instrumentation(using State): mlsBlock("End", Ls()): cde => StagedPath.mk(sp, cde)(k) - def ruleVal(defn: ValDefn, rest: Block)(k: StagedPath => Block): Block = + def ruleVal(defn: ValDefn, rest: Block)(using Context)(k: StagedPath => Block): Block = val ValDefn(tsym, sym, rhs) = defn transformPath(rhs): y => transformBlock(rest): z => @@ -231,18 +231,18 @@ class Instrumentation(using State): mlsBlock("Define", Ls(df, z.code)): cde => StagedPath.mk(z.shape, cde)(k) - def ruleBlk(b: Block)(k: StagedPath => Block): Block = + def ruleBlk(b: Block)(using Context)(k: StagedPath => Block): Block = transformBlock(b): x => fnCompile(x.code)(k) // g is Program? - def ruleCls(c: Program, rest: Block)(k: StagedPath => Block): Block = + def ruleCls(c: Program, rest: Block)(using Context)(k: StagedPath => Block): Block = // val ClsLikeDefn(_, _, ) ??? // transformations of Block - def transformPath(p: Path)(k: StagedPath => Block): Block = + def transformPath(p: Path)(using Context)(k: StagedPath => Block): Block = p match case s: Select => ruleSel(s)(k) case d: DynSelect => ruleDynSel(d)(k) @@ -250,7 +250,7 @@ class Instrumentation(using State): case Value.Lit(lit) => ruleLit(lit)(k) case _ => ??? // not supported - def transformResult(r: Result)(k: StagedPath => Block): Block = + def transformResult(r: Result)(using Context)(k: StagedPath => Block): Block = r match case c: Call => ruleApp(c)(k) case i: Instantiate => ruleInst(i)(k) @@ -258,14 +258,14 @@ class Instrumentation(using State): case p: Path => transformPath(p)(k) case _ : Lambda | _: Record => ??? // not supported - def transformArg(a: Arg)(k: StagedPath => Block): Block = + def transformArg(a: Arg)(using Context)(k: StagedPath => Block): Block = val Arg(spread, value) = a ??? // arg has no shape of its own? it's just a wrapper for Path transformPath(value)(k) // provides list of shapes and list of codes to continuation - def transformArgs(args: Ls[Arg])(k: Ls[StagedPath] => Block): Block = + def transformArgs(args: Ls[Arg])(using Context)(k: Ls[StagedPath] => Block): Block = // TODO: use BlockTransformer.applyListOf? args .map(transformArg) @@ -277,13 +277,13 @@ class Instrumentation(using State): k(p :: rest) )(k) - def transformDefine(d: Define)(k: StagedPath => Block): Block = + def transformDefine(d: Define)(using Context)(k: StagedPath => Block): Block = d.defn match case f: FunDefn => ??? case v: ValDefn => ruleVal(v, d.rest)(k) case c: ClsLikeDefn => ??? - def transformBlock(b: Block)(k: StagedPath => Block): Block = + def transformBlock(b: Block)(using Context)(k: StagedPath => Block): Block = b match case m: Match => ruleMatch(m)(k) case r: Return => ruleReturn(r)(k) From c3a1f5c519e4ad6bfe552bdda95582e624da43aa Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 3 Nov 2025 00:37:57 +0800 Subject: [PATCH 051/268] dedup Pattern with Block.Case --- .../src/test/mlscript-compile/Block.mls | 28 +++++----------- .../src/test/mlscript-compile/Shape.mls | 33 +++++++++---------- 2 files changed, 23 insertions(+), 38 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 5e5eedcc87..d32ef23f5d 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -11,6 +11,7 @@ type Opt[A] = Option[A] // dependancies referenced in Block classes, referencing implementation in Term.mls +// TODO: convert these classes to Str class Ident(val name: Str) // translation of Tree.Ident class Symbol(val name: Str) @@ -28,12 +29,14 @@ class Path with ValueRef(val l: Symbol) ValueLit(val lit: Literal) +// Match pattern for staged code class Case with constructor Lit(val lit: Literal) Cls(val cls: Symbol, val path: Path) Tup(val len: Int, val inf: Bool) - Field(val name: Ident, val safe: Bool) + Field(val name: Ident) + Wildcard class Result with constructor @@ -44,26 +47,11 @@ class Result with class Defn with constructor - ValDefn( - val sym: Symbol, - val rhs: Path, - ) - ClsLikeDefn( - val sym: Symbol, - val paramsOpt: Opt[ParamList], - val companion: Opt[ClsLikeBody], - ) - FunDefn( - val sym: Symbol, - val params: Array[ParamList], - val body: Block, - ) + ValDefn(val sym: Symbol, val rhs: Path) + ClsLikeDefn(val sym: Symbol, val paramsOpt: Opt[ParamList], val companion: Opt[ClsLikeBody]) + FunDefn(val sym: Symbol, val params: Array[ParamList], val body: Block) -class ClsLikeBody( - val isym: Symbol, - val methods: Array[FunDefn], - val publicFields: Array[Symbol -> Symbol], -) +class ClsLikeBody(val isym: Symbol, val methods: Array[FunDefn], val publicFields: Array[Symbol -> Symbol]) class Block with constructor diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index df9304d468..ddccbdfae4 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -1,5 +1,6 @@ import "./Predef.mls" import "./Option.mls" +import "./Block.mls" open Predef open Option @@ -53,38 +54,34 @@ fun sel(s1: Shape, s2: Shape) = _ then ??? fun static(s: Shape) = - if s is - Lit then true - Class | Dyn then false // c vs c() ? - _ then ??? - -module Pattern with... + if s + == Dyn then false + is + Lit then true + Class then false + _ then ??? -class Pattern with - constructor - Lit(val lit: Literal) - Class(val sym: Symbol) - Arr(val size: Int) - Wildcard +open Block -fun silh(p: Pattern): Shape = if p is +fun silh(p: Case): Shape = if p is Lit(l) then Shape.Lit(l) // where to store size of argument array? - Class(sym) then Shape.Class(sym, ???) + Class(sym, path) then Shape.Class(sym, ???) // how to initialize array of Dyn? - Arr(n) then Shape.Arr(???) + Tup(n, inf) then Shape.Arr(???) + Field(name) then ??? Wildcard then Dyn -fun match(s: Shape, p: Pattern): Option[Bool] = +fun match(s: Shape, p: Case): Option[Bool] = if [s, p] is [Shape.Lit(l1), Lit(l2)] then Some(true) [Shape.Lit(l), Class(c)] and isPrimitiveTypeOf(c, l) then Some(true) [Shape.Class(c1, _), Class(c2)] and c1 == c2 then Some(true) - [Shape.Arr(ls), Arr(n)] and ls.length == n then Some(true) + [Shape.Arr(ls), Tup(n, inf)] and ls.length == n then Some(true) [_, Wildcard] then Some(true) [Shape.Dyn, _] then None _ then Some(false) -fun det(s: Shape, ps: Array[Pattern]): Option[Bool] = +fun det(s: Shape, ps: Array[Case]): Option[Bool] = val a = ps.map(p => match(s, p) is Some(true)) return ??? From d1170e91ce80b06a80de1421ea890dbf51e22a17 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 3 Nov 2025 10:31:09 +0800 Subject: [PATCH 052/268] rename mls{Block, Shape, Symbol} helpers --- .../scala/hkmc2/codegen/Instrumentation.scala | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 0feaf8cb0e..92c207855a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -50,18 +50,17 @@ class Instrumentation(using State): val tmp = new TempSymbol(N, name) Assign(tmp, res, k(tmp.asPath)) - def mlsBlock(nme: String, args: Ls[PathLike])(k: Path => Block): Block = + def mlsBlockMod(nme: String, args: Ls[PathLike])(k: Path => Block): Block = val s = summon[State].blockSymbol.asPath.selSN(nme) assign(Instantiate(false, s, args.map(asArg)))(k) - def mlsShape(nme: String, args: Ls[PathLike])(k: Shape => Block): Block = + def mlsShapeMod(nme: String, args: Ls[PathLike])(k: Path => Block): Block = val s = summon[State].shapeSymbol.asPath.selSN(nme) - assign(Instantiate(false, s, args.map(asArg)))(p => k(Shape(p))) + assign(Instantiate(false, s, args.map(asArg)))(k) + def mlsShape(nme: String, args: Ls[PathLike])(k: Shape => Block): Block = + mlsShapeMod(nme, args)(p => k(Shape(p))) // helpers corresponding to constructors - def mlsSymbol(nme: String)(k: Path => Block): Block = - mlsBlock("Symbol", Ls(toValue(nme)))(k) - def mlsSelect(qual: Path, ident: Tree.Ident)(k: Path => Block): Block = // unnecessary assignment? assign(Select(qual, ident)(N))(k) @@ -137,14 +136,14 @@ class Instrumentation(using State): def ruleLit(l: Literal)(k: StagedPath => Block): Block = mlsShape("Lit", Ls(Value.Lit(l))): sp => - mlsBlock("Lit", Ls(Value.Lit(l))): cde => + mlsBlockMod("Lit", Ls(Value.Lit(l))): cde => StagedPath.mk(sp, cde)(k) def ruleVar(r: Value.Ref)(k: StagedPath => Block): Block = // why assume it is already staged? val sp = StagedPath(r) // why not just use sp.code? - mlsBlock("ValueRef", Ls(toValue(r.l.nme))): cde => + mlsBlockMod("ValueRef", Ls(toValue(r.l.nme))): cde => StagedPath.mk(sp.shape, cde)(k) def ruleTup(t: Tuple)(using Context)(k: StagedPath => Block): Block = @@ -172,7 +171,7 @@ class Instrumentation(using State): transformPath(qual): x => transformPath(path): y => fnSel(x.shape, y.shape): sp => - mlsBlock("DynSelect", Ls(x.code, y.code, toValue(arrayIdx))): cde => + mlsBlockMod("DynSelect", Ls(x.code, y.code, toValue(arrayIdx))): cde => StagedPath.mk(sp, cde)(k) def ruleRefinedPath(p: Path)(using ctx: Context)(k: StagedPath => Block): Block = ??? @@ -192,12 +191,12 @@ class Instrumentation(using State): mlsTuple(xs.map(_.shape)): shapes => mlsTuple(xs.map(_.code)): codes => mlsShape("Class", Ls(cls, shapes)): sp => - mlsBlock("Instantiate", Ls(cls, codes)): cde => + mlsBlockMod("Instantiate", Ls(cls, codes)): cde => StagedPath.mk(sp, cde)(k) def ruleReturn(r: Return)(using Context)(k: StagedPath => Block): Block = transformResult(r.res): x => - mlsBlock("Return", Ls(x.code)): cde => + mlsBlockMod("Return", Ls(x.code)): cde => StagedPath.mk(x.shape, cde)(k) def ruleMatch(m: Match)(using Context)(k: StagedPath => Block): Block = @@ -211,24 +210,23 @@ class Instrumentation(using State): (Assign(x, y.p, _)): transformBlock(b): z => // need to wrap x with Symbol? - mlsBlock("Assign", Ls(x, y.code, z.code)): cde => + mlsBlockMod("Assign", Ls(x, y.code, z.code)): cde => StagedPath.mk(z.shape, cde)(k) def ruleEnd()(k: StagedPath => Block): Block = mlsShape("Unit", Ls()): sp => - mlsBlock("End", Ls()): cde => + mlsBlockMod("End", Ls()): cde => StagedPath.mk(sp, cde)(k) - def ruleVal(defn: ValDefn, rest: Block)(using Context)(k: StagedPath => Block): Block = - val ValDefn(tsym, sym, rhs) = defn - transformPath(rhs): y => - transformBlock(rest): z => + def ruleVal(defn: ValDefn, b: Block)(using Context)(k: StagedPath => Block): Block = + val ValDefn(tsym, x, p) = defn + transformPath(p): y => + transformBlock(b): z => // TODO: valdefn needs to be before code blocks somehow? // y is StagedPath, not Path? - (Define(ValDefn(tsym, sym, y.p), _)): - mlsSymbol("x"): x => - mlsBlock("ValDefn", Ls(x, y.code)): df => - mlsBlock("Define", Ls(df, z.code)): cde => + (Define(ValDefn(tsym, x, y.p), _)): + mlsBlockMod("ValDefn", Ls(x, y.code)): df => + mlsBlockMod("Define", Ls(df, z.code)): cde => StagedPath.mk(z.shape, cde)(k) def ruleBlk(b: Block)(using Context)(k: StagedPath => Block): Block = From 36107df377f18bf3e84e801f77032fa823ec9e78 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 3 Nov 2025 17:02:35 +0800 Subject: [PATCH 053/268] amend! link to functions in Shape.mls link to functions in Shape.mls --- .../scala/hkmc2/codegen/Instrumentation.scala | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 92c207855a..bb04d5faee 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -92,26 +92,22 @@ class Instrumentation(using State): // linking functions defined in MLscipt - val mrgSymbol = new TempSymbol(N, "mrg") - val silhSymbol = new TempSymbol(N, "silh") - val matchSymbol = new TempSymbol(N, "match") - val selSymbol = new TempSymbol(N, "sel") - val staticSymbol = new TempSymbol(N, "static") - val compileSymbol = new TempSymbol(N, "compile") - - def fnMrg(shapes: Ls[Shape])(k: Shape => Block): Block = - mlsCall(mrgSymbol.asPath, shapes, true)(s => k(Shape(s))) + def fnMrg(shapes: Ls[Shape])(k: Shape => Block): Block = + mlsShapeMod("mrg", shapes)(s => k(Shape(s))) // TODO: make fnSilh take in a wrapped Path type - def fnSilh(pattern: Path)(k: Shape => Block) = - mlsCall(silhSymbol.asPath, Ls(pattern), true)(s => k(Shape(s))) - def fnMatch(s: Shape, pat: Path)(k: Path => Block) = - mlsCall(matchSymbol.asPath, Ls(s, pat), true)(k) - def fnSel(s1: Shape, s2: Shape)(k: Shape => Block): Block = - mlsCall(selSymbol.asPath, Ls(s1, s2), true)(s => k(Shape(s))) - def fnStatic(s: Shape)(k: Path => Block) = - mlsCall(staticSymbol.asPath, Ls(s), true)(k) - def fnCompile(x: Path)(k: StagedPath => Block): Block = - mlsCall(compileSymbol.asPath, Ls(x), true)(p => k(StagedPath(p))) + def fnSilh(pattern: Path)(k: Shape => Block) = + mlsShapeMod("silh", Ls(pattern))(s => k(Shape(s))) + def fnMatch(s: Shape, pat: Path)(k: Path => Block) = + mlsShapeMod("match", Ls(s, pat))(k) + def fnSel(s1: Shape, s2: Shape)(k: Shape => Block): Block = + mlsShapeMod("sel", Ls(s1, s2))(s => k(Shape(s))) + def fnStatic(s: Shape)(k: Path => Block) = + mlsShapeMod("static", Ls(s))(k) + def fnCompile(x: Path)(k: StagedPath => Block): Block = + mlsShapeMod("compile", Ls(x))(p => k(StagedPath(p))) + def fnDet(s: Shape, ps: Ls[PathLike])(k: Path => Block): Block = + mlsTuple(ps): tup => + mlsShapeMod("det", Ls(s, tup))(k) // helpers for instrumenting functions From ed393fcf44c484018299b29c59117b0c97a338f7 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 3 Nov 2025 20:07:29 +0800 Subject: [PATCH 054/268] flesh out {Block, Shape}.mls --- .../src/test/mlscript-compile/Block.mls | 5 +- .../src/test/mlscript-compile/Shape.mls | 78 ++++++++++++------- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index d32ef23f5d..48cd3bb942 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -12,8 +12,7 @@ type Opt[A] = Option[A] // dependancies referenced in Block classes, referencing implementation in Term.mls // TODO: convert these classes to Str -class Ident(val name: Str) // translation of Tree.Ident -class Symbol(val name: Str) +type Ident = Symbol type Literal = null | undefined | Str | Int | Num | Bool class Arg(val spread: Opt[Bool], val value: Path) @@ -34,7 +33,7 @@ class Case with constructor Lit(val lit: Literal) Cls(val cls: Symbol, val path: Path) - Tup(val len: Int, val inf: Bool) + Tup(val len: Int, val inf: Bool) // TODO: remove inf? Field(val name: Ident) Wildcard diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index ddccbdfae4..a688490556 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -15,10 +15,18 @@ class Shape with Dyn Lit(val l: Literal) Arr(val shapes: Array[Shape]) // is length parameter needed? - // TODO: change sym to accept multiple possible class symbols + // TODO: change sym to accept multiple possible class symbols? Class(val sym: Symbol, val shapes: Array[Shape]) Unit +fun isPrimitiveType(sym: Str) = + if sym is + "Str" then true + "Int" then true + "Num" then true + "Bool" then true + else false + fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = if [sym, l] is ["Str", l] and l is Str then true @@ -27,29 +35,37 @@ fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = ["Bool", b] and b is Bool then true _ then false +fun zipMrg[A](a: Array[A], b: Array[A]): Array[[A, A]] = + [...Array(a.length).keys()].map((i, _, _) => mrg2(a.at(i), b.at(i))) + // TODO: look at how Array is used fun mrg2(s1: Shape, s2: Shape) = if s1 == s2 then s1 - is Lit(l) and s2 is Class(sym, shapes) - and isPrimitiveTypeOf(sym, l) then Class(sym, shapes) - is Class(sym1, shapes1) and s2 is Class(sym2, shapes2) - and sym1 == sym2 then Class(sym1, ???) - is Arr(s1) and s2 is Arr(s2) - and s1.length == s2.length then Arr(???) - else ??? + is + Lit(l) and s2 is Class(sym, shapes) + and isPrimitiveTypeOf(sym, l) + then Class(sym, shapes) + Class(sym1, s1) and s2 is Class(sym2, s2) + and sym1 == sym2 + then Class(sym1, zipMrg(s1, s2)) + Arr(s1) and s2 is Arr(s2) + and s1.length == s2.length + then Arr(zipMrg(s1, s2)) + else Dyn -fun mrg(s1: Array[Shape]) = ??? +fun mrg(s1: Array[Shape]) = + s1.reduceRight((acc, s, _, _) => mrg2(s, acc)) fun sel(s1: Shape, s2: Shape) = if [s1, s2] is - [Class(c, shapes), Lit(n)] // n_i ? - and n is Int then shapes.n - [Dyn, Lit(n)] // n_i ? - and n is Int then Dyn + [Class(c, shapes), Lit(n)] + and n is Str then shapes.at(n) // field name election using Str? + [Dyn, Lit(n)] + and n is Str then Dyn [Arr(shapes), Lit(n)] - and n is Int then shapes.n + and n is Int then shapes.at(n) [Dyn, Lit(n)] - and n is Int then Dyn + and n is Int then Dyn [Dyn, Dyn] then Dyn _ then ??? @@ -57,31 +73,35 @@ fun static(s: Shape) = if s == Dyn then false is - Lit then true - Class then false - _ then ??? + Lit(l) then not (l is Str and isPrimitiveType(l)) // redundant bracket? + Class(_, shapes) then shapes.every((s, _, _) => static(s)) + Arr(shapes) then shapes.every((s, _, _) => static(s)) +type SLit = Lit open Block fun silh(p: Case): Shape = if p is - Lit(l) then Shape.Lit(l) + Lit(l) then SLit(l) // where to store size of argument array? - Class(sym, path) then Shape.Class(sym, ???) + Cls(sym, path) then Class(sym, ???) // how to initialize array of Dyn? - Tup(n, inf) then Shape.Arr(???) + Tup(n, inf) then Arr(Array(n).fill(Dyn)) Field(name) then ??? Wildcard then Dyn fun match(s: Shape, p: Case): Option[Bool] = if [s, p] is - [Shape.Lit(l1), Lit(l2)] then Some(true) - [Shape.Lit(l), Class(c)] and isPrimitiveTypeOf(c, l) then Some(true) - [Shape.Class(c1, _), Class(c2)] and c1 == c2 then Some(true) - [Shape.Arr(ls), Tup(n, inf)] and ls.length == n then Some(true) - [_, Wildcard] then Some(true) + [Lit(l1), Lit(l2)] then Some(true) + [Lit(l), Cls(c, _)] and isPrimitiveTypeOf(c, l) then Some(true) + [Class(c1, _), Cls(c2, _)] and c1 == c2 then Some(true) + [Arr(ls), Tup(n, inf)] and ls.length == n then Some(true) + [_, Block.Wildcard] then Some(true) [Shape.Dyn, _] then None _ then Some(false) -fun det(s: Shape, ps: Array[Case]): Option[Bool] = - val a = ps.map(p => match(s, p) is Some(true)) - return ??? +fun det(s: Shape, ps: Array[Case]): Bool = + ps.every((p, i, a) => + if i != ps.length - 1 + then match(s, p) == Some(false) + else match(s, p) == Some(true) + ) From 1c5fc1aa9bd7776600b9fbb1735625cd45efe1fd Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 3 Nov 2025 20:13:04 +0800 Subject: [PATCH 055/268] formatting --- .../scala/hkmc2/codegen/Instrumentation.scala | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index bb04d5faee..8542aeba09 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -109,25 +109,24 @@ class Instrumentation(using State): mlsTuple(ps): tup => mlsShapeMod("det", Ls(s, tup))(k) - // helpers for instrumenting functions + // helpers for instrumenting functions def inst(f: StagedPath, args: Ls[StagedPath]): StagedPath = - if ??? then + if ??? then // non-staged function ??? - else - // staged function + else + // staged function ??? def instGlobal(f: StagedPath, args: Ls[StagedPath])(k: StagedPath => Block): Block = def isFunction(p: Path) = ??? - if isFunction(f.p) then - k(inst(???, args)) - else + if isFunction(f.p) then k(inst(???, args)) + else mlsShape("Dyn", Ls()): sp => mlsCall(f.p, args.map(_.p), ???): cde => StagedPath.mk(sp, cde)(k) - + // instrumentation rules def ruleLit(l: Literal)(k: StagedPath => Block): Block = @@ -172,7 +171,7 @@ class Instrumentation(using State): def ruleRefinedPath(p: Path)(using ctx: Context)(k: StagedPath => Block): Block = ??? - // .apply is Call? + // .apply is Call? def ruleApp(c: Call)(using Context)(k: StagedPath => Block): Block = val Call(fun, args) = c transformPath(fun): f => @@ -200,7 +199,7 @@ class Instrumentation(using State): transformPath(p): x => ??? - def ruleAssign(a: Assign)(using Context)(k: StagedPath => Block): Block = + def ruleAssign(a: Assign)(using Context)(k: StagedPath => Block): Block = val Assign(x, r, b) = a transformResult(r): y => (Assign(x, y.p, _)): @@ -221,11 +220,11 @@ class Instrumentation(using State): // TODO: valdefn needs to be before code blocks somehow? // y is StagedPath, not Path? (Define(ValDefn(tsym, x, y.p), _)): - mlsBlockMod("ValDefn", Ls(x, y.code)): df => - mlsBlockMod("Define", Ls(df, z.code)): cde => - StagedPath.mk(z.shape, cde)(k) + mlsBlockMod("ValDefn", Ls(x, y.code)): df => + mlsBlockMod("Define", Ls(df, z.code)): cde => + StagedPath.mk(z.shape, cde)(k) - def ruleBlk(b: Block)(using Context)(k: StagedPath => Block): Block = + def ruleBlk(b: Block)(using Context)(k: StagedPath => Block): Block = transformBlock(b): x => fnCompile(x.code)(k) @@ -250,7 +249,7 @@ class Instrumentation(using State): case i: Instantiate => ruleInst(i)(k) case t: Tuple => ruleTup(t)(k) case p: Path => transformPath(p)(k) - case _ : Lambda | _: Record => ??? // not supported + case _: Lambda | _: Record => ??? // not supported def transformArg(a: Arg)(using Context)(k: StagedPath => Block): Block = val Arg(spread, value) = a From 38069b7294e6faee40315a2f384658bcd3b332c5 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 3 Nov 2025 20:30:18 +0800 Subject: [PATCH 056/268] implement ruleMatch --- .../scala/hkmc2/codegen/Instrumentation.scala | 89 +++++++++++++++---- 1 file changed, 74 insertions(+), 15 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 8542aeba09..18b6831b1c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -42,6 +42,17 @@ class Instrumentation(using State): case n: BigDecimal => Tree.DecLit(n) Value.Lit(l) + // TODO: use BlockTransformer.applyListOf? + extension [A](ls: Ls[(A => Block) => Block]) + def collectApply(f: Ls[A] => Block): Block = + // defer applying k while prepending new paths to the list + ls.foldRight((_: Ls[A] => Block)(Nil))((headCont, tailCont) => + k => + headCont: head => + tailCont: tail => + k(head :: tail) + )(f) + // helper for staging the constructors // could use `using` to allow passthrough of names @@ -194,10 +205,67 @@ class Instrumentation(using State): mlsBlockMod("Return", Ls(x.code)): cde => StagedPath.mk(x.shape, cde)(k) - def ruleMatch(m: Match)(using Context)(k: StagedPath => Block): Block = - val Match(p, arms, dflt, b) = m + def ruleMatch(m: Match)(using ctx: Context)(k: StagedPath => Block): Block = + def concat(b1: Block, b2: Block) = b1.mapTail { + case r: Return => r + case _: End => b2 + case _ => ??? + } + + val Match(p, arms, dflt, rest) = m + + val allArms = + // append at the end to make Ls[Opt[Case], Block] + (arms.map((c, b) => + val concatBlock = concat(b, rest) + (k: ((Path, (StagedPath => Block) => Block)) => Block) => + (c match { + // refactor as Opt[Case] + // convert to Block.mls Case + case Case.Lit(lit) => mlsBlockMod("Lit", Ls(Value.Lit(lit))) + case Case.Cls(cls, path) => mlsBlockMod("Cls", Ls(cls, path)) + case Case.Tup(len, inf) => mlsBlockMod("Tup", Ls(len, inf).map(toValue)) + case Case.Field(name, safe) => mlsBlockMod("Field", Ls(toValue(name.name))) + }): patt => + fnSilh(patt): sp => + val newCtx = ctx.clone() + newCtx += p -> sp + k(patt, transformBlock(concatBlock)(using newCtx)) + ) + ::: (dflt match + case S(b) => + val concatBlock = b + Ls((k: ((Path, (StagedPath => Block) => Block)) => Block) => + mlsBlockMod("Wildcard", Ls()): patt => + fnSilh(patt): sp => + val newCtx = ctx.clone() + newCtx += p -> sp + k(patt, transformBlock(concatBlock)(using newCtx)) + ) + case N => Nil + )) + transformPath(p): x => - ??? + allArms.collectApply: arms => + val (patts, blocksCont) = arms.unzip + (arms.zipWithIndex.foldRight(_: Block) { case (((patt, blockCont), i), rest) => + val slice = arms.slice(0, i + 1).map(_._1) + fnDet(x.shape, slice): scrut => + blockCont: block => + val cse = Case.Lit(Tree.BoolLit(false)) -> k(block) + Match(scrut, Ls(cse), S(rest), End()) + }): + // staged block + blocksCont.collectApply: xs => + val (sps, cdes) = xs.map(xi => (xi.shape, xi.code)).unzip + fnMrg(sps): s => + (patts + .zip(cdes) + .foldRight(mlsBlockMod("End", Ls())) { case ((patt, cde), restCont) => + (k: Path => Block) => + restCont: rest => + mlsBlockMod("Match", Ls(x.code, patt, cde, rest))(k) + })(StagedPath.mk(s, _)(k)) def ruleAssign(a: Assign)(using Context)(k: StagedPath => Block): Block = val Assign(x, r, b) = a @@ -259,18 +327,9 @@ class Instrumentation(using State): // provides list of shapes and list of codes to continuation def transformArgs(args: Ls[Arg])(using Context)(k: Ls[StagedPath] => Block): Block = - // TODO: use BlockTransformer.applyListOf? - args - .map(transformArg) - // defer applying k while prepending new paths to the list - .foldRight((_: Ls[StagedPath] => Block)(Nil))((pathCont, restCont) => - k => - pathCont: p => - restCont: rest => - k(p :: rest) - )(k) - - def transformDefine(d: Define)(using Context)(k: StagedPath => Block): Block = + args.map(transformArg).collectApply(k) + + def transformDefine(d: Define)(using Context)(k: StagedPath => Block): Block = d.defn match case f: FunDefn => ??? case v: ValDefn => ruleVal(v, d.rest)(k) From f1a209bdb3741cd363b1ebc290d33166647d1b75 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 3 Nov 2025 20:30:53 +0800 Subject: [PATCH 057/268] remove Label from Block.mls --- hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala | 1 - hkmc2/shared/src/test/mlscript-compile/Block.mls | 1 - 2 files changed, 2 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 18b6831b1c..e759e5a0ee 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -342,5 +342,4 @@ class Instrumentation(using State): case a: Assign => ruleAssign(a)(k) case d: Define => transformDefine(d)(k) case End(_) => ruleEnd()(k) - case l: Label => ??? case _ => ??? // not supported diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 48cd3bb942..9c9c51e71d 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -57,6 +57,5 @@ class Block with Match(val scrut: Path, val arms: Array[Case -> Block], val dflt: Opt[Block], val rest: Block) Return(val res: Result, val implct: Bool) Assign(val lhs: Symbol, val rhs: Result, val rest: Block) - Label(val lavel: Symbol, val body: Block, val rest: Block) // unused? Define(val defn: Defn, val rest: Block) End() From 55f4fa1afeb8cd18ef651b24ea05e598a7217d69 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 3 Nov 2025 22:22:16 +0800 Subject: [PATCH 058/268] rename helpers --- .../scala/hkmc2/codegen/Instrumentation.scala | 96 +++++++++++-------- .../src/test/mlscript-compile/Block.mls | 4 + 2 files changed, 58 insertions(+), 42 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index e759e5a0ee..12b9c3adde 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -53,7 +53,7 @@ class Instrumentation(using State): k(head :: tail) )(f) - // helper for staging the constructors + // helpers corresponding to constructors // could use `using` to allow passthrough of names def assign(res: Result, name: String = "tmp")(k: Path => Block): Assign = @@ -61,17 +61,6 @@ class Instrumentation(using State): val tmp = new TempSymbol(N, name) Assign(tmp, res, k(tmp.asPath)) - def mlsBlockMod(nme: String, args: Ls[PathLike])(k: Path => Block): Block = - val s = summon[State].blockSymbol.asPath.selSN(nme) - assign(Instantiate(false, s, args.map(asArg)))(k) - def mlsShapeMod(nme: String, args: Ls[PathLike])(k: Path => Block): Block = - val s = summon[State].shapeSymbol.asPath.selSN(nme) - assign(Instantiate(false, s, args.map(asArg)))(k) - def mlsShape(nme: String, args: Ls[PathLike])(k: Shape => Block): Block = - mlsShapeMod(nme, args)(p => k(Shape(p))) - - // helpers corresponding to constructors - def mlsSelect(qual: Path, ident: Tree.Ident)(k: Path => Block): Block = // unnecessary assignment? assign(Select(qual, ident)(N))(k) @@ -80,9 +69,28 @@ class Instrumentation(using State): // is this the same as "Ls of"? assign(Tuple(false, elems.map(asArg)))(k) - def mlsCall(fun: Path, args: Ls[PathLike], isMlsFun: Bool)(k: Path => Block): Block = + // helper for staging the constructors + + def blockMod(name: String) = summon[State].blockSymbol.asPath.selSN(name) + def shapeMod(name: String) = summon[State].shapeSymbol.asPath.selSN(name) + + def ctor(cls: Path, args: Ls[PathLike])(k: Path => Block): Block = + assign(Instantiate(false, cls, args.map(asArg)))(k) + + // isMlsFun is probably always true? + def call(fun: Path, args: Ls[PathLike], isMlsFun: Bool = true)(k: Path => Block): Block = assign(Call(fun, args.map(asArg))(isMlsFun, false))(k) + def blockCtor(name: String, args: Ls[PathLike])(k: Path => Block): Block = + ctor(blockMod(name), args)(k) + def shapeCtor(name: String, args: Ls[PathLike])(k: Shape => Block): Block = + ctor(shapeMod(name), args)(p => k(Shape(p))) + + def blockCall(name: String, args: Ls[PathLike])(k: Path => Block): Block = + call(blockMod(name), args)(k) + def shapeCall(name: String, args: Ls[PathLike])(k: Path => Block): Block = + call(shapeMod(name), args)(k) + // helpers to create and access the components of a staged value case class Shape(p: Path) @@ -103,22 +111,26 @@ class Instrumentation(using State): // linking functions defined in MLscipt + def fnPrintCode(p: Path)(k: Path => Block): Block = + blockCall("printCode", Ls(p))(k) + def applyCompile(r: Path)(k: Path => Block): Block = + blockCall("compile", Ls(r))(k) def fnMrg(shapes: Ls[Shape])(k: Shape => Block): Block = - mlsShapeMod("mrg", shapes)(s => k(Shape(s))) + shapeCall("mrg", shapes)(s => k(Shape(s))) // TODO: make fnSilh take in a wrapped Path type def fnSilh(pattern: Path)(k: Shape => Block) = - mlsShapeMod("silh", Ls(pattern))(s => k(Shape(s))) + shapeCall("silh", Ls(pattern))(s => k(Shape(s))) def fnMatch(s: Shape, pat: Path)(k: Path => Block) = - mlsShapeMod("match", Ls(s, pat))(k) + shapeCall("match", Ls(s, pat))(k) def fnSel(s1: Shape, s2: Shape)(k: Shape => Block): Block = - mlsShapeMod("sel", Ls(s1, s2))(s => k(Shape(s))) + shapeCall("sel", Ls(s1, s2))(s => k(Shape(s))) def fnStatic(s: Shape)(k: Path => Block) = - mlsShapeMod("static", Ls(s))(k) + shapeCall("static", Ls(s))(k) def fnCompile(x: Path)(k: StagedPath => Block): Block = - mlsShapeMod("compile", Ls(x))(p => k(StagedPath(p))) + shapeCall("compile", Ls(x))(p => k(StagedPath(p))) def fnDet(s: Shape, ps: Ls[PathLike])(k: Path => Block): Block = mlsTuple(ps): tup => - mlsShapeMod("det", Ls(s, tup))(k) + shapeCall("det", Ls(s, tup))(k) // helpers for instrumenting functions @@ -134,22 +146,22 @@ class Instrumentation(using State): def isFunction(p: Path) = ??? if isFunction(f.p) then k(inst(???, args)) else - mlsShape("Dyn", Ls()): sp => - mlsCall(f.p, args.map(_.p), ???): cde => + shapeCtor("Dyn", Ls()): sp => + call(f.p, args.map(_.p), ???): cde => StagedPath.mk(sp, cde)(k) // instrumentation rules def ruleLit(l: Literal)(k: StagedPath => Block): Block = - mlsShape("Lit", Ls(Value.Lit(l))): sp => - mlsBlockMod("Lit", Ls(Value.Lit(l))): cde => + shapeCtor("Lit", Ls(Value.Lit(l))): sp => + blockCtor("ValueLit", Ls(Value.Lit(l))): cde => StagedPath.mk(sp, cde)(k) def ruleVar(r: Value.Ref)(k: StagedPath => Block): Block = // why assume it is already staged? val sp = StagedPath(r) // why not just use sp.code? - mlsBlockMod("ValueRef", Ls(toValue(r.l.nme))): cde => + blockCtor("ValueRef", Ls(toValue(r.l.nme))): cde => StagedPath.mk(sp.shape, cde)(k) def ruleTup(t: Tuple)(using Context)(k: StagedPath => Block): Block = @@ -158,7 +170,7 @@ class Instrumentation(using State): transformArgs(elems): xs => mlsTuple(xs.map(_.shape)): shapes => - mlsShape("Arr", Ls(shapes)): sp => + shapeCtor("Arr", Ls(shapes)): sp => mlsTuple(xs.map(_.code)): cde => // is Tuple quotes as well? StagedPath.mk(sp, cde)(k) @@ -177,7 +189,7 @@ class Instrumentation(using State): transformPath(qual): x => transformPath(path): y => fnSel(x.shape, y.shape): sp => - mlsBlockMod("DynSelect", Ls(x.code, y.code, toValue(arrayIdx))): cde => + blockCtor("DynSelect", Ls(x.code, y.code, toValue(arrayIdx))): cde => StagedPath.mk(sp, cde)(k) def ruleRefinedPath(p: Path)(using ctx: Context)(k: StagedPath => Block): Block = ??? @@ -196,13 +208,13 @@ class Instrumentation(using State): transformArgs(args): xs => mlsTuple(xs.map(_.shape)): shapes => mlsTuple(xs.map(_.code)): codes => - mlsShape("Class", Ls(cls, shapes)): sp => - mlsBlockMod("Instantiate", Ls(cls, codes)): cde => + shapeCtor("Class", Ls(cls, shapes)): sp => + blockCtor("Instantiate", Ls(cls, codes)): cde => StagedPath.mk(sp, cde)(k) def ruleReturn(r: Return)(using Context)(k: StagedPath => Block): Block = transformResult(r.res): x => - mlsBlockMod("Return", Ls(x.code)): cde => + blockCtor("Return", Ls(x.code)): cde => StagedPath.mk(x.shape, cde)(k) def ruleMatch(m: Match)(using ctx: Context)(k: StagedPath => Block): Block = @@ -222,10 +234,10 @@ class Instrumentation(using State): (c match { // refactor as Opt[Case] // convert to Block.mls Case - case Case.Lit(lit) => mlsBlockMod("Lit", Ls(Value.Lit(lit))) - case Case.Cls(cls, path) => mlsBlockMod("Cls", Ls(cls, path)) - case Case.Tup(len, inf) => mlsBlockMod("Tup", Ls(len, inf).map(toValue)) - case Case.Field(name, safe) => mlsBlockMod("Field", Ls(toValue(name.name))) + case Case.Lit(lit) => blockCtor("Lit", Ls(Value.Lit(lit))) + case Case.Cls(cls, path) => blockCtor("Cls", Ls(cls, path)) + case Case.Tup(len, inf) => blockCtor("Tup", Ls(len, inf).map(toValue)) + case Case.Field(name, safe) => blockCtor("Field", Ls(toValue(name.name))) }): patt => fnSilh(patt): sp => val newCtx = ctx.clone() @@ -236,7 +248,7 @@ class Instrumentation(using State): case S(b) => val concatBlock = b Ls((k: ((Path, (StagedPath => Block) => Block)) => Block) => - mlsBlockMod("Wildcard", Ls()): patt => + blockCtor("Wildcard", Ls()): patt => fnSilh(patt): sp => val newCtx = ctx.clone() newCtx += p -> sp @@ -261,10 +273,10 @@ class Instrumentation(using State): fnMrg(sps): s => (patts .zip(cdes) - .foldRight(mlsBlockMod("End", Ls())) { case ((patt, cde), restCont) => + .foldRight(blockCtor("End", Ls())) { case ((patt, cde), restCont) => (k: Path => Block) => restCont: rest => - mlsBlockMod("Match", Ls(x.code, patt, cde, rest))(k) + blockCtor("Match", Ls(x.code, patt, cde, rest))(k) })(StagedPath.mk(s, _)(k)) def ruleAssign(a: Assign)(using Context)(k: StagedPath => Block): Block = @@ -273,12 +285,12 @@ class Instrumentation(using State): (Assign(x, y.p, _)): transformBlock(b): z => // need to wrap x with Symbol? - mlsBlockMod("Assign", Ls(x, y.code, z.code)): cde => + blockCtor("Assign", Ls(x, y.code, z.code)): cde => StagedPath.mk(z.shape, cde)(k) def ruleEnd()(k: StagedPath => Block): Block = - mlsShape("Unit", Ls()): sp => - mlsBlockMod("End", Ls()): cde => + shapeCtor("Unit", Ls()): sp => + blockCtor("End", Ls()): cde => StagedPath.mk(sp, cde)(k) def ruleVal(defn: ValDefn, b: Block)(using Context)(k: StagedPath => Block): Block = @@ -288,8 +300,8 @@ class Instrumentation(using State): // TODO: valdefn needs to be before code blocks somehow? // y is StagedPath, not Path? (Define(ValDefn(tsym, x, y.p), _)): - mlsBlockMod("ValDefn", Ls(x, y.code)): df => - mlsBlockMod("Define", Ls(df, z.code)): cde => + blockCtor("ValDefn", Ls(x, y.code)): df => + blockCtor("Define", Ls(df, z.code)): cde => StagedPath.mk(z.shape, cde)(k) def ruleBlk(b: Block)(using Context)(k: StagedPath => Block): Block = diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 9c9c51e71d..9f6dad1b91 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -59,3 +59,7 @@ class Block with Assign(val lhs: Symbol, val rhs: Result, val rest: Block) Define(val defn: Defn, val rest: Block) End() + +fun printCode(p: Block) = ??? + +fun compile(p: Block) = ??? \ No newline at end of file From 124232f7012d47dab5304c9f4c753567c9e9ec0e Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 3 Nov 2025 22:33:11 +0800 Subject: [PATCH 059/268] update Block.mls --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 9f6dad1b91..534fe777ac 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -11,11 +11,10 @@ type Opt[A] = Option[A] // dependancies referenced in Block classes, referencing implementation in Term.mls -// TODO: convert these classes to Str type Ident = Symbol type Literal = null | undefined | Str | Int | Num | Bool -class Arg(val spread: Opt[Bool], val value: Path) +class Arg(val spread: Opt[Bool], val value: Path) // unused type ParamList = Array[Symbol] @@ -39,18 +38,19 @@ class Case with class Result with constructor + // unused? TrivialResult(val path: Path) // only Path extends TrivialResult - Call(val _fun: Path, val args: Array[Arg])(isMlsFun: Bool, mayRaiseEffects: Bool) + Call(val _fun: Path, val args: Array[Arg]) Instantiate(val cls: Path, val args: Array[Arg]) // assume immutable Tuple(val elems: Array[Arg]) // assume immutable class Defn with constructor ValDefn(val sym: Symbol, val rhs: Path) - ClsLikeDefn(val sym: Symbol, val paramsOpt: Opt[ParamList], val companion: Opt[ClsLikeBody]) + ClsLikeDefn(val sym: Symbol, val paramsOpt: Opt[ParamList], val companion: Opt[ClsLikeBody]) // unused FunDefn(val sym: Symbol, val params: Array[ParamList], val body: Block) -class ClsLikeBody(val isym: Symbol, val methods: Array[FunDefn], val publicFields: Array[Symbol -> Symbol]) +class ClsLikeBody(val isym: Symbol, val methods: Array[FunDefn], val publicFields: Array[Symbol -> Symbol]) // unused class Block with constructor From 7c8f3d9e059cc71d6952158a0c9cb45aa0e7b3c1 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 3 Nov 2025 22:39:44 +0800 Subject: [PATCH 060/268] adapt NeilKleistGao's example code --- .../scala/hkmc2/codegen/Instrumentation.scala | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 12b9c3adde..bb7f12798b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -333,8 +333,6 @@ class Instrumentation(using State): def transformArg(a: Arg)(using Context)(k: StagedPath => Block): Block = val Arg(spread, value) = a - ??? // arg has no shape of its own? it's just a wrapper for Path - transformPath(value)(k) // provides list of shapes and list of codes to continuation @@ -343,9 +341,18 @@ class Instrumentation(using State): def transformDefine(d: Define)(using Context)(k: StagedPath => Block): Block = d.defn match - case f: FunDefn => ??? + case f @ FunDefn(owner, sym, parameters, body) => + val genSym = BlockMemberSymbol("gen", Nil, true) // TODO: reuse original function name? + val b = transformBlock(d.rest): res => + // TODO: remove it. only for test + // TODO: put correct parameters instead of Nil + call(genSym.asPath, Nil): ret => + blockCall("printCode", Ls(StagedPath(ret).code)): _ => // discard result, we only care about side effect + res.end + val rest = Define(FunDefn(owner, genSym, parameters, transformBlock(body)(_.end)), b) + Define(f, rest) case v: ValDefn => ruleVal(v, d.rest)(k) - case c: ClsLikeDefn => ??? + case c: ClsLikeDefn => ??? // nested class? def transformBlock(b: Block)(using Context)(k: StagedPath => Block): Block = b match @@ -355,3 +362,8 @@ class Instrumentation(using State): case d: Define => transformDefine(d)(k) case End(_) => ruleEnd()(k) case _ => ??? // not supported + + def transformProgram(prog: Program)(): Program = + // TODO imports + ??? // use ruleCls and ruleBlock here + Program(prog.imports, transformBlock(prog.main)(using new Context())(_.end)) From 6997e89ef5ea80d3a79235a7985cfe63c229708e Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 3 Nov 2025 23:56:06 +0800 Subject: [PATCH 061/268] rename helpers --- .../scala/hkmc2/codegen/Instrumentation.scala | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index bb7f12798b..9021b5dc38 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -61,19 +61,14 @@ class Instrumentation(using State): val tmp = new TempSymbol(N, name) Assign(tmp, res, k(tmp.asPath)) - def mlsSelect(qual: Path, ident: Tree.Ident)(k: Path => Block): Block = - // unnecessary assignment? - assign(Select(qual, ident)(N))(k) + def select(qual: Path, ident: Tree.Ident): Path = + // do we need to call assign here? it's already a path anyways + Select(qual, ident)(N) - def mlsTuple(elems: Ls[PathLike])(k: Path => Block): Block = + def tuple(elems: Ls[PathLike])(k: Path => Block): Block = // is this the same as "Ls of"? assign(Tuple(false, elems.map(asArg)))(k) - // helper for staging the constructors - - def blockMod(name: String) = summon[State].blockSymbol.asPath.selSN(name) - def shapeMod(name: String) = summon[State].shapeSymbol.asPath.selSN(name) - def ctor(cls: Path, args: Ls[PathLike])(k: Path => Block): Block = assign(Instantiate(false, cls, args.map(asArg)))(k) @@ -81,6 +76,11 @@ class Instrumentation(using State): def call(fun: Path, args: Ls[PathLike], isMlsFun: Bool = true)(k: Path => Block): Block = assign(Call(fun, args.map(asArg))(isMlsFun, false))(k) + // helper for staging the constructors + + def blockMod(name: String) = summon[State].blockSymbol.asPath.selSN(name) + def shapeMod(name: String) = summon[State].shapeSymbol.asPath.selSN(name) + def blockCtor(name: String, args: Ls[PathLike])(k: Path => Block): Block = ctor(blockMod(name), args)(k) def shapeCtor(name: String, args: Ls[PathLike])(k: Shape => Block): Block = @@ -102,7 +102,7 @@ class Instrumentation(using State): object StagedPath: def mk(shape: Shape, code: Path)(k: StagedPath => Block): Block = - mlsTuple(Ls(shape.p, code))(p => k(StagedPath(p))) + tuple(Ls(shape.p, code))(p => k(StagedPath(p))) // in some cases this can reduce the indentation level def mk(shapeCont: (Shape => Block) => Block, codeCont: (Path => Block) => Block)(k: StagedPath => Block): Block = shapeCont: shape => @@ -129,7 +129,7 @@ class Instrumentation(using State): def fnCompile(x: Path)(k: StagedPath => Block): Block = shapeCall("compile", Ls(x))(p => k(StagedPath(p))) def fnDet(s: Shape, ps: Ls[PathLike])(k: Path => Block): Block = - mlsTuple(ps): tup => + tuple(ps): tup => shapeCall("det", Ls(s, tup))(k) // helpers for instrumenting functions @@ -169,9 +169,9 @@ class Instrumentation(using State): assert(!mut) transformArgs(elems): xs => - mlsTuple(xs.map(_.shape)): shapes => + tuple(xs.map(_.shape)): shapes => shapeCtor("Arr", Ls(shapes)): sp => - mlsTuple(xs.map(_.code)): cde => // is Tuple quotes as well? + tuple(xs.map(_.code)): cde => // is Tuple quotes as well? StagedPath.mk(sp, cde)(k) def ruleSel(s: Select)(using Context)(k: StagedPath => Block): Block = @@ -181,7 +181,7 @@ class Instrumentation(using State): // val n = Shape(Value.Ref(new TempSymbol(N, name))) val n = ??? fnSel(x.shape, n): sp => - mlsSelect(x.code, i): cde => + select(x.code, i): cde => StagedPath.mk(sp, cde)(k) def ruleDynSel(d: DynSelect)(using Context)(k: StagedPath => Block): Block = @@ -206,8 +206,8 @@ class Instrumentation(using State): assert(!mut) transformArgs(args): xs => - mlsTuple(xs.map(_.shape)): shapes => - mlsTuple(xs.map(_.code)): codes => + tuple(xs.map(_.shape)): shapes => + tuple(xs.map(_.code)): codes => shapeCtor("Class", Ls(cls, shapes)): sp => blockCtor("Instantiate", Ls(cls, codes)): cde => StagedPath.mk(sp, cde)(k) From 36abad1e4d37d15f6de62a70134dfd5b131a79c1 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 4 Nov 2025 00:50:15 +0800 Subject: [PATCH 062/268] refactor ruleMatch --- .../scala/hkmc2/codegen/Instrumentation.scala | 88 ++++++++----------- 1 file changed, 37 insertions(+), 51 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 9021b5dc38..3c81fcf070 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -223,61 +223,47 @@ class Instrumentation(using State): case _: End => b2 case _ => ??? } + def transformCase(cse: Opt[Case])(k: Path => Block): Block = + cse match + case S(Case.Lit(lit)) => blockCtor("Lit", Ls(Value.Lit(lit)))(k) + case S(Case.Cls(cls, path)) => blockCtor("Cls", Ls(cls, path))(k) + case S(Case.Tup(len, inf)) => blockCtor("Tup", Ls(len, inf).map(toValue))(k) + case S(Case.Field(name, safe)) => blockCtor("Field", Ls(toValue(name.name)))(k) + case N => blockCtor("Wildcard", Ls())(k) val Match(p, arms, dflt, rest) = m - val allArms = - // append at the end to make Ls[Opt[Case], Block] - (arms.map((c, b) => - val concatBlock = concat(b, rest) - (k: ((Path, (StagedPath => Block) => Block)) => Block) => - (c match { - // refactor as Opt[Case] - // convert to Block.mls Case - case Case.Lit(lit) => blockCtor("Lit", Ls(Value.Lit(lit))) - case Case.Cls(cls, path) => blockCtor("Cls", Ls(cls, path)) - case Case.Tup(len, inf) => blockCtor("Tup", Ls(len, inf).map(toValue)) - case Case.Field(name, safe) => blockCtor("Field", Ls(toValue(name.name))) - }): patt => - fnSilh(patt): sp => - val newCtx = ctx.clone() - newCtx += p -> sp - k(patt, transformBlock(concatBlock)(using newCtx)) - ) - ::: (dflt match - case S(b) => - val concatBlock = b - Ls((k: ((Path, (StagedPath => Block) => Block)) => Block) => - blockCtor("Wildcard", Ls()): patt => - fnSilh(patt): sp => - val newCtx = ctx.clone() - newCtx += p -> sp - k(patt, transformBlock(concatBlock)(using newCtx)) - ) - case N => Nil - )) - transformPath(p): x => - allArms.collectApply: arms => - val (patts, blocksCont) = arms.unzip - (arms.zipWithIndex.foldRight(_: Block) { case (((patt, blockCont), i), rest) => - val slice = arms.slice(0, i + 1).map(_._1) - fnDet(x.shape, slice): scrut => - blockCont: block => - val cse = Case.Lit(Tree.BoolLit(false)) -> k(block) - Match(scrut, Ls(cse), S(rest), End()) - }): - // staged block - blocksCont.collectApply: xs => - val (sps, cdes) = xs.map(xi => (xi.shape, xi.code)).unzip - fnMrg(sps): s => - (patts - .zip(cdes) - .foldRight(blockCtor("End", Ls())) { case ((patt, cde), restCont) => - (k: Path => Block) => - restCont: rest => - blockCtor("Match", Ls(x.code, patt, cde, rest))(k) - })(StagedPath.mk(s, _)(k)) + (arms.map((c, b) => (S(c), b)) ++ (dflt.map((N, _)))) + .map: (c, b) => + val concatBlock = concat(b, rest) + (k: (((Path, (StagedPath => Block) => Block)) => Block)) => + transformCase(c): patt => + fnSilh(patt): sp => + val newCtx = ctx.clone() += (p -> sp) + val blockCont = transformBlock(concatBlock)(using newCtx) + k(patt, blockCont) + .collectApply: arms => + // we need to duplicate the blocks anyways, so it's fine that blocksCont gets evaluated twice + val (patts, blocksCont) = arms.unzip + (arms.zipWithIndex.foldRight(_: Block) { case (((patt, blockCont), i), rest) => + val slice = arms.slice(0, i + 1).map(_._1) + fnDet(x.shape, slice): scrut => + blockCont: block => + val cse = Case.Lit(Tree.BoolLit(false)) -> k(block) + Match(scrut, Ls(cse), S(rest), End()) + }): + // staged block + blocksCont.collectApply: xs => + val (shapes, codes) = xs.map(xi => (xi.shape, xi.code)).unzip + fnMrg(shapes): s => + (patts + .zip(codes) + .foldRight(blockCtor("End", Ls())) { case ((patt, cde), restCont) => + (k: Path => Block) => + restCont: rest => + blockCtor("Match", Ls(x.code, patt, cde, rest))(k) + })(StagedPath.mk(s, _)(k)) def ruleAssign(a: Assign)(using Context)(k: StagedPath => Block): Block = val Assign(x, r, b) = a From 64960a87cb227a5ed16590f529efb63d0bb418c8 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 4 Nov 2025 00:52:05 +0800 Subject: [PATCH 063/268] fix ruleTup --- hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 3c81fcf070..7c12319454 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -171,7 +171,7 @@ class Instrumentation(using State): transformArgs(elems): xs => tuple(xs.map(_.shape)): shapes => shapeCtor("Arr", Ls(shapes)): sp => - tuple(xs.map(_.code)): cde => // is Tuple quotes as well? + blockCtor("Tuple", xs.map(_.code)): cde => StagedPath.mk(sp, cde)(k) def ruleSel(s: Select)(using Context)(k: StagedPath => Block): Block = From a264406bd8480e68a66511178878c487944a975c Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 4 Nov 2025 00:54:33 +0800 Subject: [PATCH 064/268] reduce supported cases to make mvp --- .../scala/hkmc2/codegen/Instrumentation.scala | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 7c12319454..94ac6a35a4 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -84,7 +84,10 @@ class Instrumentation(using State): def blockCtor(name: String, args: Ls[PathLike])(k: Path => Block): Block = ctor(blockMod(name), args)(k) def shapeCtor(name: String, args: Ls[PathLike])(k: Shape => Block): Block = - ctor(shapeMod(name), args)(p => k(Shape(p))) + // ctor(shapeMod(name), args)(p => k(Shape(p))) + // override handling shape + if name == "Lit" then ctor(shapeMod("Lit"), args)(p => k(Shape(p))) + else ctor(shapeMod("Dyn"), Ls())(p => k(Shape(p))) def blockCall(name: String, args: Ls[PathLike])(k: Path => Block): Block = call(blockMod(name), args)(k) @@ -303,17 +306,18 @@ class Instrumentation(using State): def transformPath(p: Path)(using Context)(k: StagedPath => Block): Block = p match - case s: Select => ruleSel(s)(k) - case d: DynSelect => ruleDynSel(d)(k) + // case s: Select => ruleSel(s)(ruleRefinedPath(_)(k)) + // case d: DynSelect => ruleDynSel(d)(ruleRefinedPath(_)(k)) + // case r: Value.Ref => ruleVar(r)(ruleRefinedPath(_)(k)) case r: Value.Ref => ruleVar(r)(k) case Value.Lit(lit) => ruleLit(lit)(k) case _ => ??? // not supported def transformResult(r: Result)(using Context)(k: StagedPath => Block): Block = r match - case c: Call => ruleApp(c)(k) - case i: Instantiate => ruleInst(i)(k) - case t: Tuple => ruleTup(t)(k) + // case c: Call => ruleApp(c)(k) + // case i: Instantiate => ruleInst(i)(k) + // case t: Tuple => ruleTup(t)(k) case p: Path => transformPath(p)(k) case _: Lambda | _: Record => ??? // not supported @@ -342,9 +346,9 @@ class Instrumentation(using State): def transformBlock(b: Block)(using Context)(k: StagedPath => Block): Block = b match - case m: Match => ruleMatch(m)(k) + // case m: Match => ruleMatch(m)(k) case r: Return => ruleReturn(r)(k) - case a: Assign => ruleAssign(a)(k) + // case a: Assign => ruleAssign(a)(k) case d: Define => transformDefine(d)(k) case End(_) => ruleEnd()(k) case _ => ??? // not supported From 4ae88977a10eaa94d82ec4702e7647067e566654 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 1 Nov 2025 16:32:57 +0800 Subject: [PATCH 065/268] Update Syntax.mls --- .../src/test/mlscript/staging/Syntax.mls | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index c24dfc0a3a..be4cbbcdc5 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -60,6 +60,45 @@ staged fun f() = 0 //│ rhs = Tup of Nil //│ rhs = S of IntLit of 0 +:js +:lot +:slot +staged module B +//│ Lowered: +//│ Program: +//│ imports = Nil +//│ main = Define: +//│ defn = ClsLikeDefn: +//│ owner = N +//│ isym = class:B +//│ sym = member:B +//│ k = Cls +//│ paramsOpt = N +//│ auxParams = Nil +//│ parentPath = N +//│ methods = Nil +//│ privateFields = Nil +//│ publicFields = Nil +//│ preCtor = End of "" +//│ ctor = Return: +//│ res = Select{object:Unit}: +//│ qual = Ref of $runtime +//│ name = Ident of "Unit" +//│ implct = true +//│ companion = S of ClsLikeBody: +//│ isym = module:B +//│ methods = Nil +//│ privateFields = Nil +//│ publicFields = Nil +//│ ctor = End of "" +//│ staged = true +//│ rest = Assign: \ +//│ lhs = $block$res +//│ rhs = Lit of UnitLit of false +//│ rest = End of "" +//│ Pretty Lowered: +//│ define class B in set block$res = undefined in end + :js :lot :slot From 88c3a5ef60d975d1722a505ca82d190245ee1881 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 4 Nov 2025 19:36:17 +0800 Subject: [PATCH 066/268] move detecting staged annotation to ClsLikeDefn --- .../src/main/scala/hkmc2/codegen/Block.scala | 9 -- .../main/scala/hkmc2/codegen/Lowering.scala | 15 +++- .../main/scala/hkmc2/codegen/Printer.scala | 6 +- .../src/main/scala/hkmc2/semantics/Term.scala | 2 + .../test/mlscript/codegen/FieldSymbols.mls | 2 +- .../src/test/mlscript/staging/Syntax.mls | 90 ++----------------- 6 files changed, 27 insertions(+), 97 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala index b622df8e5e..4ed29658f2 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala @@ -340,15 +340,6 @@ final case class FunDefn( body: Block, ) extends Defn: val innerSym = N - var staged = false - - -object FunDefn: - def apply(owner: Opt[InnerSymbol], sym: BlockMemberSymbol, params: Ls[ParamList], body: Block, staged: Boolean): FunDefn = - var f = new FunDefn(owner, sym, params, body) - f.staged = staged - f - final case class ValDefn( tsym: TermSymbol, diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index 5b2109f482..edda9dfbbc 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -178,8 +178,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): blockImpl(stats, res)(k))) case syntax.Fun => val (paramLists, bodyBlock) = setupFunctionOrByNameDef(td.params, bod, S(td.sym.nme)) - val isStaged = td.extraAnnotations.contains(Annot.Modifier(syntax.Keyword.`staged`)) - Define(FunDefn(td.owner, td.sym, paramLists, bodyBlock, isStaged), + Define(FunDefn(td.owner, td.sym, paramLists, bodyBlock), blockImpl(stats, res)(k)) case syntax.Ins => // Implicit instances are not parameterized for now. @@ -1027,7 +1026,9 @@ class Lowering()(using Config, TL, Raise, State, Ctx): if lift then Lifter(S(handlerPaths)).transform(flattened) else flattened - val res = MergeMatchArmTransformer.applyBlock(lifted) + val merged = MergeMatchArmTransformer.applyBlock(lifted) + + val res = Instrumentation(using summon).applyBlock(merged) Program( imps.map(imp => imp.sym -> imp.file), @@ -1205,3 +1206,11 @@ object MergeMatchArmTransformer extends BlockTransformer(new SymbolSubst()): k.getOrElse(identity: Block => Block)(Match(scrut, arms ::: newArms, dfltRewritten, rest)) case _ => m case b => b + +class Instrumentation(using Raise) extends BlockTransformer(new SymbolSubst()): + override def applyDefn(d: Defn): Defn = super.applyDefn(d) match + case defn: ClsLikeDefn => + if defn.sym.defn.exists(_.hasStagedModifier.isDefined) + then raise(WarningReport(msg"`staged` keyword doesn't do anything currently." -> defn.sym.toLoc :: Nil)) + defn + case b => b \ No newline at end of file diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index a93b8f0fc3..d6a476b37d 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -63,8 +63,7 @@ object Printer: case fd @ FunDefn(own, sym, params, body) => val docParams = doc"${own.fold("")(_.toString+"::")}${params.map(_.params.map(x => summon[Scope].allocateName(x.sym)).mkString("(", ", ", ")")).mkString("")}" val docBody = mkDocument(body) - val docStaged = if fd.staged then doc"staged " else doc"" - doc"${docStaged}fun ${sym.nme}${docParams} { #{ # ${docBody} #} # }" + doc"fun ${sym.nme}${docParams} { #{ # ${docBody} #} # }" case ValDefn(tsym, sym, rhs) => doc"val ${tsym.nme} = ${mkDocument(rhs)}" case ClsLikeDefn(own, _, sym, k, paramsOpt, auxParams, parentSym, methods, @@ -83,7 +82,8 @@ object Printer: val docPubFlds = if publicFields.isEmpty then doc"" else doc" # ${pubFields}" val docBody = if publicFields.isEmpty && privateFields.isEmpty then doc"" else doc" { #{ ${docPrivFlds}${docPubFlds} #} # }" val docCtorParams = if clsParams.isEmpty then doc"" else doc"(${ctorParams.mkString(", ")})" - doc"class ${own.fold("")(_.toString+"::")}${sym.nme}${docCtorParams}${docBody}" + val docStaged = if !sym.defn.exists(_.hasStagedModifier.isDefined) then doc"" else doc"staged " + doc"${docStaged}class ${own.fold("")(_.toString+"::")}${sym.nme}${docCtorParams}${docBody}" def mkDocument(arg: Arg)(using Raise, Scope): Document = val doc = mkDocument(arg.value) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala index 98c6a15298..42ae9eb350 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala @@ -676,6 +676,8 @@ sealed abstract class Definition extends Declaration, Statement: val annotations: Ls[Annot] def hasDeclareModifier: Opt[Annot.Modifier] = annotations.collectFirst: case mod @ Annot.Modifier(Keyword.`declare`) => mod + def hasStagedModifier: Opt[Annot.Modifier] = annotations.collectFirst: + case mod @ Annot.Modifier(Keyword.`staged`) => mod sealed trait CompanionValue extends Definition diff --git a/hkmc2/shared/src/test/mlscript/codegen/FieldSymbols.mls b/hkmc2/shared/src/test/mlscript/codegen/FieldSymbols.mls index 867c672bcf..702afdc8d7 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/FieldSymbols.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/FieldSymbols.mls @@ -90,7 +90,7 @@ case //│ Program: //│ imports = Nil //│ main = Define: -//│ defn = FunDefn (staged=false): +//│ defn = FunDefn: //│ owner = N //│ sym = member:lambda //│ params = Ls of diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index be4cbbcdc5..dce73de7dc 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -1,33 +1,15 @@ :pt -staged module A with - fun f(x) = x -A.f(1) +staged module A //│ Parsed tree: //│ Modified: //│ modifier = Keywrd of keyword 'staged' //│ body = TypeDef: //│ k = Mod -//│ head = InfixApp: -//│ lhs = Ident of "A" -//│ kw = keyword 'with' -//│ rhs = Block of Ls of -//│ TermDef: -//│ k = Fun -//│ head = App: -//│ lhs = Ident of "f" -//│ rhs = Tup of Ls of -//│ Ident of "x" -//│ rhs = S of Ident of "x" +//│ head = Ident of "A" //│ rhs = N -//│ App: -//│ lhs = Sel: -//│ prefix = Ident of "A" -//│ name = Ident of "f" -//│ rhs = Tup of Ls of -//│ IntLit of 1 -// TODO: reject these annotations +// TODO: reject these annotations? :pt staged object Foo //│ Parsed tree: @@ -61,66 +43,12 @@ staged fun f() = 0 //│ rhs = S of IntLit of 0 :js -:lot :slot -staged module B -//│ Lowered: -//│ Program: -//│ imports = Nil -//│ main = Define: -//│ defn = ClsLikeDefn: -//│ owner = N -//│ isym = class:B -//│ sym = member:B -//│ k = Cls -//│ paramsOpt = N -//│ auxParams = Nil -//│ parentPath = N -//│ methods = Nil -//│ privateFields = Nil -//│ publicFields = Nil -//│ preCtor = End of "" -//│ ctor = Return: -//│ res = Select{object:Unit}: -//│ qual = Ref of $runtime -//│ name = Ident of "Unit" -//│ implct = true -//│ companion = S of ClsLikeBody: -//│ isym = module:B -//│ methods = Nil -//│ privateFields = Nil -//│ publicFields = Nil -//│ ctor = End of "" -//│ staged = true -//│ rest = Assign: \ -//│ lhs = $block$res -//│ rhs = Lit of UnitLit of false -//│ rest = End of "" +:w +staged module A +//│ ╔══[WARNING] `staged` keyword doesn't do anything currently. +//│ ║ l.48: staged module A +//│ ╙── ^^^^^^^^ //│ Pretty Lowered: -//│ define class B in set block$res = undefined in end +//│ define staged class A in set block$res = undefined in end -:js -:lot -:slot -staged fun f() = 0 -//│ Lowered: -//│ Program: -//│ imports = Nil -//│ main = Define: -//│ defn = FunDefn (staged=true): -//│ owner = N -//│ sym = member:f -//│ params = Ls of -//│ ParamList: -//│ flags = () -//│ params = Nil -//│ restParam = N -//│ body = Return: -//│ res = Lit of IntLit of 0 -//│ implct = false -//│ rest = Assign: \ -//│ lhs = $block$res -//│ rhs = Lit of UnitLit of false -//│ rest = End of "" -//│ Pretty Lowered: -//│ define staged fun f() { return 0 } in set block$res = undefined in end From 17701b9332d31d2ec67cc6b2aa3bdfe9f1d06f75 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 4 Nov 2025 19:38:47 +0800 Subject: [PATCH 067/268] move importing to diff testing compiler flag --- hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala | 2 -- .../shared/src/main/scala/hkmc2/semantics/Elaborator.scala | 1 + hkmc2/shared/src/test/mlscript-compile/Predef.mjs | 1 - hkmc2/shared/src/test/mlscript-compile/Runtime.mjs | 1 - hkmc2/shared/src/test/mlscript-compile/Shape.mls | 0 .../src/test/scala/hkmc2/JSBackendDiffMaker.scala | 7 ++++++- hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala | 7 +++++-- 7 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript-compile/Shape.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala b/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala index 54007a0df9..abcbaff56b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/MLsCompiler.scala @@ -41,7 +41,6 @@ class MLsCompiler(preludeFile: os.Path, mkOutput: ((Str => Unit) => Unit) => Uni val runtimeFile: os.Path = preludeFile/os.up/os.up/os.up/"mlscript-compile"/"Runtime.mjs" val termFile: os.Path = preludeFile/os.up/os.up/os.up/"mlscript-compile"/"Term.mjs" - val blockFile: os.Path = preludeFile/os.up/os.up/os.up/"mlscript-compile"/"Block.mjs" val report = ReportFormatter: outputConsumer => @@ -88,7 +87,6 @@ class MLsCompiler(preludeFile: os.Path, mkOutput: ((Str => Unit) => Unit) => Uni val blk = new semantics.Term.Blk( semantics.Import(State.runtimeSymbol, runtimeFile.toString) :: semantics.Import(State.termSymbol, termFile.toString) - :: semantics.Import(State.blockSymbol, blockFile.toString) :: blk0.stats, blk0.res ) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index cf1d8f2064..adb65752f5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -224,6 +224,7 @@ object Elaborator: val prettyPrintSymbol = TempSymbol(N, "prettyPrint") val termSymbol = TempSymbol(N, "Term") val blockSymbol = TempSymbol(N, "Block") + val shapeSymbol = TempSymbol(N, "Shape") val effectSigSymbol = ClassSymbol(DummyTypeDef(syntax.Cls), Ident("EffectSig")) val nonLocalRetHandlerTrm = val id = new Ident("NonLocalReturn") diff --git a/hkmc2/shared/src/test/mlscript-compile/Predef.mjs b/hkmc2/shared/src/test/mlscript-compile/Predef.mjs index c43f0fdf6d..d1a8d1fb79 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Predef.mjs +++ b/hkmc2/shared/src/test/mlscript-compile/Predef.mjs @@ -2,7 +2,6 @@ const definitionMetadata = globalThis.Symbol.for("mlscript.definitionMetadata"); const prettyPrint = globalThis.Symbol.for("mlscript.prettyPrint"); import runtime from "./Runtime.mjs"; import Term from "./Term.mjs"; -import Block from "./Block.mjs"; import RuntimeJS from "./RuntimeJS.mjs"; import Runtime from "./Runtime.mjs"; import Rendering from "./Rendering.mjs"; diff --git a/hkmc2/shared/src/test/mlscript-compile/Runtime.mjs b/hkmc2/shared/src/test/mlscript-compile/Runtime.mjs index 250868463e..7b1c3e8013 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Runtime.mjs +++ b/hkmc2/shared/src/test/mlscript-compile/Runtime.mjs @@ -2,7 +2,6 @@ const definitionMetadata = globalThis.Symbol.for("mlscript.definitionMetadata"); const prettyPrint = globalThis.Symbol.for("mlscript.prettyPrint"); import runtime from "./Runtime.mjs"; import Term from "./Term.mjs"; -import Block from "./Block.mjs"; import RuntimeJS from "./RuntimeJS.mjs"; import Rendering from "./Rendering.mjs"; import LazyArray from "./LazyArray.mjs"; diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls new file mode 100644 index 0000000000..e69de29bb2 diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala index 6fd0ddc9c1..a450b5c6e1 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala @@ -32,6 +32,8 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: val runtimeNme = baseScp.allocateName(Elaborator.State.runtimeSymbol) val termNme = baseScp.allocateName(Elaborator.State.termSymbol) + val blockNme = baseScp.allocateName(Elaborator.State.blockSymbol) + val shapeNme = baseScp.allocateName(Elaborator.State.shapeSymbol) val definitionMetadataNme = baseScp.allocateName(Elaborator.State.definitionMetadataSymbol) val prettyPrintNme = baseScp.allocateName(Elaborator.State.prettyPrintSymbol) @@ -57,6 +59,9 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: h.execute(s"const $definitionMetadataNme = Symbol.for(\"mlscript.definitionMetadata\");") h.execute(s"const $prettyPrintNme = Symbol.for(\"mlscript.prettyPrint\");") if importQQ.isSet then importRuntimeModule(termNme, termFile) + if stageCode.isSet then + importRuntimeModule(blockNme, blockFile) + importRuntimeModule(shapeNme, shapeFile) h private var hostCreated = false @@ -113,7 +118,7 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: ) if showLoweredTree.isSet then output(s"Lowered:") - output(le.showAsTree(using { case fd : hkmc2.codegen.FunDefn => s"staged=${fd.staged}" case _ => ""})) + output(le.showAsTree) // * We used to do this to avoid needlessly generating new variable names in separate blocks: // val nestedScp = baseScp.nest diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index 6c292f2534..a588fb0e72 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -21,6 +21,7 @@ abstract class MLsDiffMaker extends DiffMaker: val runtimeFile: os.Path = predefFile/os.up/"Runtime.mjs" // * Contains MLscript runtime definitions val termFile: os.Path = predefFile/os.up/"Term.mjs" // * Contains MLscript runtime term definitions val blockFile: os.Path = predefFile/os.up/"Block.mjs" // * Contains MLscript runtime block definitions + val shapeFile: os.Path = predefFile/os.up/"Shape.mjs" // * Contains MLscript runtime shape definitions val wd = file / os.up @@ -64,7 +65,7 @@ abstract class MLsDiffMaker extends DiffMaker: val stackSafe = Command("stackSafe")(_.trim) val liftDefns = NullaryCommand("lift") val importQQ = NullaryCommand("qq") - val staging = NullaryCommand("staging") + val stageCode = NullaryCommand("ds") def mkConfig: Config = import Config.* @@ -152,10 +153,12 @@ abstract class MLsDiffMaker extends DiffMaker: given Config = mkConfig processTrees( PrefixApp(Keywrd(`import`), StrLit(termFile.toString)) :: Nil) - if staging.isSet then + if stageCode.isSet then given Config = mkConfig processTrees( PrefixApp(Keywrd(`import`), StrLit(blockFile.toString)) :: Nil) + processTrees( + PrefixApp(Keywrd(`import`), StrLit(shapeFile.toString)) :: Nil) super.init() From 5ccb64cc36cb32a442b0e0fa3add00f48958db14 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 4 Nov 2025 20:07:00 +0800 Subject: [PATCH 068/268] revert formatting changes --- hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala | 1 + hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala | 2 +- hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala index 4ed29658f2..c8b9ccd103 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala @@ -341,6 +341,7 @@ final case class FunDefn( ) extends Defn: val innerSym = N + final case class ValDefn( tsym: TermSymbol, sym: BlockMemberSymbol, diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index edda9dfbbc..f15199fc77 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -62,7 +62,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): tl.trace[Term](s"Expanding term ${r}", post = t => s"~> ${t}"): r.expanded case t => t - + val lowerHandlers: Bool = config.effectHandlers.isDefined val lift: Bool = config.liftDefns.isDefined diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index d6a476b37d..c6637475b6 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -60,8 +60,8 @@ object Printer: case _ => TODO(blk) def mkDocument(defn: Defn)(using Raise, Scope): Document = defn match - case fd @ FunDefn(own, sym, params, body) => - val docParams = doc"${own.fold("")(_.toString+"::")}${params.map(_.params.map(x => summon[Scope].allocateName(x.sym)).mkString("(", ", ", ")")).mkString("")}" + case FunDefn(own, sym, params, body) => + val docParams = doc"${own.fold("")(_.toString+"::")}${params.map(_.params.map(x => summon[Scope].allocateName(x.sym)).mkString("(", ", ", ")")).mkString}" val docBody = mkDocument(body) doc"fun ${sym.nme}${docParams} { #{ # ${docBody} #} # }" case ValDefn(tsym, sym, rhs) => From 980d89c6b02ba4549f17556cd08236f6621d83fc Mon Sep 17 00:00:00 2001 From: Ching Long Tin <26105652+ChingLongTin@users.noreply.github.com> Date: Wed, 5 Nov 2025 18:46:31 +0800 Subject: [PATCH 069/268] Update Printer.scala Co-authored-by: Lionel Parreaux --- hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index c6637475b6..0e94b7aa7f 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -82,7 +82,7 @@ object Printer: val docPubFlds = if publicFields.isEmpty then doc"" else doc" # ${pubFields}" val docBody = if publicFields.isEmpty && privateFields.isEmpty then doc"" else doc" { #{ ${docPrivFlds}${docPubFlds} #} # }" val docCtorParams = if clsParams.isEmpty then doc"" else doc"(${ctorParams.mkString(", ")})" - val docStaged = if !sym.defn.exists(_.hasStagedModifier.isDefined) then doc"" else doc"staged " + val docStaged = if sym.defn.forall(_.hasStagedModifier.isEmpty) then doc"" else doc"staged " doc"${docStaged}class ${own.fold("")(_.toString+"::")}${sym.nme}${docCtorParams}${docBody}" def mkDocument(arg: Arg)(using Raise, Scope): Document = From ce1e38ca8911fe1b57032225e1613690a9f72802 Mon Sep 17 00:00:00 2001 From: Ching Long Tin <26105652+ChingLongTin@users.noreply.github.com> Date: Wed, 5 Nov 2025 18:47:50 +0800 Subject: [PATCH 070/268] Update Lowering.scala Co-authored-by: Lionel Parreaux --- hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index f15199fc77..4418a54a81 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -1213,4 +1213,4 @@ class Instrumentation(using Raise) extends BlockTransformer(new SymbolSubst()): if defn.sym.defn.exists(_.hasStagedModifier.isDefined) then raise(WarningReport(msg"`staged` keyword doesn't do anything currently." -> defn.sym.toLoc :: Nil)) defn - case b => b \ No newline at end of file + case b => b From 317c6f6c3a2ae963d064f1ad3b011da396bc1dfe Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 5 Nov 2025 21:14:47 +0800 Subject: [PATCH 071/268] remove redundant :pt --- .../src/test/mlscript/staging/Syntax.mls | 35 +------------------ 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index dce73de7dc..733594c96d 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -9,45 +9,12 @@ staged module A //│ head = Ident of "A" //│ rhs = N -// TODO: reject these annotations? -:pt -staged object Foo -//│ Parsed tree: -//│ Modified: -//│ modifier = Keywrd of keyword 'staged' -//│ body = TypeDef: -//│ k = Obj -//│ head = Ident of "Foo" -//│ rhs = N - -:pt -staged class Foo -//│ Parsed tree: -//│ Modified: -//│ modifier = Keywrd of keyword 'staged' -//│ body = TypeDef: -//│ k = Cls -//│ head = Ident of "Foo" -//│ rhs = N - -:pt -staged fun f() = 0 -//│ Parsed tree: -//│ Modified: -//│ modifier = Keywrd of keyword 'staged' -//│ body = TermDef: -//│ k = Fun -//│ head = App: -//│ lhs = Ident of "f" -//│ rhs = Tup of Nil -//│ rhs = S of IntLit of 0 - :js :slot :w staged module A //│ ╔══[WARNING] `staged` keyword doesn't do anything currently. -//│ ║ l.48: staged module A +//│ ║ l.15: staged module A //│ ╙── ^^^^^^^^ //│ Pretty Lowered: //│ define staged class A in set block$res = undefined in end From 9023eecc3bc42ec16a9b9617b19e53ef2206c5c4 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 5 Nov 2025 21:21:01 +0800 Subject: [PATCH 072/268] fix syntax error --- hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala | 6 +++--- hkmc2/shared/src/test/mlscript/staging/Syntax.mls | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index 5e91d08ffe..9bab660436 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -1250,9 +1250,9 @@ object MergeMatchArmTransformer extends BlockTransformer(new SymbolSubst()): case b => b class Instrumentation(using Raise) extends BlockTransformer(new SymbolSubst()): - override def applyDefn(d: Defn): Defn = super.applyDefn(d) match + override def applyDefn(d: Defn)(k: Defn => Block): Block = d match case defn: ClsLikeDefn => if defn.sym.defn.exists(_.hasStagedModifier.isDefined) then raise(WarningReport(msg"`staged` keyword doesn't do anything currently." -> defn.sym.toLoc :: Nil)) - defn - case b => b + super.applyDefn(defn)(k) + case b => super.applyDefn(b)(k) diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index 733594c96d..ee2e0b02be 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -18,4 +18,3 @@ staged module A //│ ╙── ^^^^^^^^ //│ Pretty Lowered: //│ define staged class A in set block$res = undefined in end - From 9fc83dcd6e9317bef07f5fe633e7aa00fb0b90c0 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 6 Nov 2025 01:12:36 +0800 Subject: [PATCH 073/268] fix type hint for arms in Match --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 534fe777ac..70c82c9883 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -54,7 +54,7 @@ class ClsLikeBody(val isym: Symbol, val methods: Array[FunDefn], val publicField class Block with constructor - Match(val scrut: Path, val arms: Array[Case -> Block], val dflt: Opt[Block], val rest: Block) + Match(val scrut: Path, val arms: Array[[Case, Block]], val dflt: Opt[Block], val rest: Block) Return(val res: Result, val implct: Bool) Assign(val lhs: Symbol, val rhs: Result, val rest: Block) Define(val defn: Defn, val rest: Block) From 7b702f344fa1f6a715ff7c6f3b8657a9dfb70626 Mon Sep 17 00:00:00 2001 From: TYeung Date: Thu, 6 Nov 2025 02:36:28 +0800 Subject: [PATCH 074/268] add preliminary printCode function --- .../src/test/mlscript-compile/Block.mls | 180 ++++++++++++++++++ .../test/scala/hkmc2/JSBackendDiffMaker.scala | 2 +- .../src/test/scala/hkmc2/MLsDiffMaker.scala | 4 +- 3 files changed, 184 insertions(+), 2 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index e69de29bb2..13b4457051 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -0,0 +1,180 @@ +import "./Predef.mls" +import "./Option.mls" +import "./StrOps.mls" + +open StrOps +open Predef +open Option + +module Block with... + +type Opt[A] = Option[A] + +// dependancies referenced in Block classes, referencing implementation in Term.mls + +class Symbol(val name: Str) +type Ident = Symbol + +type Literal = null | undefined | Str | Int | Num | Bool +class Arg(val spread: Opt[Bool], val value: Path) // unused + +type ParamList = Array[Symbol] + +// Classes defined in Block.scala + +class Path with + constructor + Select(val qual: Path, val name: Ident) + DynSelect(val qual: Path, val fld: Path, val arrayIdx: Bool) + ValueRef(val l: Symbol) + ValueLit(val lit: Literal) + +// Match pattern for staged code +class Case with + constructor + Lit(val lit: Literal) + Cls(val cls: Symbol, val path: Path) + Tup(val len: Int, val inf: Bool) // TODO: remove inf? + Field(val name: Ident) + Wildcard + +class Result with + constructor + // unused? + TrivialResult(val path: Path) // only Path extends TrivialResult + Call(val _fun: Path, val args: Array[Arg]) + Instantiate(val cls: Path, val args: Array[Arg]) // assume immutable + Tuple(val elems: Array[Arg]) // assume immutable + +class Defn with + constructor + ValDefn(val sym: Symbol, val rhs: Path) + ClsLikeDefn(val sym: Symbol, val paramsOpt: Opt[ParamList], val companion: Opt[ClsLikeBody]) // unused + FunDefn(val sym: Symbol, val params: Array[ParamList], val body: Block) + +class ClsLikeBody(val isym: Symbol, val methods: Array[FunDefn], val publicFields: Array[[Symbol, Symbol]]) // unused + +class Block with + constructor + Match(val scrut: Path, val arms: Array[[Case, Block]], val dflt: Opt[Block], val rest: Block) + Return(val res: Result, val implct: Bool) + Assign(val lhs: Symbol, val rhs: Result, val rest: Block) + Define(val defn: Defn, val rest: Block) + End() + +fun showBool(b: Bool) = if b then "true" else "false" + +fun showLiteral(l: Literal) = l.toString() + +fun showSymbol(s: Symbol) = "Symbol(" + "\"" + s.name + "\"" + ")" + +fun showIdent(i: Ident) = showSymbol(i) + +fun showPath(p: Path): Str = + if p is + Select(qual, name) then + "Select(" + showPath(qual) + ", " + showIdent(name) + ")" + DynSelect(qual, fld, arrayIdx) then + "DynSelect(" + showPath(qual) + ", " + showPath(fld) + ", " + showBool(arrayIdx) + ")" + ValueRef(l) then + "Ref(" + showSymbol(l) + ")" + ValueLit(lit) then + "Lit(" + showLiteral(lit) + ")" + +fun showArg(a: Arg) = + if a.spread is + Some(true) then "..." + showPath(a.value) + _ then showPath(a.value) + +fun showArgs(args: Array[Arg]) = + "[" + args.map(showArg).joinWith(", ") + "]" + +// Case (match arm patterns) +fun showCase(c: Case): Str = + if c is + Lit(lit) then "Lit(" + showLiteral(lit) + ")" + Cls(cls, path) then "Cls(" + showSymbol(cls) + ", " + showPath(path) + ")" + Tup(len, inf) then "Tup(" + len + ", " + showBool(inf) + ")" + Field(name) then "Field(" + showIdent(name) + ")" + Wildcard then "Wildcard" + +fun showResult(r: Result): Str = + if r is + TrivialResult(path) then showPath(path) + Call(f, args) then "Call(" + showPath(f) + ", " + showArgs(args) + ")" + Instantiate(cls, args) then "Instantiate(" + showPath(cls) + ", " + showArgs(args) + ")" + Tuple(elems) then "Tuple(" + showArgs(elems) + ")" + +fun showParamList(ps: ParamList) = + "[" + ps.map(showSymbol).joinWith(", ") + "]" + +fun showDefn(d: Defn): Str = + if d is + ValDefn(sym, rhs) then + "ValDefn(" + showSymbol(sym) + ", " + showPath(rhs) + ")" + FunDefn(sym, params, body) then + "FunDefn(" + showSymbol(sym) + ", " + + "[" + params.map(showParamList).joinWith(", ") + "], " + + showBlock(body) + ")" + ClsLikeDefn(sym, paramsOpt, companion) then + // minimal, since this is unused in your staged Block for now + "ClsLikeDefn(" + showSymbol(sym) + ")" + +fun showOptBlock(ob: Opt[Block]) = + if ob is Some(b) then showBlock(b) else "None" + +fun showArm(pair: Case -> Block) = + if pair is [cse, body] then showCase(cse) + " -> " + showBlock(body) else "" + +fun showBlock(b: Block): Str = + if b is + Match(scrut, arms, dflt, rest) then + "Match(" + + showPath(scrut) + ", " + + "[" + arms.map(showArm).joinWith(", ") + "], " + + showOptBlock(dflt) + ", " + + showBlock(rest) + ")" + Return(res, implct) then + "Return(" + showResult(res) + ", " + showBool(implct) + ")" + Assign(lhs, rhs, rest) then + "Assign(" + showSymbol(lhs) + ", " + showResult(rhs) + ", " + showBlock(rest) + ")" + Define(defn, rest) then + "Define(" + showDefn(defn) + ", " + showBlock(rest) + ")" + End() then "End" + +fun show(x) = + if x is + Match(_, _, _, _) then showBlock(x) + Return(_, _) then showBlock(x) + Assign(_, _, _) then showBlock(x) + Define(_, _) then showBlock(x) + End() then showBlock(x) + else if x is + Select(_, _) then showPath(x) + DynSelect(_, _, _) then showPath(x) + ValueRef(_) then showPath(x) + ValueLit(_) then showPath(x) + else if x is + TrivialResult(_) then showResult(x) + Call(_, _) then showResult(x) + Instantiate(_, _) then showResult(x) + Tuple(_) then showResult(x) + else if x is + Lit(_) then showCase(x) + Cls(_, _) then showCase(x) + Tup(_, _) then showCase(x) + Field(_) then showCase(x) + Wildcard then showCase(x) + else if x is + ValDefn(_, _) then showDefn(x) + FunDefn(_, _, _) then showDefn(x) + ClsLikeDefn(_, _, _) then showDefn(x) + else if x is + Arg(_, _) then showArg(x) + else if x is + [a, b] then StrOps.concat of "[", show(a), ", ", show(b), "]" + else + "" + + +fun compile(p: Block) = ??? \ No newline at end of file diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala index 2bf32e5879..3695c08b0f 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala @@ -61,7 +61,7 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: if importQQ.isSet then importRuntimeModule(termNme, termFile) if stageCode.isSet then importRuntimeModule(blockNme, blockFile) - importRuntimeModule(shapeNme, shapeFile) + // importRuntimeModule(shapeNme, shapeFile) h private var hostCreated = false diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index c9ee6dd0f7..ddb8b731ee 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -21,7 +21,7 @@ abstract class MLsDiffMaker extends DiffMaker: val runtimeFile: os.Path = predefFile/os.up/"Runtime.mjs" // * Contains MLscript runtime definitions val termFile: os.Path = predefFile/os.up/"Term.mjs" // * Contains MLscript runtime term definitions val blockFile: os.Path = predefFile/os.up/"Block.mjs" // * Contains MLscript runtime block definitions - val shapeFile: os.Path = predefFile/os.up/"Shape.mjs" // * Contains MLscript runtime shape definitions + // val shapeFile: os.Path = predefFile/os.up/"Shape.mjs" // * Contains MLscript runtime shape definitions val wd = file / os.up @@ -163,8 +163,10 @@ abstract class MLsDiffMaker extends DiffMaker: given Config = mkConfig processTrees( PrefixApp(Keywrd(`import`), StrLit(blockFile.toString)) :: Nil) + /* processTrees( PrefixApp(Keywrd(`import`), StrLit(shapeFile.toString)) :: Nil) + */ super.init() From e4d7b227ee3cab3d5a7461ec746cf23468b5ae8d Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 6 Nov 2025 16:41:14 +0800 Subject: [PATCH 075/268] move instrumentation to JSBackendDiffMaker --- .../scala/hkmc2/codegen/Instrumentation.scala | 15 +++++++++++++++ .../src/main/scala/hkmc2/codegen/Lowering.scala | 12 +----------- hkmc2/shared/src/test/mlscript/staging/Syntax.mls | 3 ++- .../src/test/scala/hkmc2/JSBackendDiffMaker.scala | 5 ++++- 4 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala new file mode 100644 index 0000000000..3232ad7b09 --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -0,0 +1,15 @@ +package hkmc2 +package codegen + +import utils.* +import hkmc2.Message.MessageContext + +class Instrumentation(using Raise) extends BlockTransformer(new SymbolSubst()): + def transform(prgm: Program) = Program(prgm.imports, applyBlock(prgm.main)) + + override def applyDefn(d: Defn)(k: Defn => Block): Block = d match + case defn: ClsLikeDefn => + if defn.sym.defn.exists(_.hasStagedModifier.isDefined) && defn.companion.isDefined + then raise(WarningReport(msg"`staged` keyword doesn't do anything currently." -> defn.sym.toLoc :: Nil)) + super.applyDefn(defn)(k) + case b => super.applyDefn(b)(k) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index 9bab660436..8d242536df 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -1068,9 +1068,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): val bufferable = BufferableTransform().transform(lifted) - val merged = MergeMatchArmTransformer.applyBlock(bufferable) - - val res = Instrumentation(using summon).applyBlock(merged) + val res = MergeMatchArmTransformer.applyBlock(bufferable) Program( imps.map(imp => imp.sym -> imp.str), @@ -1248,11 +1246,3 @@ object MergeMatchArmTransformer extends BlockTransformer(new SymbolSubst()): k.getOrElse(identity: Block => Block)(Match(scrut, arms ::: newArms, dfltRewritten, rest)) case _ => m case b => b - -class Instrumentation(using Raise) extends BlockTransformer(new SymbolSubst()): - override def applyDefn(d: Defn)(k: Defn => Block): Block = d match - case defn: ClsLikeDefn => - if defn.sym.defn.exists(_.hasStagedModifier.isDefined) - then raise(WarningReport(msg"`staged` keyword doesn't do anything currently." -> defn.sym.toLoc :: Nil)) - super.applyDefn(defn)(k) - case b => super.applyDefn(b)(k) diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index ee2e0b02be..d13ab800c0 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -11,10 +11,11 @@ staged module A :js :slot +:ds :w staged module A //│ ╔══[WARNING] `staged` keyword doesn't do anything currently. -//│ ║ l.15: staged module A +//│ ║ l.16: staged module A //│ ╙── ^^^^^^^^ //│ Pretty Lowered: //│ define staged class A in set block$res = undefined in end diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala index 2bf32e5879..1d5a5eab06 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala @@ -107,7 +107,10 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: new JSBuilder with JSBuilderArgNumSanityChecks val resSym = new TempSymbol(S(blk), "block$res") - val lowered0 = low.program(blk) + val lowered0 = if stageCode.isSet then + val instrumentation = new Instrumentation + instrumentation.transform(low.program(blk)) + else low.program(blk) val le = lowered0.copy(main = lowered0.main.mapTail: case e: End => Assign(resSym, Value.Lit(syntax.Tree.UnitLit(false)), e) From 6576f284b3b2ebb4ce2c7e4bea3595de04a97a26 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 6 Nov 2025 16:42:27 +0800 Subject: [PATCH 076/268] rename compiler flag to :staging --- hkmc2/shared/src/test/mlscript/staging/Syntax.mls | 2 +- hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index d13ab800c0..686338774f 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -11,7 +11,7 @@ staged module A :js :slot -:ds +:staging :w staged module A //│ ╔══[WARNING] `staged` keyword doesn't do anything currently. diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index c9ee6dd0f7..5f250a555c 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -70,7 +70,7 @@ abstract class MLsDiffMaker extends DiffMaker: val stackSafe = Command("stackSafe")(_.trim) val liftDefns = NullaryCommand("lift") val importQQ = NullaryCommand("qq") - val stageCode = NullaryCommand("ds") + val stageCode = NullaryCommand("staging") def mkConfig: Config = import Config.* From 4191464b7aea27afc99affb1812f7e726e1561cd Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 6 Nov 2025 16:45:29 +0800 Subject: [PATCH 077/268] Revert "remove redundant :pt" This reverts commit 317c6f6c3a2ae963d064f1ad3b011da396bc1dfe. --- hkmc2/shared/src/test/mlscript/staging/Syntax.mls | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index 686338774f..94accabd06 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -9,13 +9,20 @@ staged module A //│ head = Ident of "A" //│ rhs = N +// TODO: reject these annotations? +staged object Foo + +staged class Foo + +staged fun f() = 0 + :js :slot :staging :w staged module A //│ ╔══[WARNING] `staged` keyword doesn't do anything currently. -//│ ║ l.16: staged module A +//│ ║ l.23: staged module A //│ ╙── ^^^^^^^^ //│ Pretty Lowered: //│ define staged class A in set block$res = undefined in end From 817e828af3a94372b92aa49e6580948cf8da5383 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 6 Nov 2025 17:03:12 +0800 Subject: [PATCH 078/268] combine import statements to list --- hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index 5f250a555c..49117a526b 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -162,9 +162,9 @@ abstract class MLsDiffMaker extends DiffMaker: if stageCode.isSet then given Config = mkConfig processTrees( - PrefixApp(Keywrd(`import`), StrLit(blockFile.toString)) :: Nil) - processTrees( - PrefixApp(Keywrd(`import`), StrLit(shapeFile.toString)) :: Nil) + PrefixApp(Keywrd(`import`), StrLit(blockFile.toString)) + :: PrefixApp(Keywrd(`import`), StrLit(shapeFile.toString)) + :: Nil) super.init() From 33a37491c94b70f3fc2b7a1680076a6a56c99ac0 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 6 Nov 2025 17:58:54 +0800 Subject: [PATCH 079/268] reword function --- .../scala/hkmc2/codegen/Instrumentation.scala | 15 +++++---------- .../src/test/scala/hkmc2/JSBackendDiffMaker.scala | 4 ++-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 342c05d68b..b4f9a86f7c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -356,17 +356,12 @@ class InstrumentationImpl(using State): case End(_) => ruleEnd()(k) case _ => ??? // not supported - def transformProgram(prog: Program)(): Program = - // TODO imports - ??? // use ruleCls and ruleBlock here - Program(prog.imports, transformBlock(prog.main)(using new Context())(_.end)) +class InstrumentationTransformer(using State) extends BlockTransformer(new SymbolSubst()): + val impl = new InstrumentationImpl -class Instrumentation(using Raise) extends BlockTransformer(new SymbolSubst()): - def transform(prgm: Program) = Program(prgm.imports, applyBlock(prgm.main)) + def applyProgram(prgm: Program) = Program(prgm.imports, applyBlock(prgm.main)) override def applyDefn(d: Defn)(k: Defn => Block): Block = d match - case defn: ClsLikeDefn => - if defn.sym.defn.exists(_.hasStagedModifier.isDefined) && defn.companion.isDefined - then raise(WarningReport(msg"`staged` keyword doesn't do anything currently." -> defn.sym.toLoc :: Nil)) - super.applyDefn(defn)(k) + case defn: ClsLikeDefn if defn.sym.defn.exists(_.hasStagedModifier.isDefined) && defn.companion.isDefined => + ??? case b => super.applyDefn(b)(k) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala index 1d5a5eab06..12c2bbd19e 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala @@ -108,8 +108,8 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: with JSBuilderArgNumSanityChecks val resSym = new TempSymbol(S(blk), "block$res") val lowered0 = if stageCode.isSet then - val instrumentation = new Instrumentation - instrumentation.transform(low.program(blk)) + val instrumentation = new InstrumentationTransformer + instrumentation.applyProgram(low.program(blk)) else low.program(blk) val le = lowered0.copy(main = lowered0.main.mapTail: case e: End => From b10e9750d619d07f2e1ece40e5d31aa84fe3b1e2 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 6 Nov 2025 20:46:23 +0800 Subject: [PATCH 080/268] Revert "move instrumentation to JSBackendDiffMaker" This reverts commit e4d7b227ee3cab3d5a7461ec746cf23468b5ae8d. --- hkmc2/shared/src/main/scala/hkmc2/Config.scala | 2 ++ hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala | 8 +++++++- .../src/test/scala/hkmc2/JSBackendDiffMaker.scala | 5 +---- hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala | 1 + 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/Config.scala b/hkmc2/shared/src/main/scala/hkmc2/Config.scala index 44dcbe6303..d0a684622b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/Config.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/Config.scala @@ -20,6 +20,7 @@ case class Config( sanityChecks: Opt[SanityChecks], effectHandlers: Opt[EffectHandlers], liftDefns: Opt[LiftDefns], + stageCode: Bool, target: CompilationTarget, ): @@ -35,6 +36,7 @@ object Config: // sanityChecks = S(SanityChecks(light = true)), effectHandlers = N, liftDefns = N, + stageCode = false, target = CompilationTarget.JS ) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index 8d242536df..4be76c1e5f 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -11,6 +11,8 @@ import utils.* import hkmc2.Message.MessageContext +import codegen.Instrumentation + import semantics.*, ucs.FlatPattern import hkmc2.{semantics => sem} import semantics.{Term => st} @@ -1068,7 +1070,11 @@ class Lowering()(using Config, TL, Raise, State, Ctx): val bufferable = BufferableTransform().transform(lifted) - val res = MergeMatchArmTransformer.applyBlock(bufferable) + val merged = MergeMatchArmTransformer.applyBlock(bufferable) + + val res = + if config.stageCode then Instrumentation(using summon).applyBlock(merged) + else merged Program( imps.map(imp => imp.sym -> imp.str), diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala index 1d5a5eab06..2bf32e5879 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala @@ -107,10 +107,7 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: new JSBuilder with JSBuilderArgNumSanityChecks val resSym = new TempSymbol(S(blk), "block$res") - val lowered0 = if stageCode.isSet then - val instrumentation = new Instrumentation - instrumentation.transform(low.program(blk)) - else low.program(blk) + val lowered0 = low.program(blk) val le = lowered0.copy(main = lowered0.main.mapTail: case e: End => Assign(resSym, Value.Lit(syntax.Tree.UnitLit(false)), e) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index 49117a526b..e748836b81 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -96,6 +96,7 @@ abstract class MLsDiffMaker extends DiffMaker: , )), liftDefns = Opt.when(liftDefns.isSet)(LiftDefns()), + stageCode = stageCode.isSet, target = if wasm.isSet then CompilationTarget.Wasm else CompilationTarget.JS, ) From 791b5b4faebc6293bddd26c9b23d9f8a38275b35 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 6 Nov 2025 21:07:41 +0800 Subject: [PATCH 081/268] prune implementation for mvp --- .../scala/hkmc2/codegen/Instrumentation.scala | 208 ++---------------- 1 file changed, 22 insertions(+), 186 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index e75c9497da..30c8f9c4c4 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -27,9 +27,6 @@ class InstrumentationImpl(using State): // A PathLike type is a type that can be turned into an Arg type PathLike = Path | Symbol | Shape - // is Elaborator.Ctx relevant? - type Context = HashMap[Path, Shape] - def asArg(x: PathLike): Arg = x match case p: Path => p.asArg @@ -45,17 +42,6 @@ class InstrumentationImpl(using State): case n: BigDecimal => Tree.DecLit(n) Value.Lit(l) - // TODO: use BlockTransformer.applyListOf? - extension [A](ls: Ls[(A => Block) => Block]) - def collectApply(f: Ls[A] => Block): Block = - // defer applying k while prepending new paths to the list - ls.foldRight((_: Ls[A] => Block)(Nil))((headCont, tailCont) => - k => - headCont: head => - tailCont: tail => - k(head :: tail) - )(f) - // helpers corresponding to constructors // could use `using` to allow passthrough of names @@ -87,10 +73,7 @@ class InstrumentationImpl(using State): def blockCtor(name: String, args: Ls[PathLike])(k: Path => Block): Block = ctor(blockMod(name), args)(k) def shapeCtor(name: String, args: Ls[PathLike])(k: Shape => Block): Block = - // ctor(shapeMod(name), args)(p => k(Shape(p))) - // override handling shape - if name == "Lit" then ctor(shapeMod("Lit"), args)(p => k(Shape(p))) - else ctor(shapeMod("Dyn"), Ls())(p => k(Shape(p))) + ctor(shapeMod(name), args)(p => k(Shape(p))) def blockCall(name: String, args: Ls[PathLike])(k: Path => Block): Block = call(blockMod(name), args)(k) @@ -109,52 +92,11 @@ class InstrumentationImpl(using State): object StagedPath: def mk(shape: Shape, code: Path)(k: StagedPath => Block): Block = tuple(Ls(shape.p, code))(p => k(StagedPath(p))) - // in some cases this can reduce the indentation level - def mk(shapeCont: (Shape => Block) => Block, codeCont: (Path => Block) => Block)(k: StagedPath => Block): Block = - shapeCont: shape => - codeCont: code => - mk(shape, code)(k) // linking functions defined in MLscipt def fnPrintCode(p: Path)(k: Path => Block): Block = blockCall("printCode", Ls(p))(k) - def applyCompile(r: Path)(k: Path => Block): Block = - blockCall("compile", Ls(r))(k) - def fnMrg(shapes: Ls[Shape])(k: Shape => Block): Block = - shapeCall("mrg", shapes)(s => k(Shape(s))) - // TODO: make fnSilh take in a wrapped Path type - def fnSilh(pattern: Path)(k: Shape => Block) = - shapeCall("silh", Ls(pattern))(s => k(Shape(s))) - def fnMatch(s: Shape, pat: Path)(k: Path => Block) = - shapeCall("match", Ls(s, pat))(k) - def fnSel(s1: Shape, s2: Shape)(k: Shape => Block): Block = - shapeCall("sel", Ls(s1, s2))(s => k(Shape(s))) - def fnStatic(s: Shape)(k: Path => Block) = - shapeCall("static", Ls(s))(k) - def fnCompile(x: Path)(k: StagedPath => Block): Block = - shapeCall("compile", Ls(x))(p => k(StagedPath(p))) - def fnDet(s: Shape, ps: Ls[PathLike])(k: Path => Block): Block = - tuple(ps): tup => - shapeCall("det", Ls(s, tup))(k) - - // helpers for instrumenting functions - - def inst(f: StagedPath, args: Ls[StagedPath]): StagedPath = - if ??? then - // non-staged function - ??? - else - // staged function - ??? - - def instGlobal(f: StagedPath, args: Ls[StagedPath])(k: StagedPath => Block): Block = - def isFunction(p: Path) = ??? - if isFunction(f.p) then k(inst(???, args)) - else - shapeCtor("Dyn", Ls()): sp => - call(f.p, args.map(_.p), ???): cde => - StagedPath.mk(sp, cde)(k) // instrumentation rules @@ -170,108 +112,12 @@ class InstrumentationImpl(using State): blockCtor("ValueRef", Ls(toValue(r.l.nme))): cde => StagedPath.mk(sp.shape, cde)(k) - def ruleTup(t: Tuple)(using Context)(k: StagedPath => Block): Block = - val Tuple(mut, elems) = t - assert(!mut) - - transformArgs(elems): xs => - tuple(xs.map(_.shape)): shapes => - shapeCtor("Arr", Ls(shapes)): sp => - blockCtor("Tuple", xs.map(_.code)): cde => - StagedPath.mk(sp, cde)(k) - - def ruleSel(s: Select)(using Context)(k: StagedPath => Block): Block = - val Select(p, i @ Tree.Ident(name)) = s - transformPath(p): x => - // stage? there isn't a correct constructor for it though - // val n = Shape(Value.Ref(new TempSymbol(N, name))) - val n = ??? - fnSel(x.shape, n): sp => - val cde = select(x.code, i) - StagedPath.mk(sp, cde)(k) - - def ruleDynSel(d: DynSelect)(using Context)(k: StagedPath => Block): Block = - val DynSelect(qual, path, arrayIdx) = d - transformPath(qual): x => - transformPath(path): y => - fnSel(x.shape, y.shape): sp => - blockCtor("DynSelect", Ls(x.code, y.code, toValue(arrayIdx))): cde => - StagedPath.mk(sp, cde)(k) - - def ruleRefinedPath(p: Path)(using ctx: Context)(k: StagedPath => Block): Block = ??? - - // .apply is Call? - def ruleApp(c: Call)(using Context)(k: StagedPath => Block): Block = - val Call(fun, args) = c - transformPath(fun): f => - transformArgs(args): xs => - instGlobal(f, xs)(k) - - def ruleInst(i: Instantiate)(using Context)(k: StagedPath => Block): Block = - val Instantiate(mut, cls, args) = i - assert(!mut) - - transformArgs(args): xs => - tuple(xs.map(_.shape)): shapes => - tuple(xs.map(_.code)): codes => - shapeCtor("Class", Ls(cls, shapes)): sp => - blockCtor("Instantiate", Ls(cls, codes)): cde => - StagedPath.mk(sp, cde)(k) - - def ruleReturn(r: Return)(using Context)(k: StagedPath => Block): Block = + def ruleReturn(r: Return)(k: StagedPath => Block): Block = transformResult(r.res): x => blockCtor("Return", Ls(x.code)): cde => StagedPath.mk(x.shape, cde)(k) - def ruleMatch(m: Match)(using ctx: Context)(k: StagedPath => Block): Block = - def concat(b1: Block, b2: Block) = b1.mapTail { - case r: Return => r - case _: End => b2 - case _ => ??? - } - def transformCase(cse: Opt[Case])(k: Path => Block): Block = - cse match - case S(Case.Lit(lit)) => blockCtor("Lit", Ls(Value.Lit(lit)))(k) - case S(Case.Cls(cls, path)) => blockCtor("Cls", Ls(cls, path))(k) - case S(Case.Tup(len, inf)) => blockCtor("Tup", Ls(len, inf).map(toValue))(k) - case S(Case.Field(name, safe)) => blockCtor("Field", Ls(toValue(name.name)))(k) - case N => blockCtor("Wildcard", Ls())(k) - - val Match(p, arms, dflt, rest) = m - - transformPath(p): x => - (arms.map((c, b) => (S(c), b)) ++ (dflt.map((N, _)))) - .map: (c, b) => - val concatBlock = concat(b, rest) - (k: (((Path, (StagedPath => Block) => Block)) => Block)) => - transformCase(c): patt => - fnSilh(patt): sp => - val newCtx = ctx.clone() += (p -> sp) - val blockCont = transformBlock(concatBlock)(using newCtx) - k(patt, blockCont) - .collectApply: arms => - // we need to duplicate the blocks anyways, so it's fine that blocksCont gets evaluated twice - val (patts, blocksCont) = arms.unzip - (arms.zipWithIndex.foldRight(_: Block) { case (((patt, blockCont), i), rest) => - val slice = arms.slice(0, i + 1).map(_._1) - fnDet(x.shape, slice): scrut => - blockCont: block => - val cse = Case.Lit(Tree.BoolLit(false)) -> k(block) - Match(scrut, Ls(cse), S(rest), End()) - }): - // staged block - blocksCont.collectApply: xs => - val (shapes, codes) = xs.map(xi => (xi.shape, xi.code)).unzip - fnMrg(shapes): s => - (patts - .zip(codes) - .foldRight(blockCtor("End", Ls())) { case ((patt, cde), restCont) => - (k: Path => Block) => - restCont: rest => - blockCtor("Match", Ls(x.code, patt, cde, rest))(k) - })(StagedPath.mk(s, _)(k)) - - def ruleAssign(a: Assign)(using Context)(k: StagedPath => Block): Block = + def ruleAssign(a: Assign)(k: StagedPath => Block): Block = val Assign(x, r, b) = a transformResult(r): y => (Assign(x, y.p, _)): @@ -285,7 +131,7 @@ class InstrumentationImpl(using State): blockCtor("End", Ls()): cde => StagedPath.mk(sp, cde)(k) - def ruleVal(defn: ValDefn, b: Block)(using Context)(k: StagedPath => Block): Block = + def ruleVal(defn: ValDefn, b: Block)(k: StagedPath => Block): Block = val ValDefn(tsym, x, p) = defn transformPath(p): y => transformBlock(b): z => @@ -296,43 +142,34 @@ class InstrumentationImpl(using State): blockCtor("Define", Ls(df, z.code)): cde => StagedPath.mk(z.shape, cde)(k) - def ruleBlk(b: Block)(using Context)(k: StagedPath => Block): Block = - transformBlock(b): x => - fnCompile(x.code)(k) - - // g is Program? - def ruleCls(c: Program, rest: Block)(using Context)(k: StagedPath => Block): Block = - // val ClsLikeDefn(_, _, ) - ??? - // transformations of Block - def transformPath(p: Path)(using Context)(k: StagedPath => Block): Block = + def transformPath(p: Path)(k: StagedPath => Block): Block = p match - // case s: Select => ruleSel(s)(ruleRefinedPath(_)(k)) - // case d: DynSelect => ruleDynSel(d)(ruleRefinedPath(_)(k)) - // case r: Value.Ref => ruleVar(r)(ruleRefinedPath(_)(k)) case r: Value.Ref => ruleVar(r)(k) case Value.Lit(lit) => ruleLit(lit)(k) case _ => ??? // not supported - def transformResult(r: Result)(using Context)(k: StagedPath => Block): Block = + def transformResult(r: Result)(k: StagedPath => Block): Block = r match - // case c: Call => ruleApp(c)(k) - // case i: Instantiate => ruleInst(i)(k) - // case t: Tuple => ruleTup(t)(k) case p: Path => transformPath(p)(k) - case _: Lambda | _: Record => ??? // not supported + case _ => ??? // not supported - def transformArg(a: Arg)(using Context)(k: StagedPath => Block): Block = + def transformArg(a: Arg)(k: StagedPath => Block): Block = val Arg(spread, value) = a transformPath(value)(k) - - // provides list of shapes and list of codes to continuation - def transformArgs(args: Ls[Arg])(using Context)(k: Ls[StagedPath] => Block): Block = - args.map(transformArg).collectApply(k) - - def transformDefine(d: Define)(using Context)(k: StagedPath => Block): Block = + + def transformFunDefn(f: FunDefn): FunDefn = + val FunDefn(owner, sym, parameters, body) = f + val genSym = BlockMemberSymbol(sym.nme+"_gen", Nil, true) // TODO: reuse original function name? + // TODO: remove it. only for test + // TODO: put correct parameters instead of Nil + val b = call(genSym.asPath, Nil): ret => + blockCall("printCode", Ls(StagedPath(ret).code)): _ => // discard result, we only care about side effect + transformBlock(body)(_.end) + FunDefn(owner, genSym, parameters, transformBlock(body)(_.end)) + + def transformDefine(d: Define)(k: StagedPath => Block): Block = d.defn match case f @ FunDefn(owner, sym, parameters, body) => val genSym = BlockMemberSymbol("gen", Nil, true) // TODO: reuse original function name? @@ -347,11 +184,10 @@ class InstrumentationImpl(using State): case v: ValDefn => ruleVal(v, d.rest)(k) case c: ClsLikeDefn => ??? // nested class? - def transformBlock(b: Block)(using Context)(k: StagedPath => Block): Block = + def transformBlock(b: Block)(k: StagedPath => Block): Block = b match - // case m: Match => ruleMatch(m)(k) case r: Return => ruleReturn(r)(k) - // case a: Assign => ruleAssign(a)(k) + case a: Assign => ruleAssign(a)(k) case d: Define => transformDefine(d)(k) case End(_) => ruleEnd()(k) case _ => ??? // not supported From 578dfd16159eec36f99f5cb9dc68a861049cea7d Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 6 Nov 2025 21:20:38 +0800 Subject: [PATCH 082/268] implement rudimentary instrumentation logic --- .../scala/hkmc2/codegen/Instrumentation.scala | 22 +++++- .../src/test/mlscript/staging/Functions.mls | 77 +++++++++++++++++++ 2 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/staging/Functions.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 30c8f9c4c4..3ddcc6738d 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -197,8 +197,22 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): val impl = new InstrumentationImpl def applyProgram(prgm: Program) = Program(prgm.imports, applyBlock(prgm.main)) + + // This stages any function definition, + // instead of staging functions within staged modules. + override def applyBlock(b: Block): Block = b match + case Define(defn, rest) => + defn match + case f @ FunDefn(owner, sym, parameters, body) => + val genSym = BlockMemberSymbol("gen", Nil, true) // TODO: reuse original function name? + val staged = FunDefn(owner, genSym, parameters, impl.transformBlock(body)(_.end)) + // TODO: remove it. only for test + // TODO: put correct parameters instead of Nil + val b = impl.call(genSym.asPath, Nil): ret => + // discard result, we only care about side effect of printCode + impl.blockCall("printCode", Ls(impl.StagedPath(ret).code)): _ => + applyBlock(rest) + Define(f, Define(staged, b)) + case _ => b + case _ => b - override def applyDefn(d: Defn)(k: Defn => Block): Block = d match - case defn: ClsLikeDefn if defn.sym.defn.exists(_.hasStagedModifier.isDefined) && defn.companion.isDefined => - ??? - case b => super.applyDefn(b)(k) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls new file mode 100644 index 0000000000..4650c0d09b --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -0,0 +1,77 @@ + +:js +:staging +:ssjs +:re +fun f() = + let x = 42 + x +//│ JS: +//│ f = function f(...args) { +//│ runtime.checkArgs("f", 0, true, args.length); +//│ let x; +//│ x = 42; +//│ return x +//│ }; +//│ gen = function gen(...args) { +//│ runtime.checkArgs("gen", 0, true, args.length); +//│ let x, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10; +//│ tmp2 = globalThis.Object.freeze(new Shape.Lit(42)); +//│ tmp3 = globalThis.Object.freeze(new Block.ValueLit(42)); +//│ tmp4 = globalThis.Object.freeze([ +//│ tmp2, +//│ tmp3 +//│ ]); +//│ x = tmp4; +//│ tmp5 = globalThis.Object.freeze(new Block.ValueRef("x")); +//│ tmp6 = globalThis.Object.freeze([ +//│ x[0], +//│ tmp5 +//│ ]); +//│ tmp7 = globalThis.Object.freeze(new Block.Return(tmp6[1])); +//│ tmp8 = globalThis.Object.freeze([ +//│ tmp6[0], +//│ tmp7 +//│ ]); +//│ tmp9 = globalThis.Object.freeze(new Block.Assign(x, tmp4[1], tmp8[1])); +//│ tmp10 = globalThis.Object.freeze([ +//│ tmp8[0], +//│ tmp9 +//│ ]); +//│ return tmp10 +//│ }; +//│ tmp = runtime.checkCall(gen()); +//│ tmp1 = runtime.checkCall(Block.printCode(tmp[1])); +//│ block$res = undefined; +//│ ═══[RUNTIME ERROR] Error: Not implemented + +:js +:staging +:ssjs +:re +fun g() = 12 +//│ JS: +//│ g = function g(...args) { +//│ runtime.checkArgs("g", 0, true, args.length); +//│ return 12 +//│ }; +//│ gen1 = function gen(...args) { +//│ runtime.checkArgs("gen", 0, true, args.length); +//│ let tmp4, tmp5, tmp6, tmp7, tmp8; +//│ tmp4 = globalThis.Object.freeze(new Shape.Lit(12)); +//│ tmp5 = globalThis.Object.freeze(new Block.ValueLit(12)); +//│ tmp6 = globalThis.Object.freeze([ +//│ tmp4, +//│ tmp5 +//│ ]); +//│ tmp7 = globalThis.Object.freeze(new Block.Return(tmp6[1])); +//│ tmp8 = globalThis.Object.freeze([ +//│ tmp6[0], +//│ tmp7 +//│ ]); +//│ return tmp8 +//│ }; +//│ tmp2 = runtime.checkCall(gen1()); +//│ tmp3 = runtime.checkCall(Block.printCode(tmp2[1])); +//│ block$res1 = undefined; +//│ ═══[RUNTIME ERROR] Error: Not implemented From 27bf507e156f3c96d88e71b3eaeaf7f1f11ef986 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 6 Nov 2025 22:17:12 +0800 Subject: [PATCH 083/268] implement printing for DynSelect --- hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index 63a0569c6e..254442efdf 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -100,6 +100,10 @@ object Printer: case Select(qual, name) => val docQual = mkDocument(qual) doc"${docQual}.${name.name}" + case DynSelect(qual, fld, true) => + val docQual = mkDocument(qual) + val docFld = mkDocument(fld) + doc"${docQual}[${docFld}]" case x: Value => mkDocument(x) case _ => TODO(path) From 9c975f6827efb2d8f6e09932bbd958f0bc3dbe23 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 6 Nov 2025 23:46:29 +0800 Subject: [PATCH 084/268] only stage functions in staged modules --- .../scala/hkmc2/codegen/Instrumentation.scala | 45 +++++--- .../src/test/mlscript-compile/Block.mls | 4 +- .../src/test/mlscript/staging/Functions.mls | 103 ++++++------------ 3 files changed, 66 insertions(+), 86 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 3ddcc6738d..b3dfbe66c2 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -158,10 +158,10 @@ class InstrumentationImpl(using State): def transformArg(a: Arg)(k: StagedPath => Block): Block = val Arg(spread, value) = a transformPath(value)(k) - + def transformFunDefn(f: FunDefn): FunDefn = val FunDefn(owner, sym, parameters, body) = f - val genSym = BlockMemberSymbol(sym.nme+"_gen", Nil, true) // TODO: reuse original function name? + val genSym = BlockMemberSymbol(sym.nme + "_gen", Nil, true) // TODO: reuse original function name? // TODO: remove it. only for test // TODO: put correct parameters instead of Nil val b = call(genSym.asPath, Nil): ret => @@ -196,23 +196,38 @@ class InstrumentationImpl(using State): class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): val impl = new InstrumentationImpl - def applyProgram(prgm: Program) = Program(prgm.imports, applyBlock(prgm.main)) - // This stages any function definition, // instead of staging functions within staged modules. override def applyBlock(b: Block): Block = b match case Define(defn, rest) => defn match - case f @ FunDefn(owner, sym, parameters, body) => - val genSym = BlockMemberSymbol("gen", Nil, true) // TODO: reuse original function name? - val staged = FunDefn(owner, genSym, parameters, impl.transformBlock(body)(_.end)) - // TODO: remove it. only for test - // TODO: put correct parameters instead of Nil - val b = impl.call(genSym.asPath, Nil): ret => - // discard result, we only care about side effect of printCode - impl.blockCall("printCode", Ls(impl.StagedPath(ret).code)): _ => - applyBlock(rest) - Define(f, Define(staged, b)) + // case f @ FunDefn(owner, sym, parameters, body) => + // val genSym = BlockMemberSymbol("gen", Nil, true) // TODO: reuse original function name? + // val staged = FunDefn(owner, genSym, parameters, impl.transformBlock(body)(_.end)) + // // TODO: remove it. only for test + // // TODO: put correct parameters instead of Nil + // val b = impl.call(genSym.asPath, Nil): ret => + // // discard result, we only care about side effect of printCode + // impl.blockCall("printCode", Ls(impl.StagedPath(ret).code)): _ => + // applyBlock(rest) + // Define(f, Define(staged, b)) + // find modules with staged annotation + case c: ClsLikeDefn if c.sym.defn.exists(_.hasStagedModifier.isDefined) && c.companion.isDefined => + val companion = c.companion.get + val (stagedMethods, debugPrintCode) = companion.methods.map { case f @ FunDefn(owner, sym, parameters, body) => + val genSym = BlockMemberSymbol(sym.nme + "_gen", Nil, true) // TODO: reuse original function name? + // TODO: remove it. only for test + // TODO: put correct parameters instead of Nil + // Select(c.sym, genSym.nme) + // c.sym.selSN(genSym.nme) + val b: Block = impl.call(c.sym.asPath.selSN(genSym.nme), Nil): ret => + impl.blockCall("printCode", Ls(impl.StagedPath(ret).code)): _ => // discard result, we only care about side effect + End() + (f.copy(sym = genSym, body = impl.transformBlock(body)(_.end)), b) + }.unzip + val newCompanion = companion.copy(methods = companion.methods ++ stagedMethods) + val newModule = c.copy(sym = c.sym, companion = Some(newCompanion)) + val debugBlock: Block = debugPrintCode.foldRight(rest)((b1, b2) => b1.mapTail { case _ => b2 }) + Define(newModule, debugBlock) case _ => b case _ => b - diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 70c82c9883..0bced10f9f 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -60,6 +60,6 @@ class Block with Define(val defn: Defn, val rest: Block) End() -fun printCode(p: Block) = ??? +fun printCode(p: Block) = print("printCode") -fun compile(p: Block) = ??? \ No newline at end of file +fun compile(p: Block) = 0 \ No newline at end of file diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 4650c0d09b..391028146b 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -2,76 +2,41 @@ :js :staging :ssjs -:re -fun f() = - let x = 42 - x +staged module A with + fun f() = 1 //│ JS: -//│ f = function f(...args) { -//│ runtime.checkArgs("f", 0, true, args.length); -//│ let x; -//│ x = 42; -//│ return x -//│ }; -//│ gen = function gen(...args) { -//│ runtime.checkArgs("gen", 0, true, args.length); -//│ let x, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10; -//│ tmp2 = globalThis.Object.freeze(new Shape.Lit(42)); -//│ tmp3 = globalThis.Object.freeze(new Block.ValueLit(42)); -//│ tmp4 = globalThis.Object.freeze([ -//│ tmp2, -//│ tmp3 -//│ ]); -//│ x = tmp4; -//│ tmp5 = globalThis.Object.freeze(new Block.ValueRef("x")); -//│ tmp6 = globalThis.Object.freeze([ -//│ x[0], -//│ tmp5 -//│ ]); -//│ tmp7 = globalThis.Object.freeze(new Block.Return(tmp6[1])); -//│ tmp8 = globalThis.Object.freeze([ -//│ tmp6[0], -//│ tmp7 -//│ ]); -//│ tmp9 = globalThis.Object.freeze(new Block.Assign(x, tmp4[1], tmp8[1])); -//│ tmp10 = globalThis.Object.freeze([ -//│ tmp8[0], -//│ tmp9 -//│ ]); -//│ return tmp10 -//│ }; -//│ tmp = runtime.checkCall(gen()); +//│ globalThis.Object.freeze(class A { +//│ static { +//│ A1 = this +//│ } +//│ constructor() { +//│ runtime.Unit; +//│ } +//│ static f(...args) { +//│ runtime.checkArgs("f", 0, true, args.length); +//│ return 1 +//│ } +//│ static f_gen(...args) { +//│ runtime.checkArgs("f_gen", 0, true, args.length); +//│ let tmp2, tmp3, tmp4, tmp5, tmp6; +//│ tmp2 = globalThis.Object.freeze(new Shape.Lit(1)); +//│ tmp3 = globalThis.Object.freeze(new Block.ValueLit(1)); +//│ tmp4 = globalThis.Object.freeze([ +//│ tmp2, +//│ tmp3 +//│ ]); +//│ tmp5 = globalThis.Object.freeze(new Block.Return(tmp4[1])); +//│ tmp6 = globalThis.Object.freeze([ +//│ tmp4[0], +//│ tmp5 +//│ ]); +//│ return tmp6 +//│ } +//│ toString() { return runtime.render(this); } +//│ static [definitionMetadata] = ["class", "A"]; +//│ }); +//│ tmp = runtime.checkCall(A1.f_gen()); //│ tmp1 = runtime.checkCall(Block.printCode(tmp[1])); //│ block$res = undefined; -//│ ═══[RUNTIME ERROR] Error: Not implemented +//│ > printCode -:js -:staging -:ssjs -:re -fun g() = 12 -//│ JS: -//│ g = function g(...args) { -//│ runtime.checkArgs("g", 0, true, args.length); -//│ return 12 -//│ }; -//│ gen1 = function gen(...args) { -//│ runtime.checkArgs("gen", 0, true, args.length); -//│ let tmp4, tmp5, tmp6, tmp7, tmp8; -//│ tmp4 = globalThis.Object.freeze(new Shape.Lit(12)); -//│ tmp5 = globalThis.Object.freeze(new Block.ValueLit(12)); -//│ tmp6 = globalThis.Object.freeze([ -//│ tmp4, -//│ tmp5 -//│ ]); -//│ tmp7 = globalThis.Object.freeze(new Block.Return(tmp6[1])); -//│ tmp8 = globalThis.Object.freeze([ -//│ tmp6[0], -//│ tmp7 -//│ ]); -//│ return tmp8 -//│ }; -//│ tmp2 = runtime.checkCall(gen1()); -//│ tmp3 = runtime.checkCall(Block.printCode(tmp2[1])); -//│ block$res1 = undefined; -//│ ═══[RUNTIME ERROR] Error: Not implemented From ff6b121cd055e5089b9dacc7d8e6328342c86577 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 6 Nov 2025 23:47:49 +0800 Subject: [PATCH 085/268] update Syntax.mls --- hkmc2/shared/src/test/mlscript/staging/Syntax.mls | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index 94accabd06..2f5c8aab11 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -19,10 +19,6 @@ staged fun f() = 0 :js :slot :staging -:w staged module A -//│ ╔══[WARNING] `staged` keyword doesn't do anything currently. -//│ ║ l.23: staged module A -//│ ╙── ^^^^^^^^ //│ Pretty Lowered: //│ define staged class A in set block$res = undefined in end From 068fd379441e6cc1a191ff3eb09b13ab299bd8e6 Mon Sep 17 00:00:00 2001 From: TYeung Date: Sat, 8 Nov 2025 00:58:50 +0800 Subject: [PATCH 086/268] remove bugs in pretty printing --- .../src/test/mlscript-compile/Block.mls | 39 ++++++------------- .../src/test/mlscript/staging/Block.mls | 38 ++++++++++++++++++ .../src/test/scala/hkmc2/MLsDiffMaker.scala | 2 +- 3 files changed, 51 insertions(+), 28 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/staging/Block.mls diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 13b4457051..764433cbbb 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -2,8 +2,8 @@ import "./Predef.mls" import "./Option.mls" import "./StrOps.mls" -open StrOps open Predef +open StrOps open Option module Block with... @@ -106,7 +106,7 @@ fun showResult(r: Result): Str = Tuple(elems) then "Tuple(" + showArgs(elems) + ")" fun showParamList(ps: ParamList) = - "[" + ps.map(showSymbol).joinWith(", ") + "]" + "[" + ps.map(s => showSymbol(s)).join(", ") + "]" fun showDefn(d: Defn): Str = if d is @@ -114,7 +114,7 @@ fun showDefn(d: Defn): Str = "ValDefn(" + showSymbol(sym) + ", " + showPath(rhs) + ")" FunDefn(sym, params, body) then "FunDefn(" + showSymbol(sym) + ", " + - "[" + params.map(showParamList).joinWith(", ") + "], " + + showParamList(params) + ", " + showBlock(body) + ")" ClsLikeDefn(sym, paramsOpt, companion) then // minimal, since this is unused in your staged Block for now @@ -131,7 +131,7 @@ fun showBlock(b: Block): Str = Match(scrut, arms, dflt, rest) then "Match(" + showPath(scrut) + ", " + - "[" + arms.map(showArm).joinWith(", ") + "], " + + "[" + arms.map(showArm).join(", ") + "], " + showOptBlock(dflt) + ", " + showBlock(rest) + ")" Return(res, implct) then @@ -144,37 +144,22 @@ fun showBlock(b: Block): Str = fun show(x) = if x is - Match(_, _, _, _) then showBlock(x) - Return(_, _) then showBlock(x) - Assign(_, _, _) then showBlock(x) - Define(_, _) then showBlock(x) - End() then showBlock(x) + Symbol then showSymbol(x) else if x is - Select(_, _) then showPath(x) - DynSelect(_, _, _) then showPath(x) - ValueRef(_) then showPath(x) - ValueLit(_) then showPath(x) + Path then showPath(x) else if x is - TrivialResult(_) then showResult(x) - Call(_, _) then showResult(x) - Instantiate(_, _) then showResult(x) - Tuple(_) then showResult(x) + Result then showResult(x) else if x is - Lit(_) then showCase(x) - Cls(_, _) then showCase(x) - Tup(_, _) then showCase(x) - Field(_) then showCase(x) - Wildcard then showCase(x) + Case then showCase(x) else if x is - ValDefn(_, _) then showDefn(x) - FunDefn(_, _, _) then showDefn(x) - ClsLikeDefn(_, _, _) then showDefn(x) + Defn then showDefn(x) else if x is - Arg(_, _) then showArg(x) + Arg then showArg(x) else if x is - [a, b] then StrOps.concat of "[", show(a), ", ", show(b), "]" + Block then showBlock(x) else "" +fun printCode(x) = print(show(x)) fun compile(p: Block) = ??? \ No newline at end of file diff --git a/hkmc2/shared/src/test/mlscript/staging/Block.mls b/hkmc2/shared/src/test/mlscript/staging/Block.mls new file mode 100644 index 0000000000..00a8b3c364 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/staging/Block.mls @@ -0,0 +1,38 @@ +:staging +:js + +//│ Block = class Block { +//│ Symbol: fun Symbol { class: class Symbol }, +//│ Arg: fun Arg { class: class Arg }, +//│ Path: class Path, +//│ Select: fun Select { class: class Select }, +//│ DynSelect: fun DynSelect { class: class DynSelect }, +//│ ValueRef: fun ValueRef { class: class ValueRef }, +//│ ValueLit: fun ValueLit { class: class ValueLit }, +//│ Case: class Case, +//│ Lit: fun Lit { class: class Lit }, +//│ Cls: fun Cls { class: class Cls }, +//│ Tup: fun Tup { class: class Tup }, +//│ Field: fun Field { class: class Field }, +//│ Wildcard: class Wildcard, +//│ Result: class Result, +//│ TrivialResult: fun TrivialResult { class: class TrivialResult }, +//│ Call: fun Call { class: class Call }, +//│ Instantiate: fun Instantiate { class: class Instantiate }, +//│ Tuple: fun Tuple { class: class Tuple }, +//│ Defn: class Defn, +//│ ValDefn: fun ValDefn { class: class ValDefn }, +//│ ClsLikeDefn: fun ClsLikeDefn { class: class ClsLikeDefn }, +//│ FunDefn: fun FunDefn { class: class FunDefn }, +//│ ClsLikeBody: fun ClsLikeBody { class: class ClsLikeBody }, +//│ Block: class Block, +//│ Match: fun Match { class: class Match }, +//│ Return: fun Return { class: class Return }, +//│ Assign: fun Assign { class: class Assign }, +//│ Define: fun Define { class: class Define }, +//│ End: fun End { class: class End } +//│ } + +Block.printCode(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x")], Block.Return(Block.TrivialResult(Block.ValueLit(1)), false))) +//│ > FunDefn(Symbol("f"), [Symbol("x")], Return(Lit(1), false)) + diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index ddb8b731ee..b8cfdf866d 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -70,7 +70,7 @@ abstract class MLsDiffMaker extends DiffMaker: val stackSafe = Command("stackSafe")(_.trim) val liftDefns = NullaryCommand("lift") val importQQ = NullaryCommand("qq") - val stageCode = NullaryCommand("ds") + val stageCode = NullaryCommand("staging") def mkConfig: Config = import Config.* From 3f32b39664e4e76b5d74678b97068d7fe9321e65 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 8 Nov 2025 23:43:30 +0800 Subject: [PATCH 087/268] formatting --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 764433cbbb..0db9c74c0e 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -124,7 +124,7 @@ fun showOptBlock(ob: Opt[Block]) = if ob is Some(b) then showBlock(b) else "None" fun showArm(pair: Case -> Block) = - if pair is [cse, body] then showCase(cse) + " -> " + showBlock(body) else "" + if pair is [cse, body] then showCase(cse) + " -> " + showBlock(body) else "" fun showBlock(b: Block): Str = if b is @@ -145,17 +145,11 @@ fun showBlock(b: Block): Str = fun show(x) = if x is Symbol then showSymbol(x) - else if x is Path then showPath(x) - else if x is Result then showResult(x) - else if x is Case then showCase(x) - else if x is Defn then showDefn(x) - else if x is Arg then showArg(x) - else if x is Block then showBlock(x) else "" From d3bd300a2320e88d3c7c8ee6321f314bf889cd23 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 8 Nov 2025 23:45:07 +0800 Subject: [PATCH 088/268] add back Symbol class this was done to be in line with Block, though there's no reason Symbol can't just be a Str --- .../scala/hkmc2/codegen/Instrumentation.scala | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index b3dfbe66c2..5022b97b65 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -109,8 +109,9 @@ class InstrumentationImpl(using State): // why assume it is already staged? val sp = StagedPath(r) // why not just use sp.code? - blockCtor("ValueRef", Ls(toValue(r.l.nme))): cde => - StagedPath.mk(sp.shape, cde)(k) + blockCtor("Symbol", Ls(toValue(r.l.nme))): sym => + blockCtor("ValueRef", Ls(sym)): cde => + StagedPath.mk(sp.shape, cde)(k) def ruleReturn(r: Return)(k: StagedPath => Block): Block = transformResult(r.res): x => @@ -122,9 +123,10 @@ class InstrumentationImpl(using State): transformResult(r): y => (Assign(x, y.p, _)): transformBlock(b): z => - // need to wrap x with Symbol? - blockCtor("Assign", Ls(x, y.code, z.code)): cde => - StagedPath.mk(z.shape, cde)(k) + blockCtor("Symbol", Ls(toValue(x.nme))): x => + // need to wrap x with Symbol? + blockCtor("Assign", Ls(x, y.code, z.code)): cde => + StagedPath.mk(z.shape, cde)(k) def ruleEnd()(k: StagedPath => Block): Block = shapeCtor("Unit", Ls()): sp => @@ -152,7 +154,10 @@ class InstrumentationImpl(using State): def transformResult(r: Result)(k: StagedPath => Block): Block = r match - case p: Path => transformPath(p)(k) + case p: Path => + transformPath(p): p => + blockCtor("TrivialResult", Ls(p.code)): cde => + StagedPath.mk(p.shape, cde)(k) case _ => ??? // not supported def transformArg(a: Arg)(k: StagedPath => Block): Block = From 8ef91e9a3d987191867f73c5d7a69c227a0cf585 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 8 Nov 2025 23:53:40 +0800 Subject: [PATCH 089/268] reuse original function name --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 5022b97b65..e43b8f36f7 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -166,7 +166,7 @@ class InstrumentationImpl(using State): def transformFunDefn(f: FunDefn): FunDefn = val FunDefn(owner, sym, parameters, body) = f - val genSym = BlockMemberSymbol(sym.nme + "_gen", Nil, true) // TODO: reuse original function name? + val genSym = BlockMemberSymbol(sym.nme + "_gen", Nil, true) // TODO: remove it. only for test // TODO: put correct parameters instead of Nil val b = call(genSym.asPath, Nil): ret => @@ -176,8 +176,9 @@ class InstrumentationImpl(using State): def transformDefine(d: Define)(k: StagedPath => Block): Block = d.defn match + // duplicated because we need a reference to genSym here case f @ FunDefn(owner, sym, parameters, body) => - val genSym = BlockMemberSymbol("gen", Nil, true) // TODO: reuse original function name? + val genSym = BlockMemberSymbol(sym.nme + "_gen", Nil, true) val b = transformBlock(d.rest): res => // TODO: remove it. only for test // TODO: put correct parameters instead of Nil @@ -223,8 +224,6 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): val genSym = BlockMemberSymbol(sym.nme + "_gen", Nil, true) // TODO: reuse original function name? // TODO: remove it. only for test // TODO: put correct parameters instead of Nil - // Select(c.sym, genSym.nme) - // c.sym.selSN(genSym.nme) val b: Block = impl.call(c.sym.asPath.selSN(genSym.nme), Nil): ret => impl.blockCall("printCode", Ls(impl.StagedPath(ret).code)): _ => // discard result, we only care about side effect End() From 3c7f58db43afc7837bd51545d377b3c6235e6d3d Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 8 Nov 2025 23:53:49 +0800 Subject: [PATCH 090/268] update test cases --- .../src/test/mlscript/staging/Functions.mls | 48 +++++-------------- .../staging/{Block.mls => PrintCode.mls} | 8 ++++ 2 files changed, 19 insertions(+), 37 deletions(-) rename hkmc2/shared/src/test/mlscript/staging/{Block.mls => PrintCode.mls} (86%) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 391028146b..e1a145ea2d 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -1,42 +1,16 @@ :js :staging -:ssjs +// :ssjs staged module A with fun f() = 1 -//│ JS: -//│ globalThis.Object.freeze(class A { -//│ static { -//│ A1 = this -//│ } -//│ constructor() { -//│ runtime.Unit; -//│ } -//│ static f(...args) { -//│ runtime.checkArgs("f", 0, true, args.length); -//│ return 1 -//│ } -//│ static f_gen(...args) { -//│ runtime.checkArgs("f_gen", 0, true, args.length); -//│ let tmp2, tmp3, tmp4, tmp5, tmp6; -//│ tmp2 = globalThis.Object.freeze(new Shape.Lit(1)); -//│ tmp3 = globalThis.Object.freeze(new Block.ValueLit(1)); -//│ tmp4 = globalThis.Object.freeze([ -//│ tmp2, -//│ tmp3 -//│ ]); -//│ tmp5 = globalThis.Object.freeze(new Block.Return(tmp4[1])); -//│ tmp6 = globalThis.Object.freeze([ -//│ tmp4[0], -//│ tmp5 -//│ ]); -//│ return tmp6 -//│ } -//│ toString() { return runtime.render(this); } -//│ static [definitionMetadata] = ["class", "A"]; -//│ }); -//│ tmp = runtime.checkCall(A1.f_gen()); -//│ tmp1 = runtime.checkCall(Block.printCode(tmp[1])); -//│ block$res = undefined; -//│ > printCode - + fun g() = + let x = 42 + let y = x + y + // I-Val doesn't work yet + // fun i() = + // val x = 1 + // x +//│ > Return(Lit(1), false) +//│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) diff --git a/hkmc2/shared/src/test/mlscript/staging/Block.mls b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls similarity index 86% rename from hkmc2/shared/src/test/mlscript/staging/Block.mls rename to hkmc2/shared/src/test/mlscript/staging/PrintCode.mls index 00a8b3c364..332923c4f8 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Block.mls +++ b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls @@ -32,6 +32,14 @@ //│ Define: fun Define { class: class Define }, //│ End: fun End { class: class End } //│ } +//│ Shape = class Shape { +//│ Shape: class Shape, +//│ Dyn: class Dyn, +//│ Lit: fun Lit { class: class Lit }, +//│ Arr: fun Arr { class: class Arr }, +//│ Class: fun Class { class: class Class }, +//│ Unit: class Unit +//│ } Block.printCode(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x")], Block.Return(Block.TrivialResult(Block.ValueLit(1)), false))) //│ > FunDefn(Symbol("f"), [Symbol("x")], Return(Lit(1), false)) From 2ecda34ca3718947acac4e3395c7710564a334d7 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 9 Nov 2025 00:24:13 +0800 Subject: [PATCH 091/268] fix ruleVal --- .../main/scala/hkmc2/codegen/Instrumentation.scala | 14 +++++++------- .../shared/src/test/mlscript/staging/Functions.mls | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index e43b8f36f7..300db4dba0 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -136,13 +136,13 @@ class InstrumentationImpl(using State): def ruleVal(defn: ValDefn, b: Block)(k: StagedPath => Block): Block = val ValDefn(tsym, x, p) = defn transformPath(p): y => - transformBlock(b): z => - // TODO: valdefn needs to be before code blocks somehow? - // y is StagedPath, not Path? - (Define(ValDefn(tsym, x, y.p), _)): - blockCtor("ValDefn", Ls(x, y.code)): df => - blockCtor("Define", Ls(df, z.code)): cde => - StagedPath.mk(z.shape, cde)(k) + // y is StagedPath, not Path? + (Define(ValDefn(tsym, x, y.p), _)): + transformBlock(b): z => + blockCtor("Symbol", Ls(toValue(x.nme))): x => + blockCtor("ValDefn", Ls(x, y.code)): df => + blockCtor("Define", Ls(df, z.code)): cde => + StagedPath.mk(z.shape, cde)(k) // transformations of Block diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index e1a145ea2d..9f61a56a4c 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -8,9 +8,9 @@ staged module A with let x = 42 let y = x y - // I-Val doesn't work yet - // fun i() = - // val x = 1 - // x + fun i() = + val x = 1 + x //│ > Return(Lit(1), false) //│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) +//│ > Define(ValDefn(Symbol("x"), Lit(1)), Return(Ref(Symbol("x")), false)) From 9ebf26b47f87a236c95a7c8d834454be7b91dea8 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 9 Nov 2025 00:31:08 +0800 Subject: [PATCH 092/268] add some debug symbol names --- .../scala/hkmc2/codegen/Instrumentation.scala | 50 +++++++++---------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 300db4dba0..387d4d8416 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -44,41 +44,39 @@ class InstrumentationImpl(using State): // helpers corresponding to constructors - // could use `using` to allow passthrough of names - def assign(res: Result, name: String = "tmp")(k: Path => Block): Assign = + def assign(res: Result, symName: String = "tmp")(k: Path => Block): Assign = // TODO: skip assignment if res: Path? - val tmp = new TempSymbol(N, name) + val tmp = new TempSymbol(N, symName) Assign(tmp, res, k(tmp.asPath)) def select(qual: Path, ident: Tree.Ident): Path = - // do we need to call assign here? it's already a path anyways Select(qual, ident)(N) - def tuple(elems: Ls[PathLike])(k: Path => Block): Block = + def tuple(elems: Ls[PathLike], symName: String = "tmp")(k: Path => Block): Block = // is this the same as "Ls of"? - assign(Tuple(false, elems.map(asArg)))(k) + assign(Tuple(false, elems.map(asArg)), symName)(k) - def ctor(cls: Path, args: Ls[PathLike])(k: Path => Block): Block = - assign(Instantiate(false, cls, args.map(asArg)))(k) + def ctor(cls: Path, args: Ls[PathLike], symName: String = "tmp")(k: Path => Block): Block = + assign(Instantiate(false, cls, args.map(asArg)), symName)(k) // isMlsFun is probably always true? - def call(fun: Path, args: Ls[PathLike], isMlsFun: Bool = true)(k: Path => Block): Block = - assign(Call(fun, args.map(asArg))(isMlsFun, false))(k) + def call(fun: Path, args: Ls[PathLike], isMlsFun: Bool = true, symName: String = "tmp")(k: Path => Block): Block = + assign(Call(fun, args.map(asArg))(isMlsFun, false), symName)(k) // helper for staging the constructors def blockMod(name: String) = summon[State].blockSymbol.asPath.selSN(name) def shapeMod(name: String) = summon[State].shapeSymbol.asPath.selSN(name) - def blockCtor(name: String, args: Ls[PathLike])(k: Path => Block): Block = - ctor(blockMod(name), args)(k) - def shapeCtor(name: String, args: Ls[PathLike])(k: Shape => Block): Block = - ctor(shapeMod(name), args)(p => k(Shape(p))) + def blockCtor(name: String, args: Ls[PathLike], symName: String = "tmp")(k: Path => Block): Block = + ctor(blockMod(name), args, symName = symName)(k) + def shapeCtor(name: String, args: Ls[PathLike], symName: String = "tmp")(k: Shape => Block): Block = + ctor(shapeMod(name), args, symName = symName)(p => k(Shape(p))) - def blockCall(name: String, args: Ls[PathLike])(k: Path => Block): Block = - call(blockMod(name), args)(k) - def shapeCall(name: String, args: Ls[PathLike])(k: Path => Block): Block = - call(shapeMod(name), args)(k) + def blockCall(name: String, args: Ls[PathLike], symName: String = "tmp")(k: Path => Block): Block = + call(blockMod(name), args, symName = symName)(k) + def shapeCall(name: String, args: Ls[PathLike], symName: String = "tmp")(k: Path => Block): Block = + call(shapeMod(name), args, symName = symName)(k) // helpers to create and access the components of a staged value case class Shape(p: Path) @@ -90,8 +88,8 @@ class InstrumentationImpl(using State): def end: Block = Return(p, false) object StagedPath: - def mk(shape: Shape, code: Path)(k: StagedPath => Block): Block = - tuple(Ls(shape.p, code))(p => k(StagedPath(p))) + def mk(shape: Shape, code: Path, symName: String = "tmp")(k: StagedPath => Block): Block = + tuple(Ls(shape.p, code), symName)(p => k(StagedPath(p))) // linking functions defined in MLscipt @@ -103,7 +101,7 @@ class InstrumentationImpl(using State): def ruleLit(l: Literal)(k: StagedPath => Block): Block = shapeCtor("Lit", Ls(Value.Lit(l))): sp => blockCtor("ValueLit", Ls(Value.Lit(l))): cde => - StagedPath.mk(sp, cde)(k) + StagedPath.mk(sp, cde, "lit")(k) def ruleVar(r: Value.Ref)(k: StagedPath => Block): Block = // why assume it is already staged? @@ -111,12 +109,12 @@ class InstrumentationImpl(using State): // why not just use sp.code? blockCtor("Symbol", Ls(toValue(r.l.nme))): sym => blockCtor("ValueRef", Ls(sym)): cde => - StagedPath.mk(sp.shape, cde)(k) + StagedPath.mk(sp.shape, cde, "var")(k) def ruleReturn(r: Return)(k: StagedPath => Block): Block = transformResult(r.res): x => blockCtor("Return", Ls(x.code)): cde => - StagedPath.mk(x.shape, cde)(k) + StagedPath.mk(x.shape, cde, "ret")(k) def ruleAssign(a: Assign)(k: StagedPath => Block): Block = val Assign(x, r, b) = a @@ -126,12 +124,12 @@ class InstrumentationImpl(using State): blockCtor("Symbol", Ls(toValue(x.nme))): x => // need to wrap x with Symbol? blockCtor("Assign", Ls(x, y.code, z.code)): cde => - StagedPath.mk(z.shape, cde)(k) + StagedPath.mk(z.shape, cde, "ass")(k) def ruleEnd()(k: StagedPath => Block): Block = shapeCtor("Unit", Ls()): sp => blockCtor("End", Ls()): cde => - StagedPath.mk(sp, cde)(k) + StagedPath.mk(sp, cde, "end")(k) def ruleVal(defn: ValDefn, b: Block)(k: StagedPath => Block): Block = val ValDefn(tsym, x, p) = defn @@ -142,7 +140,7 @@ class InstrumentationImpl(using State): blockCtor("Symbol", Ls(toValue(x.nme))): x => blockCtor("ValDefn", Ls(x, y.code)): df => blockCtor("Define", Ls(df, z.code)): cde => - StagedPath.mk(z.shape, cde)(k) + StagedPath.mk(z.shape, cde, "val")(k) // transformations of Block From 0198eb997d8cc0562a8ce004731d5495045f7f57 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 9 Nov 2025 00:37:09 +0800 Subject: [PATCH 093/268] rename PathLike to ArgWrappable --- .../scala/hkmc2/codegen/Instrumentation.scala | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 387d4d8416..4ef75d72d2 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -24,10 +24,9 @@ import syntax.{Literal, Tree} // the previous blocks created by the fields are handled by BlockTransformer's continuation code class InstrumentationImpl(using State): - // A PathLike type is a type that can be turned into an Arg - type PathLike = Path | Symbol | Shape + type ArgWrappable = Path | Symbol | Shape - def asArg(x: PathLike): Arg = + def asArg(x: ArgWrappable): Arg = x match case p: Path => p.asArg case l: Symbol => l.asPath.asArg @@ -52,15 +51,15 @@ class InstrumentationImpl(using State): def select(qual: Path, ident: Tree.Ident): Path = Select(qual, ident)(N) - def tuple(elems: Ls[PathLike], symName: String = "tmp")(k: Path => Block): Block = + def tuple(elems: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = // is this the same as "Ls of"? assign(Tuple(false, elems.map(asArg)), symName)(k) - def ctor(cls: Path, args: Ls[PathLike], symName: String = "tmp")(k: Path => Block): Block = + def ctor(cls: Path, args: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = assign(Instantiate(false, cls, args.map(asArg)), symName)(k) // isMlsFun is probably always true? - def call(fun: Path, args: Ls[PathLike], isMlsFun: Bool = true, symName: String = "tmp")(k: Path => Block): Block = + def call(fun: Path, args: Ls[ArgWrappable], isMlsFun: Bool = true, symName: String = "tmp")(k: Path => Block): Block = assign(Call(fun, args.map(asArg))(isMlsFun, false), symName)(k) // helper for staging the constructors @@ -68,14 +67,14 @@ class InstrumentationImpl(using State): def blockMod(name: String) = summon[State].blockSymbol.asPath.selSN(name) def shapeMod(name: String) = summon[State].shapeSymbol.asPath.selSN(name) - def blockCtor(name: String, args: Ls[PathLike], symName: String = "tmp")(k: Path => Block): Block = + def blockCtor(name: String, args: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = ctor(blockMod(name), args, symName = symName)(k) - def shapeCtor(name: String, args: Ls[PathLike], symName: String = "tmp")(k: Shape => Block): Block = + def shapeCtor(name: String, args: Ls[ArgWrappable], symName: String = "tmp")(k: Shape => Block): Block = ctor(shapeMod(name), args, symName = symName)(p => k(Shape(p))) - def blockCall(name: String, args: Ls[PathLike], symName: String = "tmp")(k: Path => Block): Block = + def blockCall(name: String, args: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = call(blockMod(name), args, symName = symName)(k) - def shapeCall(name: String, args: Ls[PathLike], symName: String = "tmp")(k: Path => Block): Block = + def shapeCall(name: String, args: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = call(shapeMod(name), args, symName = symName)(k) // helpers to create and access the components of a staged value From 8fa331b20e3bf441e6fd18017004e1987b2ccd90 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 10 Nov 2025 00:37:14 +0800 Subject: [PATCH 094/268] fix applyBlock impl this makes it so modules that are not the first node of the Block will still be staged --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 4ef75d72d2..85d613e133 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -201,8 +201,8 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): // This stages any function definition, // instead of staging functions within staged modules. - override def applyBlock(b: Block): Block = b match - case Define(defn, rest) => + override def applyBlock(b: Block): Block = super.applyBlock(b) match + case d @ Define(defn, rest) => defn match // case f @ FunDefn(owner, sym, parameters, body) => // val genSym = BlockMemberSymbol("gen", Nil, true) // TODO: reuse original function name? @@ -230,5 +230,5 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): val newModule = c.copy(sym = c.sym, companion = Some(newCompanion)) val debugBlock: Block = debugPrintCode.foldRight(rest)((b1, b2) => b1.mapTail { case _ => b2 }) Define(newModule, debugBlock) - case _ => b - case _ => b + case _ => d + case b => b From e167b2062777c37d3302a151ca0ae7f9532aeab2 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 10 Nov 2025 08:45:03 +0800 Subject: [PATCH 095/268] refactor transformFunDefn clean up function staging logic --- .../scala/hkmc2/codegen/Instrumentation.scala | 53 ++++++------------- 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 85d613e133..87cbd7a512 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -161,29 +161,26 @@ class InstrumentationImpl(using State): val Arg(spread, value) = a transformPath(value)(k) - def transformFunDefn(f: FunDefn): FunDefn = - val FunDefn(owner, sym, parameters, body) = f - val genSym = BlockMemberSymbol(sym.nme + "_gen", Nil, true) + // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function + // so we pass modSym instead + def transformFunDefn(modSym: Symbol, f: FunDefn): (FunDefn, Block) = + val genSym = BlockMemberSymbol(f.sym.nme + "_gen", Nil, true) // TODO: remove it. only for test // TODO: put correct parameters instead of Nil - val b = call(genSym.asPath, Nil): ret => - blockCall("printCode", Ls(StagedPath(ret).code)): _ => // discard result, we only care about side effect - transformBlock(body)(_.end) - FunDefn(owner, genSym, parameters, transformBlock(body)(_.end)) + val debug = + call(modSym.asPath.selSN(genSym.nme), Nil): ret => + blockCall("printCode", Ls(StagedPath(ret).code)): _ => // discard result, we only care about side effect + End() + + ( + f.copy(sym = genSym, body = transformBlock(f.body)(_.end)), + debug + ) def transformDefine(d: Define)(k: StagedPath => Block): Block = d.defn match // duplicated because we need a reference to genSym here - case f @ FunDefn(owner, sym, parameters, body) => - val genSym = BlockMemberSymbol(sym.nme + "_gen", Nil, true) - val b = transformBlock(d.rest): res => - // TODO: remove it. only for test - // TODO: put correct parameters instead of Nil - call(genSym.asPath, Nil): ret => - blockCall("printCode", Ls(StagedPath(ret).code)): _ => // discard result, we only care about side effect - res.end - val rest = Define(FunDefn(owner, genSym, parameters, transformBlock(body)(_.end)), b) - Define(f, rest) + case f: FunDefn => ??? case v: ValDefn => ruleVal(v, d.rest)(k) case c: ClsLikeDefn => ??? // nested class? @@ -204,28 +201,12 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): override def applyBlock(b: Block): Block = super.applyBlock(b) match case d @ Define(defn, rest) => defn match - // case f @ FunDefn(owner, sym, parameters, body) => - // val genSym = BlockMemberSymbol("gen", Nil, true) // TODO: reuse original function name? - // val staged = FunDefn(owner, genSym, parameters, impl.transformBlock(body)(_.end)) - // // TODO: remove it. only for test - // // TODO: put correct parameters instead of Nil - // val b = impl.call(genSym.asPath, Nil): ret => - // // discard result, we only care about side effect of printCode - // impl.blockCall("printCode", Ls(impl.StagedPath(ret).code)): _ => - // applyBlock(rest) - // Define(f, Define(staged, b)) // find modules with staged annotation case c: ClsLikeDefn if c.sym.defn.exists(_.hasStagedModifier.isDefined) && c.companion.isDefined => val companion = c.companion.get - val (stagedMethods, debugPrintCode) = companion.methods.map { case f @ FunDefn(owner, sym, parameters, body) => - val genSym = BlockMemberSymbol(sym.nme + "_gen", Nil, true) // TODO: reuse original function name? - // TODO: remove it. only for test - // TODO: put correct parameters instead of Nil - val b: Block = impl.call(c.sym.asPath.selSN(genSym.nme), Nil): ret => - impl.blockCall("printCode", Ls(impl.StagedPath(ret).code)): _ => // discard result, we only care about side effect - End() - (f.copy(sym = genSym, body = impl.transformBlock(body)(_.end)), b) - }.unzip + val (stagedMethods, debugPrintCode) = companion.methods + .map(impl.transformFunDefn(c.sym, _)) + .unzip val newCompanion = companion.copy(methods = companion.methods ++ stagedMethods) val newModule = c.copy(sym = c.sym, companion = Some(newCompanion)) val debugBlock: Block = debugPrintCode.foldRight(rest)((b1, b2) => b1.mapTail { case _ => b2 }) From 0e08e07e433d12fdcf59d6701b3d078946b36c50 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 10 Nov 2025 08:52:57 +0800 Subject: [PATCH 096/268] remove spread from Arg this makes having to import Option and makes transformArg easier to implement --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 0db9c74c0e..f8e4f0e898 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -16,7 +16,7 @@ class Symbol(val name: Str) type Ident = Symbol type Literal = null | undefined | Str | Int | Num | Bool -class Arg(val spread: Opt[Bool], val value: Path) // unused +type Arg = Path type ParamList = Array[Symbol] @@ -81,13 +81,8 @@ fun showPath(p: Path): Str = ValueLit(lit) then "Lit(" + showLiteral(lit) + ")" -fun showArg(a: Arg) = - if a.spread is - Some(true) then "..." + showPath(a.value) - _ then showPath(a.value) - fun showArgs(args: Array[Arg]) = - "[" + args.map(showArg).joinWith(", ") + "]" + "[" + args.map(showPath).joinWith(", ") + "]" // Case (match arm patterns) fun showCase(c: Case): Str = @@ -149,7 +144,6 @@ fun show(x) = Result then showResult(x) Case then showCase(x) Defn then showDefn(x) - Arg then showArg(x) Block then showBlock(x) else "" From 827f6af3ab0dd840b11f685cdf196910fda63395 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 10 Nov 2025 09:56:27 +0800 Subject: [PATCH 097/268] clean up outdated comments and helpers --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 87cbd7a512..9807c1c8dd 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -48,9 +48,6 @@ class InstrumentationImpl(using State): val tmp = new TempSymbol(N, symName) Assign(tmp, res, k(tmp.asPath)) - def select(qual: Path, ident: Tree.Ident): Path = - Select(qual, ident)(N) - def tuple(elems: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = // is this the same as "Ls of"? assign(Tuple(false, elems.map(asArg)), symName)(k) @@ -105,7 +102,6 @@ class InstrumentationImpl(using State): def ruleVar(r: Value.Ref)(k: StagedPath => Block): Block = // why assume it is already staged? val sp = StagedPath(r) - // why not just use sp.code? blockCtor("Symbol", Ls(toValue(r.l.nme))): sym => blockCtor("ValueRef", Ls(sym)): cde => StagedPath.mk(sp.shape, cde, "var")(k) @@ -121,7 +117,6 @@ class InstrumentationImpl(using State): (Assign(x, y.p, _)): transformBlock(b): z => blockCtor("Symbol", Ls(toValue(x.nme))): x => - // need to wrap x with Symbol? blockCtor("Assign", Ls(x, y.code, z.code)): cde => StagedPath.mk(z.shape, cde, "ass")(k) @@ -209,7 +204,7 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): .unzip val newCompanion = companion.copy(methods = companion.methods ++ stagedMethods) val newModule = c.copy(sym = c.sym, companion = Some(newCompanion)) - val debugBlock: Block = debugPrintCode.foldRight(rest)((b1, b2) => b1.mapTail { case _ => b2 }) + val debugBlock = debugPrintCode.foldRight(rest)((b1, b2) => b1.mapTail { case _ => b2 }) Define(newModule, debugBlock) case _ => d case b => b From 57b45fd5d6d8bd9976da4f755068190450381d80 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 10 Nov 2025 10:26:38 +0800 Subject: [PATCH 098/268] implement ruleTup --- .../scala/hkmc2/codegen/Instrumentation.scala | 27 +++++++++++++++++++ .../src/test/mlscript-compile/Block.mls | 2 +- .../src/test/mlscript/staging/Functions.mls | 4 ++- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 9807c1c8dd..8ac4e34969 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -41,6 +41,17 @@ class InstrumentationImpl(using State): case n: BigDecimal => Tree.DecLit(n) Value.Lit(l) + // TODO: use BlockTransformer.applyListOf? + extension [A](ls: Ls[(A => Block) => Block]) + def collectApply(f: Ls[A] => Block): Block = + // defer applying k while prepending new paths to the list + ls.foldRight((_: Ls[A] => Block)(Nil))((headCont, tailCont) => + k => + headCont: head => + tailCont: tail => + k(head :: tail) + )(f) + // helpers corresponding to constructors def assign(res: Result, symName: String = "tmp")(k: Path => Block): Assign = @@ -106,6 +117,15 @@ class InstrumentationImpl(using State): blockCtor("ValueRef", Ls(sym)): cde => StagedPath.mk(sp.shape, cde, "var")(k) + def ruleTup(t: Tuple)(k: StagedPath => Block): Block = + assert(!t.mut) + transformArgs(t.elems): xs => + tuple(xs.map(_.shape)): shapes => + shapeCtor("Arr", Ls(shapes)): sp => + tuple(xs.map(_.code)): codes => + blockCtor("Tuple", Ls(codes)): cde => + StagedPath.mk(sp, cde, "tup")(k) + def ruleReturn(r: Return)(k: StagedPath => Block): Block = transformResult(r.res): x => blockCtor("Return", Ls(x.code)): cde => @@ -150,12 +170,17 @@ class InstrumentationImpl(using State): transformPath(p): p => blockCtor("TrivialResult", Ls(p.code)): cde => StagedPath.mk(p.shape, cde)(k) + case t: Tuple => ruleTup(t)(k) case _ => ??? // not supported def transformArg(a: Arg)(k: StagedPath => Block): Block = val Arg(spread, value) = a transformPath(value)(k) + // provides list of shapes and list of codes to continuation + def transformArgs(args: Ls[Arg])(k: Ls[StagedPath] => Block): Block = + args.map(transformArg).collectApply(k) + // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function // so we pass modSym instead def transformFunDefn(modSym: Symbol, f: FunDefn): (FunDefn, Block) = @@ -185,6 +210,8 @@ class InstrumentationImpl(using State): case a: Assign => ruleAssign(a)(k) case d: Define => transformDefine(d)(k) case End(_) => ruleEnd()(k) + // temporary measure to accept returning an array + case Begin(b1, b2) => transformBlock(b1.mapTail { case _ => b2 })(k) case _ => ??? // not supported // TODO: rename as InstrumentationTransformer? diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index f8e4f0e898..30fee28783 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -82,7 +82,7 @@ fun showPath(p: Path): Str = "Lit(" + showLiteral(lit) + ")" fun showArgs(args: Array[Arg]) = - "[" + args.map(showPath).joinWith(", ") + "]" + "[" + args.map(showPath).join(", ") + "]" // Case (match arm patterns) fun showCase(c: Case): Str = diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 9f61a56a4c..5dddcb891e 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -8,9 +8,11 @@ staged module A with let x = 42 let y = x y - fun i() = + fun h() = val x = 1 x + fun i() = [1, 2] //│ > Return(Lit(1), false) //│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) //│ > Define(ValDefn(Symbol("x"), Lit(1)), Return(Ref(Symbol("x")), false)) +//│ > Return(Tuple([Lit(1), Lit(2)]), false) From 37eb7a10181a4a92fe633fe1ee89ca1f412d3b23 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 10 Nov 2025 10:51:09 +0800 Subject: [PATCH 099/268] formatting --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 8ac4e34969..de8f29b61c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -105,9 +105,9 @@ class InstrumentationImpl(using State): // instrumentation rules - def ruleLit(l: Literal)(k: StagedPath => Block): Block = - shapeCtor("Lit", Ls(Value.Lit(l))): sp => - blockCtor("ValueLit", Ls(Value.Lit(l))): cde => + def ruleLit(l: Value.Lit)(k: StagedPath => Block): Block = + shapeCtor("Lit", Ls(l)): sp => + blockCtor("ValueLit", Ls(l)): cde => StagedPath.mk(sp, cde, "lit")(k) def ruleVar(r: Value.Ref)(k: StagedPath => Block): Block = @@ -161,7 +161,7 @@ class InstrumentationImpl(using State): def transformPath(p: Path)(k: StagedPath => Block): Block = p match case r: Value.Ref => ruleVar(r)(k) - case Value.Lit(lit) => ruleLit(lit)(k) + case l: Value.Lit => ruleLit(l)(k) case _ => ??? // not supported def transformResult(r: Result)(k: StagedPath => Block): Block = From 69f5997ce86603cc7f897cf367fb323004b56b75 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:22:36 +0800 Subject: [PATCH 100/268] implement ruleSel and ruleInst --- .../scala/hkmc2/codegen/Instrumentation.scala | 27 +++++++++++++++++++ .../src/test/mlscript-compile/Shape.mls | 6 ++--- .../src/test/mlscript/staging/Functions.mls | 12 +++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index de8f29b61c..af3d4109da 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -102,6 +102,8 @@ class InstrumentationImpl(using State): def fnPrintCode(p: Path)(k: Path => Block): Block = blockCall("printCode", Ls(p))(k) + def fnSel(s1: Shape, s2: Shape)(k: Shape => Block): Block = + shapeCall("sel", Ls(s1, s2))(s => k(Shape(s))) // instrumentation rules @@ -126,6 +128,29 @@ class InstrumentationImpl(using State): blockCtor("Tuple", Ls(codes)): cde => StagedPath.mk(sp, cde, "tup")(k) + def ruleSel(s: Select)(k: StagedPath => Block): Block = + val Select(p, i @ Tree.Ident(name)) = s + transformPath(p): x => + // TODO: figure out actual shape + shapeCtor("Dyn", Ls()): n => + fnSel(x.shape, n): sp => + blockCtor("Symbol", Ls(toValue(name))): name => + blockCtor("Select", Ls(x.code, name)): cde => + StagedPath.mk(sp, cde, "sel")(k) + + def ruleInst(i: Instantiate)(k: StagedPath => Block): Block = + val Instantiate(mut, cls, args) = i + assert(!mut) + transformArgs(args): xs => + tuple(xs.map(_.shape)): shapes => + tuple(xs.map(_.code)): codes => + // NOTE: this was not needed in the formalization + // but it seems to be necessary to stage the path? + transformPath(cls): cls => + shapeCtor("Class", Ls(cls.code, shapes)): sp => + blockCtor("Instantiate", Ls(cls.code, codes)): cde => + StagedPath.mk(sp, cde, "inst")(k) + def ruleReturn(r: Return)(k: StagedPath => Block): Block = transformResult(r.res): x => blockCtor("Return", Ls(x.code)): cde => @@ -162,6 +187,7 @@ class InstrumentationImpl(using State): p match case r: Value.Ref => ruleVar(r)(k) case l: Value.Lit => ruleLit(l)(k) + case s: Select => ruleSel(s)(k) case _ => ??? // not supported def transformResult(r: Result)(k: StagedPath => Block): Block = @@ -171,6 +197,7 @@ class InstrumentationImpl(using State): blockCtor("TrivialResult", Ls(p.code)): cde => StagedPath.mk(p.shape, cde)(k) case t: Tuple => ruleTup(t)(k) + case i: Instantiate => ruleInst(i)(k) case _ => ??? // not supported def transformArg(a: Arg)(k: StagedPath => Block): Block = diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index a688490556..f149533b3c 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -12,12 +12,12 @@ module Shape with... class Shape with constructor - Dyn + Dyn() Lit(val l: Literal) Arr(val shapes: Array[Shape]) // is length parameter needed? // TODO: change sym to accept multiple possible class symbols? Class(val sym: Symbol, val shapes: Array[Shape]) - Unit + Unit() fun isPrimitiveType(sym: Str) = if sym is @@ -67,7 +67,7 @@ fun sel(s1: Shape, s2: Shape) = [Dyn, Lit(n)] and n is Int then Dyn [Dyn, Dyn] then Dyn - _ then ??? + _ then Dyn // temp, makes call not error fun static(s: Shape) = if s diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 5dddcb891e..cd00dea636 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -2,6 +2,7 @@ :js :staging // :ssjs +class B() staged module A with fun f() = 1 fun g() = @@ -12,7 +13,18 @@ staged module A with val x = 1 x fun i() = [1, 2] + fun j() = new B() //│ > Return(Lit(1), false) //│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) //│ > Define(ValDefn(Symbol("x"), Lit(1)), Return(Ref(Symbol("x")), false)) //│ > Return(Tuple([Lit(1), Lit(2)]), false) +//│ > Return(Instantiate(Select(Ref(Symbol("B")), Symbol("class")), []), false) + +// collision with class name? +:js +:staging +:fixme +class A() +staged module A with + fun f() = 1 +//│ ═══[RUNTIME ERROR] TypeError: A3.f_gen is not a function From 6831c6157a4747269c64246ed43ea48566a258a1 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:24:58 +0800 Subject: [PATCH 101/268] remove outdated comment --- hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index af3d4109da..f0fd125d7a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -60,7 +60,6 @@ class InstrumentationImpl(using State): Assign(tmp, res, k(tmp.asPath)) def tuple(elems: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = - // is this the same as "Ls of"? assign(Tuple(false, elems.map(asArg)), symName)(k) def ctor(cls: Path, args: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = From ab92537dd3655bb4661a1abfc224e0e286ceb773 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:48:11 +0800 Subject: [PATCH 102/268] clean up symName printing --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index f0fd125d7a..277df5fcc2 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -75,9 +75,9 @@ class InstrumentationImpl(using State): def shapeMod(name: String) = summon[State].shapeSymbol.asPath.selSN(name) def blockCtor(name: String, args: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = - ctor(blockMod(name), args, symName = symName)(k) + ctor(blockMod(name), args)(k) def shapeCtor(name: String, args: Ls[ArgWrappable], symName: String = "tmp")(k: Shape => Block): Block = - ctor(shapeMod(name), args, symName = symName)(p => k(Shape(p))) + ctor(shapeMod(name), args)(p => k(Shape(p))) def blockCall(name: String, args: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = call(blockMod(name), args, symName = symName)(k) @@ -153,7 +153,7 @@ class InstrumentationImpl(using State): def ruleReturn(r: Return)(k: StagedPath => Block): Block = transformResult(r.res): x => blockCtor("Return", Ls(x.code)): cde => - StagedPath.mk(x.shape, cde, "ret")(k) + StagedPath.mk(x.shape, cde, "return")(k) def ruleAssign(a: Assign)(k: StagedPath => Block): Block = val Assign(x, r, b) = a @@ -162,7 +162,7 @@ class InstrumentationImpl(using State): transformBlock(b): z => blockCtor("Symbol", Ls(toValue(x.nme))): x => blockCtor("Assign", Ls(x, y.code, z.code)): cde => - StagedPath.mk(z.shape, cde, "ass")(k) + StagedPath.mk(z.shape, cde, "assign")(k) def ruleEnd()(k: StagedPath => Block): Block = shapeCtor("Unit", Ls()): sp => From 29c1109a2ce574c261b419891a46489fd5b0d901 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:48:50 +0800 Subject: [PATCH 103/268] formatting --- .../scala/hkmc2/codegen/Instrumentation.scala | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 277df5fcc2..578501349b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -54,34 +54,34 @@ class InstrumentationImpl(using State): // helpers corresponding to constructors - def assign(res: Result, symName: String = "tmp")(k: Path => Block): Assign = + def assign(res: Result, symName: Str = "tmp")(k: Path => Block): Assign = // TODO: skip assignment if res: Path? val tmp = new TempSymbol(N, symName) Assign(tmp, res, k(tmp.asPath)) - def tuple(elems: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = + def tuple(elems: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = assign(Tuple(false, elems.map(asArg)), symName)(k) - def ctor(cls: Path, args: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = + def ctor(cls: Path, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = assign(Instantiate(false, cls, args.map(asArg)), symName)(k) // isMlsFun is probably always true? - def call(fun: Path, args: Ls[ArgWrappable], isMlsFun: Bool = true, symName: String = "tmp")(k: Path => Block): Block = + def call(fun: Path, args: Ls[ArgWrappable], isMlsFun: Bool = true, symName: Str = "tmp")(k: Path => Block): Block = assign(Call(fun, args.map(asArg))(isMlsFun, false), symName)(k) // helper for staging the constructors - def blockMod(name: String) = summon[State].blockSymbol.asPath.selSN(name) - def shapeMod(name: String) = summon[State].shapeSymbol.asPath.selSN(name) + def blockMod(name: Str) = summon[State].blockSymbol.asPath.selSN(name) + def shapeMod(name: Str) = summon[State].shapeSymbol.asPath.selSN(name) - def blockCtor(name: String, args: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = + def blockCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = ctor(blockMod(name), args)(k) - def shapeCtor(name: String, args: Ls[ArgWrappable], symName: String = "tmp")(k: Shape => Block): Block = + def shapeCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Shape => Block): Block = ctor(shapeMod(name), args)(p => k(Shape(p))) - def blockCall(name: String, args: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = + def blockCall(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = call(blockMod(name), args, symName = symName)(k) - def shapeCall(name: String, args: Ls[ArgWrappable], symName: String = "tmp")(k: Path => Block): Block = + def shapeCall(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = call(shapeMod(name), args, symName = symName)(k) // helpers to create and access the components of a staged value @@ -94,7 +94,7 @@ class InstrumentationImpl(using State): def end: Block = Return(p, false) object StagedPath: - def mk(shape: Shape, code: Path, symName: String = "tmp")(k: StagedPath => Block): Block = + def mk(shape: Shape, code: Path, symName: Str = "tmp")(k: StagedPath => Block): Block = tuple(Ls(shape.p, code), symName)(p => k(StagedPath(p))) // linking functions defined in MLscipt From 55fdf2666d7ea4fec0a440116a211b9afb3c07a3 Mon Sep 17 00:00:00 2001 From: TYeung Date: Tue, 11 Nov 2025 20:08:49 +0800 Subject: [PATCH 104/268] Add shape in diff testing --- hkmc2/shared/src/test/mlscript/staging/PrintCode.mls | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls index 332923c4f8..a09ef4f3a2 100644 --- a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls +++ b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls @@ -40,6 +40,14 @@ //│ Class: fun Class { class: class Class }, //│ Unit: class Unit //│ } +//│ Shape = class Shape { +//│ Shape: class Shape, +//│ Dyn: class Dyn, +//│ Lit: fun Lit { class: class Lit }, +//│ Arr: fun Arr { class: class Arr }, +//│ Class: fun Class { class: class Class }, +//│ Unit: class Unit +//│ } Block.printCode(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x")], Block.Return(Block.TrivialResult(Block.ValueLit(1)), false))) //│ > FunDefn(Symbol("f"), [Symbol("x")], Return(Lit(1), false)) From 1e0eb651696629888d3ad5f3160df88f9cfcbd6a Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 17 Nov 2025 09:57:45 +0800 Subject: [PATCH 105/268] update note as BlockTransformer doesn't pass around a context, the implementation should be more than just a extension of BlockTransformer --- .../main/scala/hkmc2/codegen/Instrumentation.scala | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 578501349b..37fc7544fb 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -13,15 +13,8 @@ import semantics.Elaborator.State import syntax.{Literal, Tree} -// TODO: I didn't use BlockTransformer here, because in some cases it constrains the type of the continuation -// but it seems some logic should be deferred to it to dedup code - -// it should be possible to convert to the BlockTransformer signatures, -// but it would require re-extracting and re-assigning StagedPath from the output. - -// the continuation would basically be solely dedicated to staging then? -// like, we do a transformation on DynSelect where we keep the fields inteact, then perform staging in the DynSelect => Block continuation? -// the previous blocks created by the fields are handled by BlockTransformer's continuation code +// it seems some logic should be deferred to BlockTransformer to dedup code +// but it doesn't accept the current context, so applications seem limited class InstrumentationImpl(using State): type ArgWrappable = Path | Symbol | Shape From 772c93a42514afb17959df023a1556258a2ee656 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 17 Nov 2025 11:16:00 +0800 Subject: [PATCH 106/268] update Shape constructors --- .../scala/hkmc2/codegen/Instrumentation.scala | 11 ++-- .../src/test/mlscript-compile/Shape.mls | 61 +++++++++---------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 37fc7544fb..4731443a26 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -34,7 +34,7 @@ class InstrumentationImpl(using State): case n: BigDecimal => Tree.DecLit(n) Value.Lit(l) - // TODO: use BlockTransformer.applyListOf? + // TODO: use BlockTransformer.applyListOf? extension [A](ls: Ls[(A => Block) => Block]) def collectApply(f: Ls[A] => Block): Block = // defer applying k while prepending new paths to the list @@ -104,6 +104,7 @@ class InstrumentationImpl(using State): blockCtor("ValueLit", Ls(l)): cde => StagedPath.mk(sp, cde, "lit")(k) + // outdated def ruleVar(r: Value.Ref)(k: StagedPath => Block): Block = // why assume it is already staged? val sp = StagedPath(r) @@ -158,10 +159,12 @@ class InstrumentationImpl(using State): StagedPath.mk(z.shape, cde, "assign")(k) def ruleEnd()(k: StagedPath => Block): Block = - shapeCtor("Unit", Ls()): sp => - blockCtor("End", Ls()): cde => - StagedPath.mk(sp, cde, "end")(k) + assign(State.globalThisSymbol.asPath.selSN("Set")): newSet => + shapeCtor("Multiple", Ls(newSet)): sp => + blockCtor("End", Ls()): cde => + StagedPath.mk(sp, cde, "end")(k) + // converted to ruleLet? def ruleVal(defn: ValDefn, b: Block)(k: StagedPath => Block): Block = val ValDefn(tsym, x, p) = defn transformPath(p): y => diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index f149533b3c..b6ee6fa1d8 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -15,9 +15,8 @@ class Shape with Dyn() Lit(val l: Literal) Arr(val shapes: Array[Shape]) // is length parameter needed? - // TODO: change sym to accept multiple possible class symbols? Class(val sym: Symbol, val shapes: Array[Shape]) - Unit() + Multiple(val shapes: Set) // empty represents bottom fun isPrimitiveType(sym: Str) = if sym is @@ -58,24 +57,28 @@ fun mrg(s1: Array[Shape]) = fun sel(s1: Shape, s2: Shape) = if [s1, s2] is - [Class(c, shapes), Lit(n)] - and n is Str then shapes.at(n) // field name election using Str? - [Dyn, Lit(n)] - and n is Str then Dyn - [Arr(shapes), Lit(n)] - and n is Int then shapes.at(n) - [Dyn, Lit(n)] - and n is Int then Dyn - [Dyn, Dyn] then Dyn + [Class(c, shapes), Lit(n)] and n is Str + then shapes.at(n) // field name election using Str? + [Dyn, Lit(n)] and n is Str + then Dyn + [Arr(shapes), Lit(n)] and n is Int + then shapes.at(n) + [Arr(shapes), Dyn] then + Multiple(new Set(shapes)) + [Dyn, Lit(n)] and n is Int + then Dyn + [Dyn, Dyn] + then Dyn + [Multiple(shapes), s2] + then Multiple(new Set(shapes.values().map((s, _) => sel(s, s2)))) _ then Dyn // temp, makes call not error fun static(s: Shape) = - if s - == Dyn then false - is - Lit(l) then not (l is Str and isPrimitiveType(l)) // redundant bracket? - Class(_, shapes) then shapes.every((s, _, _) => static(s)) - Arr(shapes) then shapes.every((s, _, _) => static(s)) + if s is + Dyn then false + Lit(l) then not (l is Str and isPrimitiveType(l)) // redundant bracket? + Class(_, shapes) then shapes.every((s, _, _) => static(s)) + Arr(shapes) then shapes.every((s, _, _) => static(s)) type SLit = Lit open Block @@ -89,19 +92,13 @@ fun silh(p: Case): Shape = if p is Field(name) then ??? Wildcard then Dyn -fun match(s: Shape, p: Case): Option[Bool] = +fun filter(s: Shape, p: Case): Shape = if [s, p] is - [Lit(l1), Lit(l2)] then Some(true) - [Lit(l), Cls(c, _)] and isPrimitiveTypeOf(c, l) then Some(true) - [Class(c1, _), Cls(c2, _)] and c1 == c2 then Some(true) - [Arr(ls), Tup(n, inf)] and ls.length == n then Some(true) - [_, Block.Wildcard] then Some(true) - [Shape.Dyn, _] then None - _ then Some(false) - -fun det(s: Shape, ps: Array[Case]): Bool = - ps.every((p, i, a) => - if i != ps.length - 1 - then match(s, p) == Some(false) - else match(s, p) == Some(true) - ) + [_, Wildcard] then s + [Lit(l1), Lit(l2)] and l1 == l2 then l1 // typo? should be Lit(l1)? + [Lit(l), Cls(c, _)] and isPrimitiveTypeOf(c, l) then s + [Arr(ls), Tup(n, _)] and ls.length == n then s + [Class(c1, _), Cls(c2, _)] and c1 == c2 then s + [Dyn, _] then silh(p) + [Multiple(shapes), _] then Multiple(shapes.map((s, _, _) => filter(s, p))) + _ then Multiple(new Set()) From fbe45ea1e7a82a9363b3b45c127cc9cd71b8ff20 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 17 Nov 2025 11:53:26 +0800 Subject: [PATCH 107/268] add context --- .../scala/hkmc2/codegen/Instrumentation.scala | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 4731443a26..90cbca8e38 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -18,6 +18,7 @@ import syntax.{Literal, Tree} class InstrumentationImpl(using State): type ArgWrappable = Path | Symbol | Shape + type Context = HashMap[Path, StagedPath] def asArg(x: ArgWrappable): Arg = x match @@ -112,7 +113,7 @@ class InstrumentationImpl(using State): blockCtor("ValueRef", Ls(sym)): cde => StagedPath.mk(sp.shape, cde, "var")(k) - def ruleTup(t: Tuple)(k: StagedPath => Block): Block = + def ruleTup(t: Tuple)(using ctx: Context)(k: StagedPath => Block): Block = assert(!t.mut) transformArgs(t.elems): xs => tuple(xs.map(_.shape)): shapes => @@ -121,7 +122,7 @@ class InstrumentationImpl(using State): blockCtor("Tuple", Ls(codes)): cde => StagedPath.mk(sp, cde, "tup")(k) - def ruleSel(s: Select)(k: StagedPath => Block): Block = + def ruleSel(s: Select)(using ctx: Context)(k: StagedPath => Block): Block = val Select(p, i @ Tree.Ident(name)) = s transformPath(p): x => // TODO: figure out actual shape @@ -131,7 +132,7 @@ class InstrumentationImpl(using State): blockCtor("Select", Ls(x.code, name)): cde => StagedPath.mk(sp, cde, "sel")(k) - def ruleInst(i: Instantiate)(k: StagedPath => Block): Block = + def ruleInst(i: Instantiate)(using ctx: Context)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i assert(!mut) transformArgs(args): xs => @@ -144,19 +145,20 @@ class InstrumentationImpl(using State): blockCtor("Instantiate", Ls(cls.code, codes)): cde => StagedPath.mk(sp, cde, "inst")(k) - def ruleReturn(r: Return)(k: StagedPath => Block): Block = + def ruleReturn(r: Return)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = transformResult(r.res): x => blockCtor("Return", Ls(x.code)): cde => - StagedPath.mk(x.shape, cde, "return")(k) + StagedPath.mk(x.shape, cde, "return")(k(_, ctx)) - def ruleAssign(a: Assign)(k: StagedPath => Block): Block = + // outdated + def ruleAssign(a: Assign)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Assign(x, r, b) = a transformResult(r): y => (Assign(x, y.p, _)): - transformBlock(b): z => + transformBlock(b): z => // have ctx here? blockCtor("Symbol", Ls(toValue(x.nme))): x => blockCtor("Assign", Ls(x, y.code, z.code)): cde => - StagedPath.mk(z.shape, cde, "assign")(k) + StagedPath.mk(z.shape, cde, "assign")(k(_, ctx)) def ruleEnd()(k: StagedPath => Block): Block = assign(State.globalThisSymbol.asPath.selSN("Set")): newSet => @@ -165,7 +167,8 @@ class InstrumentationImpl(using State): StagedPath.mk(sp, cde, "end")(k) // converted to ruleLet? - def ruleVal(defn: ValDefn, b: Block)(k: StagedPath => Block): Block = + // outdated + def ruleVal(defn: ValDefn, b: Block)(using ctx: Context)(k: StagedPath => Block): Block = val ValDefn(tsym, x, p) = defn transformPath(p): y => // y is StagedPath, not Path? @@ -178,14 +181,14 @@ class InstrumentationImpl(using State): // transformations of Block - def transformPath(p: Path)(k: StagedPath => Block): Block = + def transformPath(p: Path)(using ctx: Context)(k: StagedPath => Block): Block = p match case r: Value.Ref => ruleVar(r)(k) case l: Value.Lit => ruleLit(l)(k) case s: Select => ruleSel(s)(k) - case _ => ??? // not supported + case _ => ??? // not supporteda - def transformResult(r: Result)(k: StagedPath => Block): Block = + def transformResult(r: Result)(using ctx: Context)(k: StagedPath => Block): Block = r match case p: Path => transformPath(p): p => @@ -195,17 +198,17 @@ class InstrumentationImpl(using State): case i: Instantiate => ruleInst(i)(k) case _ => ??? // not supported - def transformArg(a: Arg)(k: StagedPath => Block): Block = + def transformArg(a: Arg)(using ctx: Context)(k: StagedPath => Block): Block = val Arg(spread, value) = a transformPath(value)(k) // provides list of shapes and list of codes to continuation - def transformArgs(args: Ls[Arg])(k: Ls[StagedPath] => Block): Block = + def transformArgs(args: Ls[Arg])(using ctx: Context)(k: Ls[StagedPath] => Block): Block = args.map(transformArg).collectApply(k) // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function // so we pass modSym instead - def transformFunDefn(modSym: Symbol, f: FunDefn): (FunDefn, Block) = + def transformFunDefn(modSym: Symbol, f: FunDefn)(using ctx: Context): (FunDefn, Block) = val genSym = BlockMemberSymbol(f.sym.nme + "_gen", Nil, true) // TODO: remove it. only for test // TODO: put correct parameters instead of Nil @@ -219,17 +222,19 @@ class InstrumentationImpl(using State): debug ) - def transformDefine(d: Define)(k: StagedPath => Block): Block = + def transformDefine(d: Define)(using ctx: Context)(k: StagedPath => Block): Block = d.defn match // duplicated because we need a reference to genSym here case f: FunDefn => ??? case v: ValDefn => ruleVal(v, d.rest)(k) case c: ClsLikeDefn => ??? // nested class? - def transformBlock(b: Block)(k: StagedPath => Block): Block = + def transformBlock(b: Block)(using ctx: Context)(k: StagedPath => Block): Block = + // ruleBlk? + val k2 = (p: StagedPath, ctx: Context) => k(p) b match - case r: Return => ruleReturn(r)(k) - case a: Assign => ruleAssign(a)(k) + case r: Return => ruleReturn(r)(k2) + case a: Assign => ruleAssign(a)(k2) case d: Define => transformDefine(d)(k) case End(_) => ruleEnd()(k) // temporary measure to accept returning an array @@ -249,7 +254,7 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): case c: ClsLikeDefn if c.sym.defn.exists(_.hasStagedModifier.isDefined) && c.companion.isDefined => val companion = c.companion.get val (stagedMethods, debugPrintCode) = companion.methods - .map(impl.transformFunDefn(c.sym, _)) + .map(impl.transformFunDefn(c.sym, _)(using new HashMap())) // fold instead to retain env? .unzip val newCompanion = companion.copy(methods = companion.methods ++ stagedMethods) val newModule = c.copy(sym = c.sym, companion = Some(newCompanion)) From 873c8cc2259efc7751ea79e977e8881796090e4a Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 17 Nov 2025 11:53:46 +0800 Subject: [PATCH 108/268] remove outdated comments --- .../shared/src/main/scala/hkmc2/codegen/Instrumentation.scala | 3 --- 1 file changed, 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 90cbca8e38..0617675a75 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -224,7 +224,6 @@ class InstrumentationImpl(using State): def transformDefine(d: Define)(using ctx: Context)(k: StagedPath => Block): Block = d.defn match - // duplicated because we need a reference to genSym here case f: FunDefn => ??? case v: ValDefn => ruleVal(v, d.rest)(k) case c: ClsLikeDefn => ??? // nested class? @@ -245,8 +244,6 @@ class InstrumentationImpl(using State): class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): val impl = new InstrumentationImpl - // This stages any function definition, - // instead of staging functions within staged modules. override def applyBlock(b: Block): Block = super.applyBlock(b) match case d @ Define(defn, rest) => defn match From 31809c784a751c55d3c8b3f076af6cf67dd5eb1d Mon Sep 17 00:00:00 2001 From: TYeung Date: Thu, 20 Nov 2025 16:44:04 +0800 Subject: [PATCH 109/268] correc comment --- hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index f0fd125d7a..4fca2c8c3e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -20,7 +20,7 @@ import syntax.{Literal, Tree} // but it would require re-extracting and re-assigning StagedPath from the output. // the continuation would basically be solely dedicated to staging then? -// like, we do a transformation on DynSelect where we keep the fields inteact, then perform staging in the DynSelect => Block continuation? +// like, we do a transformation on DynSelect where we keep the fields intact, then perform staging in the DynSelect => Block continuation? // the previous blocks created by the fields are handled by BlockTransformer's continuation code class InstrumentationImpl(using State): From 91e5197ca676e329ec2eaa6672649dcb08b41aa9 Mon Sep 17 00:00:00 2001 From: TYeung Date: Thu, 20 Nov 2025 16:44:25 +0800 Subject: [PATCH 110/268] fix pretty print to print mlscript --- .../src/test/mlscript-compile/Block.mls | 158 ++++++++---------- .../src/test/mlscript/staging/PrintCode.mls | 45 +++-- 2 files changed, 103 insertions(+), 100 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 30fee28783..0b01e6915b 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -1,9 +1,8 @@ -import "./Predef.mls" +// import "./Predef.mls" import "./Option.mls" import "./StrOps.mls" -open Predef -open StrOps +// open Predef open Option module Block with... @@ -11,25 +10,25 @@ module Block with... type Opt[A] = Option[A] // dependancies referenced in Block classes, referencing implementation in Term.mls - class Symbol(val name: Str) type Ident = Symbol +// what's the difference between Ident & Symbol? type Literal = null | undefined | Str | Int | Num | Bool -type Arg = Path type ParamList = Array[Symbol] // Classes defined in Block.scala - class Path with constructor Select(val qual: Path, val name: Ident) DynSelect(val qual: Path, val fld: Path, val arrayIdx: Bool) ValueRef(val l: Symbol) ValueLit(val lit: Literal) + +class Arg(val spread: Opt[Bool], val value: Path) +// Classes defined in Block.scala -// Match pattern for staged code class Case with constructor Lit(val lit: Literal) @@ -50,104 +49,91 @@ class Defn with constructor ValDefn(val sym: Symbol, val rhs: Path) ClsLikeDefn(val sym: Symbol, val paramsOpt: Opt[ParamList], val companion: Opt[ClsLikeBody]) // unused - FunDefn(val sym: Symbol, val params: Array[ParamList], val body: Block) + FunDefn(val sym: Symbol, val params: ParamList, val body: Block, val stage: Bool) class ClsLikeBody(val isym: Symbol, val methods: Array[FunDefn], val publicFields: Array[[Symbol, Symbol]]) // unused +class Arm(val cse: Case, val body: Block) + class Block with constructor - Match(val scrut: Path, val arms: Array[[Case, Block]], val dflt: Opt[Block], val rest: Block) + Match(val scrut: Path, val arms: Array[Arm], val dflt: Opt[Block], val rest: Block) Return(val res: Result, val implct: Bool) Assign(val lhs: Symbol, val rhs: Result, val rest: Block) Define(val defn: Defn, val rest: Block) End() -fun showBool(b: Bool) = if b then "true" else "false" - -fun showLiteral(l: Literal) = l.toString() -fun showSymbol(s: Symbol) = "Symbol(" + "\"" + s.name + "\"" + ")" +fun showSymbol(s) = s.name -fun showIdent(i: Ident) = showSymbol(i) +fun showLiteral(l) = l.toString() -fun showPath(p: Path): Str = +fun showPath(p) = if p is - Select(qual, name) then - "Select(" + showPath(qual) + ", " + showIdent(name) + ")" - DynSelect(qual, fld, arrayIdx) then - "DynSelect(" + showPath(qual) + ", " + showPath(fld) + ", " + showBool(arrayIdx) + ")" - ValueRef(l) then - "Ref(" + showSymbol(l) + ")" - ValueLit(lit) then - "Lit(" + showLiteral(lit) + ")" - -fun showArgs(args: Array[Arg]) = - "[" + args.map(showPath).join(", ") + "]" - -// Case (match arm patterns) -fun showCase(c: Case): Str = - if c is - Lit(lit) then "Lit(" + showLiteral(lit) + ")" - Cls(cls, path) then "Cls(" + showSymbol(cls) + ", " + showPath(path) + ")" - Tup(len, inf) then "Tup(" + len + ", " + showBool(inf) + ")" - Field(name) then "Field(" + showIdent(name) + ")" - Wildcard then "Wildcard" + Select(qual, name) then showPath(qual) + "." + showSymbol(name) + DynSelect(qual, fld, idx) then showPath(qual) + "[" + showPath(fld) + "]" + ValueRef(s) then showSymbol(s) + ValueLit(l) then showLiteral(l) + _ then "" -fun showResult(r: Result): Str = +fun showArg(a) = + (if a.spread is Some(true) then "..." else "") + showPath(a.value) + +fun showArgs(args) = + args.map(showArg) + +fun showResult(r) = if r is - TrivialResult(path) then showPath(path) - Call(f, args) then "Call(" + showPath(f) + ", " + showArgs(args) + ")" - Instantiate(cls, args) then "Instantiate(" + showPath(cls) + ", " + showArgs(args) + ")" - Tuple(elems) then "Tuple(" + showArgs(elems) + ")" + TrivialResult(p) then showPath(p) + Call(f, args) then showPath(f) + "(" + showArgs(args) + ")" + Instantiate(cls, args) then "new " + showPath(cls) + "(" + showArgs(args) + ")" + Tuple(elems) then "(" + showArgs(elems) + ")" + +fun showCase(c) = + if c is + Lit(l) then showLiteral(l) + Cls(cls, p) then showSymbol(cls) + "(" + showPath(p) + ")" + Tup(len, inf) then "Tuple" // Simplified + Field(n) then showSymbol(n) + Wildcard then "_" + +fun showArm(a) = + showCase(a.cse) + " then " + showBlock(a.body) + +fun showParamsOpt(p) = + if p is + Some(s) then showParams(s) + None then "()" -fun showParamList(ps: ParamList) = - "[" + ps.map(s => showSymbol(s)).join(", ") + "]" +fun showParams(p: ParamList) = + "(" + p.map(showSymbol).join(", ") + ")" -fun showDefn(d: Defn): Str = +fun showDefn(d) = if d is ValDefn(sym, rhs) then - "ValDefn(" + showSymbol(sym) + ", " + showPath(rhs) + ")" - FunDefn(sym, params, body) then - "FunDefn(" + showSymbol(sym) + ", " + - showParamList(params) + ", " + - showBlock(body) + ")" - ClsLikeDefn(sym, paramsOpt, companion) then - // minimal, since this is unused in your staged Block for now - "ClsLikeDefn(" + showSymbol(sym) + ")" - -fun showOptBlock(ob: Opt[Block]) = - if ob is Some(b) then showBlock(b) else "None" - -fun showArm(pair: Case -> Block) = - if pair is [cse, body] then showCase(cse) + " -> " + showBlock(body) else "" - -fun showBlock(b: Block): Str = + "let " + showSymbol(sym) + " = " + showPath(rhs) + FunDefn(sym, params, body, stage) then + "fun " + showSymbol(sym) + "(" + params.map(showSymbol) + ") =" + + (if body is Return(_, _) then " " else "\n ") + showBlock(body) + ClsLikeDefn(sym, paramsOpt, _) then + "class " + showSymbol(sym) + showParamsOpt(paramsOpt) + +fun showBlock(b) = if b is + Assign(lhs, rhs, rest) then + "let " + showSymbol(lhs) + " = " + showResult(rhs) + "\n" + showBlock(rest) + Define(d, rest) then + showDefn(d) + "\n" + showBlock(rest) + Return(res, _) then + showResult(res) Match(scrut, arms, dflt, rest) then - "Match(" + - showPath(scrut) + ", " + - "[" + arms.map(showArm).join(", ") + "], " + - showOptBlock(dflt) + ", " + - showBlock(rest) + ")" - Return(res, implct) then - "Return(" + showResult(res) + ", " + showBool(implct) + ")" - Assign(lhs, rhs, rest) then - "Assign(" + showSymbol(lhs) + ", " + showResult(rhs) + ", " + showBlock(rest) + ")" - Define(defn, rest) then - "Define(" + showDefn(defn) + ", " + showBlock(rest) + ")" - End() then "End" - -fun show(x) = - if x is - Symbol then showSymbol(x) - Path then showPath(x) - Result then showResult(x) - Case then showCase(x) - Defn then showDefn(x) - Block then showBlock(x) - else - "" - -fun printCode(x) = print(show(x)) - -fun compile(p: Block) = ??? \ No newline at end of file + "if " + showPath(scrut) + " is\n" + + arms.map(showArm).join("\n") + + (if dflt is Some(db) then "\nelse " + showBlock(db) else "") + + "\n" + showBlock(rest) + End() then "" + _ then "" + +fun printCode(p: Block) = + let s = showBlock(p) in + console.log(s) diff --git a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls index a09ef4f3a2..1a3c7f27b9 100644 --- a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls +++ b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls @@ -3,12 +3,12 @@ //│ Block = class Block { //│ Symbol: fun Symbol { class: class Symbol }, -//│ Arg: fun Arg { class: class Arg }, //│ Path: class Path, //│ Select: fun Select { class: class Select }, //│ DynSelect: fun DynSelect { class: class DynSelect }, //│ ValueRef: fun ValueRef { class: class ValueRef }, //│ ValueLit: fun ValueLit { class: class ValueLit }, +//│ Arg: fun Arg { class: class Arg }, //│ Case: class Case, //│ Lit: fun Lit { class: class Lit }, //│ Cls: fun Cls { class: class Cls }, @@ -25,6 +25,7 @@ //│ ClsLikeDefn: fun ClsLikeDefn { class: class ClsLikeDefn }, //│ FunDefn: fun FunDefn { class: class FunDefn }, //│ ClsLikeBody: fun ClsLikeBody { class: class ClsLikeBody }, +//│ Arm: fun Arm { class: class Arm }, //│ Block: class Block, //│ Match: fun Match { class: class Match }, //│ Return: fun Return { class: class Return }, @@ -34,21 +35,37 @@ //│ } //│ Shape = class Shape { //│ Shape: class Shape, -//│ Dyn: class Dyn, +//│ Dyn: fun Dyn { class: class Dyn }, //│ Lit: fun Lit { class: class Lit }, //│ Arr: fun Arr { class: class Arr }, //│ Class: fun Class { class: class Class }, -//│ Unit: class Unit +//│ Unit: fun Unit { class: class Unit } //│ } -//│ Shape = class Shape { -//│ Shape: class Shape, -//│ Dyn: class Dyn, -//│ Lit: fun Lit { class: class Lit }, -//│ Arr: fun Arr { class: class Arr }, -//│ Class: fun Class { class: class Class }, -//│ Unit: class Unit -//│ } - -Block.printCode(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x")], Block.Return(Block.TrivialResult(Block.ValueLit(1)), false))) -//│ > FunDefn(Symbol("f"), [Symbol("x")], Return(Lit(1), false)) +import "../../mlscript-compile/Option.mls" +open Option +Block.printCode(Block.Define(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x")], Block.Return(Block.TrivialResult(Block.ValueRef(Block.Symbol("x"))), false)), Block.Return(Block.TrivialResult(Block.ValueRef(Block.Symbol("x"))), false))) +Block.printCode( + Block.Define( + Block.ClsLikeDefn(Block.Symbol("C"), Some([Block.Symbol("x"), Block.Symbol("y")]), None), + Block.Assign( + Block.Symbol("x"), + Block.Instantiate( + Block.ValueRef(Block.Symbol("C")), [Block.Arg(Some(false), Block.ValueLit("1")), Block.Arg(Some(false), Block.ValueLit("2"))] + ), + Block.Return( + Block.TrivialResult( + Block.Select(Block.ValueRef(Block.Symbol("x")), Block.Symbol("y")) + ), + false + ) + ) + ) +) +Block.printCode(Block.Return(Block.Tuple([Block.Arg(None, Block.ValueLit(1)), Block.Arg(None, Block.ValueLit(2))]), false)) +//│ > fun f(x) = x +//│ > x +//│ > class C(x, y) +//│ > let x = new C(1,2) +//│ > x.y +//│ > (1,2) From f1886ece519879bc2a008505bce81adbe2f49866 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 20 Nov 2025 19:20:30 +0800 Subject: [PATCH 111/268] refactor add back symName parameter to {block, shape}Ctor --- .../scala/hkmc2/codegen/Instrumentation.scala | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 0617675a75..5c51f26b76 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -35,6 +35,13 @@ class InstrumentationImpl(using State): case n: BigDecimal => Tree.DecLit(n) Value.Lit(l) + def concat(b1: Block, b2: Block): Block = + b1.mapTail { + case _: Return => b2 + case _: End => b2 + case _ => ??? + } + // TODO: use BlockTransformer.applyListOf? extension [A](ls: Ls[(A => Block) => Block]) def collectApply(f: Ls[A] => Block): Block = @@ -69,9 +76,9 @@ class InstrumentationImpl(using State): def shapeMod(name: Str) = summon[State].shapeSymbol.asPath.selSN(name) def blockCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = - ctor(blockMod(name), args)(k) + ctor(blockMod(name), args, symName)(k) def shapeCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Shape => Block): Block = - ctor(shapeMod(name), args)(p => k(Shape(p))) + ctor(shapeMod(name), args, symName)(p => k(Shape(p))) def blockCall(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = call(blockMod(name), args, symName = symName)(k) @@ -217,10 +224,7 @@ class InstrumentationImpl(using State): blockCall("printCode", Ls(StagedPath(ret).code)): _ => // discard result, we only care about side effect End() - ( - f.copy(sym = genSym, body = transformBlock(f.body)(_.end)), - debug - ) + (f.copy(sym = genSym, body = transformBlock(f.body)(_.end)), debug) def transformDefine(d: Define)(using ctx: Context)(k: StagedPath => Block): Block = d.defn match @@ -237,8 +241,7 @@ class InstrumentationImpl(using State): case d: Define => transformDefine(d)(k) case End(_) => ruleEnd()(k) // temporary measure to accept returning an array - case Begin(b1, b2) => transformBlock(b1.mapTail { case _ => b2 })(k) - case _ => ??? // not supported + case Begin(b1, b2) => transformBlock(concat(b1, b2))(k) // TODO: rename as InstrumentationTransformer? class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): @@ -255,7 +258,7 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): .unzip val newCompanion = companion.copy(methods = companion.methods ++ stagedMethods) val newModule = c.copy(sym = c.sym, companion = Some(newCompanion)) - val debugBlock = debugPrintCode.foldRight(rest)((b1, b2) => b1.mapTail { case _ => b2 }) + val debugBlock = debugPrintCode.foldRight(rest)(impl.concat) Define(newModule, debugBlock) case _ => d case b => b From d99eda9121083e416eab8a223881fbf2af0435ab Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 20 Nov 2025 19:21:03 +0800 Subject: [PATCH 112/268] follow JSBuilder pretty printing for DynSelect in Printer --- hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index 254442efdf..f8ac2202df 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -100,10 +100,10 @@ object Printer: case Select(qual, name) => val docQual = mkDocument(qual) doc"${docQual}.${name.name}" - case DynSelect(qual, fld, true) => - val docQual = mkDocument(qual) - val docFld = mkDocument(fld) - doc"${docQual}[${docFld}]" + case DynSelect(qual, fld, ai) => + if ai + then doc"${mkDocument(qual)}.at(${mkDocument(fld)})" + else doc"${mkDocument(qual)}[${mkDocument(fld)}]" case x: Value => mkDocument(x) case _ => TODO(path) From 02303a3ff97283b5e6692aeffe3c4b230848f143 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 20 Nov 2025 19:23:53 +0800 Subject: [PATCH 113/268] remove Field from Case this makes Block.Case line up with formalization of Pattern --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 2 -- hkmc2/shared/src/test/mlscript-compile/Shape.mls | 1 - 2 files changed, 3 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 30fee28783..38ff2dffd0 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -35,7 +35,6 @@ class Case with Lit(val lit: Literal) Cls(val cls: Symbol, val path: Path) Tup(val len: Int, val inf: Bool) // TODO: remove inf? - Field(val name: Ident) Wildcard class Result with @@ -90,7 +89,6 @@ fun showCase(c: Case): Str = Lit(lit) then "Lit(" + showLiteral(lit) + ")" Cls(cls, path) then "Cls(" + showSymbol(cls) + ", " + showPath(path) + ")" Tup(len, inf) then "Tup(" + len + ", " + showBool(inf) + ")" - Field(name) then "Field(" + showIdent(name) + ")" Wildcard then "Wildcard" fun showResult(r: Result): Str = diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index b6ee6fa1d8..ab0e9aac11 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -89,7 +89,6 @@ fun silh(p: Case): Shape = if p is Cls(sym, path) then Class(sym, ???) // how to initialize array of Dyn? Tup(n, inf) then Arr(Array(n).fill(Dyn)) - Field(name) then ??? Wildcard then Dyn fun filter(s: Shape, p: Case): Shape = From d6dc21ec1e8e3988caf37d380689969a31b61222 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 20 Nov 2025 19:36:50 +0800 Subject: [PATCH 114/268] change transformBlock signature --- .../scala/hkmc2/codegen/Instrumentation.scala | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 5c51f26b76..1238d73dbc 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -233,14 +233,19 @@ class InstrumentationImpl(using State): case c: ClsLikeDefn => ??? // nested class? def transformBlock(b: Block)(using ctx: Context)(k: StagedPath => Block): Block = + transformBlock(b)((p, _) => k(p)) + + def transformBlock(b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = // ruleBlk? - val k2 = (p: StagedPath, ctx: Context) => k(p) + val k2 = k(_, ctx) b match - case r: Return => ruleReturn(r)(k2) - case a: Assign => ruleAssign(a)(k2) - case d: Define => transformDefine(d)(k) - case End(_) => ruleEnd()(k) + case r: Return => ruleReturn(r)(k) + case a: Assign => ruleAssign(a)(k) + case d: Define => transformDefine(d)(k2) + case End(_) => ruleEnd()(k2) + case _: Match => ??? // temporary measure to accept returning an array + // use BlockTransformer here? case Begin(b1, b2) => transformBlock(concat(b1, b2))(k) // TODO: rename as InstrumentationTransformer? From cde7a682a6d36ba6b801a1ef5ff58841deafee00 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 20 Nov 2025 20:09:22 +0800 Subject: [PATCH 115/268] implement more rules --- .../scala/hkmc2/codegen/Instrumentation.scala | 34 ++++++++++++------- .../src/test/mlscript/staging/Functions.mls | 2 ++ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 1238d73dbc..7d6466bfeb 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -114,11 +114,10 @@ class InstrumentationImpl(using State): // outdated def ruleVar(r: Value.Ref)(k: StagedPath => Block): Block = - // why assume it is already staged? - val sp = StagedPath(r) blockCtor("Symbol", Ls(toValue(r.l.nme))): sym => blockCtor("ValueRef", Ls(sym)): cde => - StagedPath.mk(sp.shape, cde, "var")(k) + shapeCtor("Dyn", Ls()): sp => // keep dynamic for now + StagedPath.mk(sp, cde, "var")(k) def ruleTup(t: Tuple)(using ctx: Context)(k: StagedPath => Block): Block = assert(!t.mut) @@ -132,21 +131,27 @@ class InstrumentationImpl(using State): def ruleSel(s: Select)(using ctx: Context)(k: StagedPath => Block): Block = val Select(p, i @ Tree.Ident(name)) = s transformPath(p): x => - // TODO: figure out actual shape - shapeCtor("Dyn", Ls()): n => + shapeCtor("Lit", Ls(toValue(name))): n => fnSel(x.shape, n): sp => blockCtor("Symbol", Ls(toValue(name))): name => blockCtor("Select", Ls(x.code, name)): cde => StagedPath.mk(sp, cde, "sel")(k) + def ruleDynSel(d: DynSelect)(using ctx: Context)(k: StagedPath => Block): Block = + val DynSelect(qual, fld, arrayIdx) = d + transformPath(qual): x => + transformPath(fld): y => + fnSel(x.shape, y.shape): sp => + blockCtor("DynSelect", Ls(x.code, y.code, toValue(arrayIdx))): cde => + StagedPath.mk(sp, cde, "dynsel")(k) + def ruleInst(i: Instantiate)(using ctx: Context)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i assert(!mut) transformArgs(args): xs => tuple(xs.map(_.shape)): shapes => tuple(xs.map(_.code)): codes => - // NOTE: this was not needed in the formalization - // but it seems to be necessary to stage the path? + // reuse instrumentation logic, shape of cls is discarded transformPath(cls): cls => shapeCtor("Class", Ls(cls.code, shapes)): sp => blockCtor("Instantiate", Ls(cls.code, codes)): cde => @@ -162,7 +167,7 @@ class InstrumentationImpl(using State): val Assign(x, r, b) = a transformResult(r): y => (Assign(x, y.p, _)): - transformBlock(b): z => // have ctx here? + transformBlock(b): (z, ctx) => // have ctx here? blockCtor("Symbol", Ls(toValue(x.nme))): x => blockCtor("Assign", Ls(x, y.code, z.code)): cde => StagedPath.mk(z.shape, cde, "assign")(k(_, ctx)) @@ -189,11 +194,14 @@ class InstrumentationImpl(using State): // transformations of Block def transformPath(p: Path)(using ctx: Context)(k: StagedPath => Block): Block = - p match - case r: Value.Ref => ruleVar(r)(k) - case l: Value.Lit => ruleLit(l)(k) - case s: Select => ruleSel(s)(k) - case _ => ??? // not supporteda + // rulePath + ctx.get(p).map(k).getOrElse: + p match + case r: Value.Ref => ruleVar(r)(k) + case l: Value.Lit => ruleLit(l)(k) + case s: Select => ruleSel(s)(k) + case d: DynSelect => ruleDynSel(d)(k) + case _ => ??? // not supported def transformResult(r: Result)(using ctx: Context)(k: StagedPath => Block): Block = r match diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index cd00dea636..5483b1db08 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -14,11 +14,13 @@ staged module A with x fun i() = [1, 2] fun j() = new B() + fun k() = [1].(0) //│ > Return(Lit(1), false) //│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) //│ > Define(ValDefn(Symbol("x"), Lit(1)), Return(Ref(Symbol("x")), false)) //│ > Return(Tuple([Lit(1), Lit(2)]), false) //│ > Return(Instantiate(Select(Ref(Symbol("B")), Symbol("class")), []), false) +//│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) // collision with class name? :js From 1f3ee7cda92a4fcd2ef5fa50812083b07b04d282 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 20 Nov 2025 20:13:23 +0800 Subject: [PATCH 116/268] remove import Option from Shape.mls --- hkmc2/shared/src/test/mlscript-compile/Shape.mls | 3 --- 1 file changed, 3 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index ab0e9aac11..a0850f7227 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -1,12 +1,9 @@ import "./Predef.mls" -import "./Option.mls" import "./Block.mls" open Predef -open Option type Literal = null | undefined | Str | Int | Num | Bool -type Opt[A] = Option[A] module Shape with... From 0499166b9ac89a323abb191420c901470193bbe0 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 20 Nov 2025 20:17:18 +0800 Subject: [PATCH 117/268] replace Multiple with ShapeSet we keep ShapeSet and Shape separate for now --- .../scala/hkmc2/codegen/Instrumentation.scala | 7 +++---- hkmc2/shared/src/test/mlscript-compile/Shape.mls | 15 ++++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 7d6466bfeb..11256bf6fc 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -173,10 +173,9 @@ class InstrumentationImpl(using State): StagedPath.mk(z.shape, cde, "assign")(k(_, ctx)) def ruleEnd()(k: StagedPath => Block): Block = - assign(State.globalThisSymbol.asPath.selSN("Set")): newSet => - shapeCtor("Multiple", Ls(newSet)): sp => - blockCtor("End", Ls()): cde => - StagedPath.mk(sp, cde, "end")(k) + shapeCtor("Dyn", Ls()): sp => + blockCtor("End", Ls()): cde => + StagedPath.mk(sp, cde, "end")(k) // converted to ruleLet? // outdated diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index a0850f7227..65d8d90367 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -7,13 +7,17 @@ type Literal = null | undefined | Str | Int | Num | Bool module Shape with... +// TODO: implement ShapeSet +class ShapeSet(val s: Shape) + +fun union(s1: ShapeSet, s2: ShapeSet) = ShapeSet(Dyn()) + class Shape with constructor Dyn() Lit(val l: Literal) Arr(val shapes: Array[Shape]) // is length parameter needed? Class(val sym: Symbol, val shapes: Array[Shape]) - Multiple(val shapes: Set) // empty represents bottom fun isPrimitiveType(sym: Str) = if sym is @@ -61,14 +65,12 @@ fun sel(s1: Shape, s2: Shape) = [Arr(shapes), Lit(n)] and n is Int then shapes.at(n) [Arr(shapes), Dyn] then - Multiple(new Set(shapes)) + Dyn // TODO [Dyn, Lit(n)] and n is Int then Dyn [Dyn, Dyn] then Dyn - [Multiple(shapes), s2] - then Multiple(new Set(shapes.values().map((s, _) => sel(s, s2)))) - _ then Dyn // temp, makes call not error + else Dyn // temp, makes call not error fun static(s: Shape) = if s is @@ -96,5 +98,4 @@ fun filter(s: Shape, p: Case): Shape = [Arr(ls), Tup(n, _)] and ls.length == n then s [Class(c1, _), Cls(c2, _)] and c1 == c2 then s [Dyn, _] then silh(p) - [Multiple(shapes), _] then Multiple(shapes.map((s, _, _) => filter(s, p))) - _ then Multiple(new Set()) + else Dyn // TODO From fbb869c070b28a21123b5238c9e474e8fdae3c9d Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 20 Nov 2025 20:17:55 +0800 Subject: [PATCH 118/268] misc fixes to Shape.mls --- .../src/test/mlscript-compile/Shape.mls | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index 65d8d90367..046ac5af08 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -33,10 +33,10 @@ fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = ["Int", i] and i is Int then true ["Num", n] and n is Num then true ["Bool", b] and b is Bool then true - _ then false + else false -fun zipMrg[A](a: Array[A], b: Array[A]): Array[[A, A]] = - [...Array(a.length).keys()].map((i, _, _) => mrg2(a.at(i), b.at(i))) +fun zipMrg[A](a: Array[A], b: Array[A]): Array[A] = + a.map((a, i, _) => mrg2(a, b.at(i))) // TODO: look at how Array is used fun mrg2(s1: Shape, s2: Shape) = if s1 @@ -51,7 +51,7 @@ fun mrg2(s1: Shape, s2: Shape) = if s1 Arr(s1) and s2 is Arr(s2) and s1.length == s2.length then Arr(zipMrg(s1, s2)) - else Dyn + else Dyn() fun mrg(s1: Array[Shape]) = s1.reduceRight((acc, s, _, _) => mrg2(s, acc)) @@ -61,16 +61,16 @@ fun sel(s1: Shape, s2: Shape) = [Class(c, shapes), Lit(n)] and n is Str then shapes.at(n) // field name election using Str? [Dyn, Lit(n)] and n is Str - then Dyn + then Dyn() [Arr(shapes), Lit(n)] and n is Int then shapes.at(n) [Arr(shapes), Dyn] then - Dyn // TODO + Dyn() // TODO [Dyn, Lit(n)] and n is Int - then Dyn + then Dyn() [Dyn, Dyn] - then Dyn - else Dyn // temp, makes call not error + then Dyn() + else Dyn() // temp, makes call not error fun static(s: Shape) = if s is @@ -88,14 +88,14 @@ fun silh(p: Case): Shape = if p is Cls(sym, path) then Class(sym, ???) // how to initialize array of Dyn? Tup(n, inf) then Arr(Array(n).fill(Dyn)) - Wildcard then Dyn + Wildcard then Dyn() fun filter(s: Shape, p: Case): Shape = if [s, p] is [_, Wildcard] then s - [Lit(l1), Lit(l2)] and l1 == l2 then l1 // typo? should be Lit(l1)? + [Lit(l1), Lit(l2)] and l1 == l2 then s [Lit(l), Cls(c, _)] and isPrimitiveTypeOf(c, l) then s [Arr(ls), Tup(n, _)] and ls.length == n then s [Class(c1, _), Cls(c2, _)] and c1 == c2 then s [Dyn, _] then silh(p) - else Dyn // TODO + else Dyn() // TODO From adf5590f81cc32b664753be14d87156514e6c9aa Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 20 Nov 2025 22:23:56 +0800 Subject: [PATCH 119/268] patch showLiteral for null and undefined --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 38ff2dffd0..e3060a23a5 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -63,7 +63,11 @@ class Block with fun showBool(b: Bool) = if b then "true" else "false" -fun showLiteral(l: Literal) = l.toString() +fun showLiteral(l: Literal) = + if l is + undefined then "undefined" + null then "null" + else l.toString() fun showSymbol(s: Symbol) = "Symbol(" + "\"" + s.name + "\"" + ")" From ada9c3aeff41028eabce41a351b4a09489948e5a Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 21 Nov 2025 12:54:05 +0800 Subject: [PATCH 120/268] replace ruleVal --- .../scala/hkmc2/codegen/Instrumentation.scala | 66 ++++++++++++------- .../src/test/mlscript/staging/Functions.mls | 2 +- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 11256bf6fc..9442869496 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -104,6 +104,8 @@ class InstrumentationImpl(using State): blockCall("printCode", Ls(p))(k) def fnSel(s1: Shape, s2: Shape)(k: Shape => Block): Block = shapeCall("sel", Ls(s1, s2))(s => k(Shape(s))) + def fnUnion(s1: Shape, s2: Shape)(k: Shape => Block): Block = + shapeCall("union", Ls(s1, s2))(s => k(Shape(s))) // instrumentation rules @@ -159,36 +161,52 @@ class InstrumentationImpl(using State): def ruleReturn(r: Return)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = transformResult(r.res): x => - blockCtor("Return", Ls(x.code)): cde => + blockCtor("Return", Ls(x.code, toValue(false))): cde => StagedPath.mk(x.shape, cde, "return")(k(_, ctx)) - // outdated def ruleAssign(a: Assign)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Assign(x, r, b) = a - transformResult(r): y => - (Assign(x, y.p, _)): - transformBlock(b): (z, ctx) => // have ctx here? - blockCtor("Symbol", Ls(toValue(x.nme))): x => - blockCtor("Assign", Ls(x, y.code, z.code)): cde => - StagedPath.mk(z.shape, cde, "assign")(k(_, ctx)) + // if ctx contains x, x was defined earlier + // otherwise, x is defined here + ctx.get(x.asPath) match + case S(x1) => + transformResult(r): y => + fnUnion(y.shape, x1.shape): sp => + blockCtor("Symbol", Ls(toValue(x.nme))): xSym => + blockCtor("ValueRef", Ls(xSym)): xStaged => + StagedPath.mk(sp, xStaged, "assign_x2"): x2 => + (Assign(x, x2.p, _)): + given Context = ctx.clone() += x.asPath -> x2 + transformBlock(b): (z, ctx) => + blockCtor("Assign", Ls(xSym, y.code, z.code), "assign_cde"): cde => + StagedPath.mk(z.shape, cde, "assign")(k(_, summon)) + case N => + transformResult(r): y => + (Assign(x, y.p, _)): + transformBlock(b): (z, ctx) => + blockCtor("Symbol", Ls(toValue(x.nme))): x => + blockCtor("Assign", Ls(x, y.code, z.code)): cde => + StagedPath.mk(z.shape, cde, "assign")(k(_, ctx)) + + def ruleLet(x: BlockMemberSymbol, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + val y = TempSymbol(N, "tmp") + shapeCtor("Bot", Ls()): bot => + blockCtor("Symbol", Ls(toValue(x.nme))): xSym => + StagedPath.mk(bot, xSym, "let_y"): y => + (Assign(x, y.p, _)): + given Context = ctx.clone() += x.asPath -> y + transformBlock(b): (z, ctx) => + blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false))), "let_undef"): undefined => + blockCtor("TrivialResult", Ls(undefined)): undefined => + blockCtor("Assign", Ls(xSym, undefined, z.code), "let_code"): cde => + StagedPath.mk(z.shape, cde, "_let")(k(_, summon)) def ruleEnd()(k: StagedPath => Block): Block = shapeCtor("Dyn", Ls()): sp => blockCtor("End", Ls()): cde => StagedPath.mk(sp, cde, "end")(k) - // converted to ruleLet? - // outdated - def ruleVal(defn: ValDefn, b: Block)(using ctx: Context)(k: StagedPath => Block): Block = - val ValDefn(tsym, x, p) = defn - transformPath(p): y => - // y is StagedPath, not Path? - (Define(ValDefn(tsym, x, y.p), _)): - transformBlock(b): z => - blockCtor("Symbol", Ls(toValue(x.nme))): x => - blockCtor("ValDefn", Ls(x, y.code)): df => - blockCtor("Define", Ls(df, z.code)): cde => - StagedPath.mk(z.shape, cde, "val")(k) + // transformations of Block @@ -233,10 +251,12 @@ class InstrumentationImpl(using State): (f.copy(sym = genSym, body = transformBlock(f.body)(_.end)), debug) - def transformDefine(d: Define)(using ctx: Context)(k: StagedPath => Block): Block = + def transformDefine(d: Define)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = d.defn match case f: FunDefn => ??? - case v: ValDefn => ruleVal(v, d.rest)(k) + case v: ValDefn => + val ValDefn(t, x, r) = v + ruleLet(x, Assign(x, r, d.rest))(k) case c: ClsLikeDefn => ??? // nested class? def transformBlock(b: Block)(using ctx: Context)(k: StagedPath => Block): Block = @@ -248,7 +268,7 @@ class InstrumentationImpl(using State): b match case r: Return => ruleReturn(r)(k) case a: Assign => ruleAssign(a)(k) - case d: Define => transformDefine(d)(k2) + case d: Define => transformDefine(d)(k) case End(_) => ruleEnd()(k2) case _: Match => ??? // temporary measure to accept returning an array diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 5483b1db08..5d10b7c2a1 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -17,7 +17,7 @@ staged module A with fun k() = [1].(0) //│ > Return(Lit(1), false) //│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) -//│ > Define(ValDefn(Symbol("x"), Lit(1)), Return(Ref(Symbol("x")), false)) +//│ > Assign(Symbol("x"), Lit(undefined), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false))) //│ > Return(Tuple([Lit(1), Lit(2)]), false) //│ > Return(Instantiate(Select(Ref(Symbol("B")), Symbol("class")), []), false) //│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) From 9f6b1ab8a05b1feb8014d87488bda2e471737a5d Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 21 Nov 2025 13:04:09 +0800 Subject: [PATCH 121/268] clean up --- .../scala/hkmc2/codegen/Instrumentation.scala | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 9442869496..c47dd15c25 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -166,39 +166,36 @@ class InstrumentationImpl(using State): def ruleAssign(a: Assign)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Assign(x, r, b) = a - // if ctx contains x, x was defined earlier - // otherwise, x is defined here - ctx.get(x.asPath) match - case S(x1) => - transformResult(r): y => - fnUnion(y.shape, x1.shape): sp => - blockCtor("Symbol", Ls(toValue(x.nme))): xSym => + transformResult(r): y => + blockCtor("Symbol", Ls(toValue(x.nme))): xSym => + // if ctx contains x, x was defined earlier + // otherwise, x is defined here + ctx.get(x.asPath) match + case S(x1) => + fnUnion(y.shape, x1.shape): sp => blockCtor("ValueRef", Ls(xSym)): xStaged => - StagedPath.mk(sp, xStaged, "assign_x2"): x2 => + StagedPath.mk(sp, xStaged): x2 => + given Context = ctx.clone() += x.asPath -> x2 (Assign(x, x2.p, _)): - given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => - blockCtor("Assign", Ls(xSym, y.code, z.code), "assign_cde"): cde => + blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => StagedPath.mk(z.shape, cde, "assign")(k(_, summon)) - case N => - transformResult(r): y => - (Assign(x, y.p, _)): - transformBlock(b): (z, ctx) => - blockCtor("Symbol", Ls(toValue(x.nme))): x => - blockCtor("Assign", Ls(x, y.code, z.code)): cde => - StagedPath.mk(z.shape, cde, "assign")(k(_, ctx)) + case N => + (Assign(x, y.p, _)): + transformBlock(b): (z, ctx) => + blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => + StagedPath.mk(z.shape, cde, "assign")(k(_, summon)) def ruleLet(x: BlockMemberSymbol, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = - val y = TempSymbol(N, "tmp") shapeCtor("Bot", Ls()): bot => blockCtor("Symbol", Ls(toValue(x.nme))): xSym => - StagedPath.mk(bot, xSym, "let_y"): y => + StagedPath.mk(bot, xSym): y => (Assign(x, y.p, _)): given Context = ctx.clone() += x.asPath -> y transformBlock(b): (z, ctx) => - blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false))), "let_undef"): undefined => + blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => blockCtor("TrivialResult", Ls(undefined)): undefined => - blockCtor("Assign", Ls(xSym, undefined, z.code), "let_code"): cde => + blockCtor("Assign", Ls(xSym, undefined, z.code)): cde => StagedPath.mk(z.shape, cde, "_let")(k(_, summon)) def ruleEnd()(k: StagedPath => Block): Block = From ba80ea43fbe4caa3c794da25270d01f7aa2b0fb3 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 21 Nov 2025 13:16:50 +0800 Subject: [PATCH 122/268] add symbol to Class Shape for matching --- hkmc2/shared/src/test/mlscript-compile/Shape.mls | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index 046ac5af08..a30235d03b 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -17,7 +17,8 @@ class Shape with Dyn() Lit(val l: Literal) Arr(val shapes: Array[Shape]) // is length parameter needed? - Class(val sym: Symbol, val shapes: Array[Shape]) + Class(val sym: Symbol, val params: Array[[Symbol, Shape]]) + Bot() // temp stub for ShapeSet fun isPrimitiveType(sym: Str) = if sym is From 8efd61df1a2f7e9ce980c218b179319a39973f42 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 21 Nov 2025 21:49:59 +0800 Subject: [PATCH 123/268] add spread field to Arg this introduces a new Option symbol to Elaborator if paramsOpt and companion are unused for ClsLikeDefn in Block.mls, it might be possible to avoid using Option for defining Block.mls --- .../scala/hkmc2/codegen/Instrumentation.scala | 16 +++++++++++++++- .../main/scala/hkmc2/semantics/Elaborator.scala | 1 + hkmc2/shared/src/test/mlscript-compile/Block.mls | 9 +++++++-- .../test/scala/hkmc2/JSBackendDiffMaker.scala | 2 ++ .../src/test/scala/hkmc2/MLsDiffMaker.scala | 1 + 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index c47dd15c25..a610449472 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -74,11 +74,16 @@ class InstrumentationImpl(using State): def blockMod(name: Str) = summon[State].blockSymbol.asPath.selSN(name) def shapeMod(name: Str) = summon[State].shapeSymbol.asPath.selSN(name) + def optionMod(name: Str) = summon[State].optionSymbol.asPath.selSN(name) def blockCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = ctor(blockMod(name), args, symName)(k) def shapeCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Shape => Block): Block = ctor(shapeMod(name), args, symName)(p => k(Shape(p))) + def optionSome(arg: ArgWrappable, symName: Str = "tmp")(k: Path => Block): Block = + ctor(optionMod("Some"), Ls(arg), symName)(k) + def optionNone(symName: Str = "tmp")(k: Path => Block): Block = + assign(optionMod("None"), symName)(k) def blockCall(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = call(blockMod(name), args, symName = symName)(k) @@ -207,6 +212,12 @@ class InstrumentationImpl(using State): // transformations of Block + + def transformOption[A](xOpt: Opt[A], f: A => (Path => Block) => Block)(k: Path => Block): Block = + xOpt match + case S(x) => f(x)(optionSome(_)(k)) + case N => optionNone()(k) + def transformPath(p: Path)(using ctx: Context)(k: StagedPath => Block): Block = // rulePath ctx.get(p).map(k).getOrElse: @@ -229,7 +240,10 @@ class InstrumentationImpl(using State): def transformArg(a: Arg)(using ctx: Context)(k: StagedPath => Block): Block = val Arg(spread, value) = a - transformPath(value)(k) + optionNone(): opt => + transformPath(value): value => + blockCtor("Arg", Ls(opt, value.code)): cde => + StagedPath.mk(value.shape, cde)(k) // provides list of shapes and list of codes to continuation def transformArgs(args: Ls[Arg])(using ctx: Context)(k: Ls[StagedPath] => Block): Block = diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index 92432e8c0d..d6e92ef237 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -235,6 +235,7 @@ object Elaborator: val termSymbol = TempSymbol(N, "Term") val blockSymbol = TempSymbol(N, "Block") val shapeSymbol = TempSymbol(N, "Shape") + val optionSymbol = TempSymbol(N, "Option") val wasmSymbol = TempSymbol(N, "wasm") val effectSigSymbol = ClassSymbol(DummyTypeDef(syntax.Cls), Ident("EffectSig")) val nonLocalRetHandlerTrm = diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index e3060a23a5..a441b233e5 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -16,12 +16,13 @@ class Symbol(val name: Str) type Ident = Symbol type Literal = null | undefined | Str | Int | Num | Bool -type Arg = Path type ParamList = Array[Symbol] // Classes defined in Block.scala +class Arg(val spread: Opt[Bool], val value: Path) + class Path with constructor Select(val qual: Path, val name: Ident) @@ -84,8 +85,12 @@ fun showPath(p: Path): Str = ValueLit(lit) then "Lit(" + showLiteral(lit) + ")" +fun showArg(arg: Arg) = + if arg.spread is Some(true) then "..." + showPath(arg.value) + else showPath(arg.value) + fun showArgs(args: Array[Arg]) = - "[" + args.map(showPath).join(", ") + "]" + "[" + args.map(showArg).join(", ") + "]" // Case (match arm patterns) fun showCase(c: Case): Str = diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala index 2bf32e5879..e86d5994df 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala @@ -34,6 +34,7 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: val termNme = baseScp.allocateName(Elaborator.State.termSymbol) val blockNme = baseScp.allocateName(Elaborator.State.blockSymbol) val shapeNme = baseScp.allocateName(Elaborator.State.shapeSymbol) + val optionNme = baseScp.allocateName(Elaborator.State.optionSymbol) val definitionMetadataNme = baseScp.allocateName(Elaborator.State.definitionMetadataSymbol) val prettyPrintNme = baseScp.allocateName(Elaborator.State.prettyPrintSymbol) @@ -62,6 +63,7 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: if stageCode.isSet then importRuntimeModule(blockNme, blockFile) importRuntimeModule(shapeNme, shapeFile) + importRuntimeModule(optionNme, optionFile) h private var hostCreated = false diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index e748836b81..5bbb459cd7 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -22,6 +22,7 @@ abstract class MLsDiffMaker extends DiffMaker: val termFile: os.Path = predefFile/os.up/"Term.mjs" // * Contains MLscript runtime term definitions val blockFile: os.Path = predefFile/os.up/"Block.mjs" // * Contains MLscript runtime block definitions val shapeFile: os.Path = predefFile/os.up/"Shape.mjs" // * Contains MLscript runtime shape definitions + val optionFile: os.Path = predefFile/os.up/"Option.mjs" // * Contains MLscript runtime shape definitions val wd = file / os.up From e19dbd6b705a3c50a7126f55b7e8bcc3d93ebeea Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 21 Nov 2025 22:09:14 +0800 Subject: [PATCH 124/268] update PrintCode.mls --- hkmc2/shared/src/test/mlscript/staging/PrintCode.mls | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls index fba1de4806..0314c3488d 100644 --- a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls +++ b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls @@ -3,6 +3,7 @@ //│ Block = class Block { //│ Symbol: fun Symbol { class: class Symbol }, +//│ Arg: fun Arg { class: class Arg }, //│ Path: class Path, //│ Select: fun Select { class: class Select }, //│ DynSelect: fun DynSelect { class: class DynSelect }, @@ -12,8 +13,7 @@ //│ Lit: fun Lit { class: class Lit }, //│ Cls: fun Cls { class: class Cls }, //│ Tup: fun Tup { class: class Tup }, -//│ Field: fun Field { class: class Field }, -//│ Wildcard: class Wildcard, +//│ Wildcard: fun Wildcard { class: class Wildcard }, //│ Result: class Result, //│ TrivialResult: fun TrivialResult { class: class TrivialResult }, //│ Call: fun Call { class: class Call }, @@ -32,12 +32,13 @@ //│ End: fun End { class: class End } //│ } //│ Shape = class Shape { +//│ ShapeSet: fun ShapeSet { class: class ShapeSet }, //│ Shape: class Shape, //│ Dyn: fun Dyn { class: class Dyn }, //│ Lit: fun Lit { class: class Lit }, //│ Arr: fun Arr { class: class Arr }, //│ Class: fun Class { class: class Class }, -//│ Unit: fun Unit { class: class Unit } +//│ Bot: fun Bot { class: class Bot } //│ } Block.printCode(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x")], Block.Return(Block.TrivialResult(Block.ValueLit(1)), false))) From 146a1988fa450c50ddf6cda90dd63b68fd177a4b Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 21 Nov 2025 22:20:13 +0800 Subject: [PATCH 125/268] add ruleCls --- .../scala/hkmc2/codegen/Instrumentation.scala | 36 ++++++++++++++----- .../src/test/mlscript/staging/Functions.mls | 27 +++++++++++--- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index a610449472..e1093915de 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -106,6 +106,7 @@ class InstrumentationImpl(using State): // linking functions defined in MLscipt def fnPrintCode(p: Path)(k: Path => Block): Block = + // discard result, we only care about side effect blockCall("printCode", Ls(p))(k) def fnSel(s1: Shape, s2: Shape)(k: Shape => Block): Block = shapeCall("sel", Ls(s1, s2))(s => k(Shape(s))) @@ -208,6 +209,18 @@ class InstrumentationImpl(using State): blockCtor("End", Ls()): cde => StagedPath.mk(sp, cde, "end")(k) + def ruleCls(cls: ClsLikeDefn, rest: Block)(using ctx: Context)(k: Path => Block): Block = + (Define(cls, _)): + transformBlock(rest): p => + blockCtor("Symbol", Ls(toValue(cls.sym.nme))): c => + def stageParamList(ps: ParamList)(k: Path => Block) = + ps.params.map(p => transformSymbol(p.sym)).collectApply: params => + tuple(params)(k) + transformOption(cls.paramsOpt, stageParamList): paramsOpt => + assert(cls.companion.isEmpty) // does not support nested module + optionNone(): none => + blockCtor("ClsLikeDefn", Ls(c, paramsOpt, none)): cls => + blockCtor("Define", Ls(cls, p.code))(k) // transformations of Block @@ -251,15 +264,16 @@ class InstrumentationImpl(using State): // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function // so we pass modSym instead - def transformFunDefn(modSym: Symbol, f: FunDefn)(using ctx: Context): (FunDefn, Block) = + def transformFunDefn(modSym: BlockMemberSymbol, f: FunDefn)(using ctx: Context): (FunDefn, Block) = val genSym = BlockMemberSymbol(f.sym.nme + "_gen", Nil, true) // TODO: remove it. only for test // TODO: put correct parameters instead of Nil + val sym = modSym.asPath.selSN(genSym.nme) val debug = - call(modSym.asPath.selSN(genSym.nme), Nil): ret => - blockCall("printCode", Ls(StagedPath(ret).code)): _ => // discard result, we only care about side effect - End() + call(sym, Nil): ret => + fnPrintCode(StagedPath(ret).code)(_ => End()) + // NOTE: this debug printing only works for top-level modules, nested modules don't work (f.copy(sym = genSym, body = transformBlock(f.body)(_.end)), debug) def transformDefine(d: Define)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = @@ -268,7 +282,10 @@ class InstrumentationImpl(using State): case v: ValDefn => val ValDefn(t, x, r) = v ruleLet(x, Assign(x, r, d.rest))(k) - case c: ClsLikeDefn => ??? // nested class? + case c: ClsLikeDefn => + ruleCls(c, d.rest): p => + ruleEnd(): b => + fnPrintCode(p)(_ => k(b, ctx)) def transformBlock(b: Block)(using ctx: Context)(k: StagedPath => Block): Block = transformBlock(b)((p, _) => k(p)) @@ -295,12 +312,15 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): defn match // find modules with staged annotation case c: ClsLikeDefn if c.sym.defn.exists(_.hasStagedModifier.isDefined) && c.companion.isDefined => + val sym = c.sym.subst val companion = c.companion.get val (stagedMethods, debugPrintCode) = companion.methods - .map(impl.transformFunDefn(c.sym, _)(using new HashMap())) // fold instead to retain env? + .map(impl.transformFunDefn(sym, _)(using new HashMap())) // fold instead to retain env? .unzip - val newCompanion = companion.copy(methods = companion.methods ++ stagedMethods) - val newModule = c.copy(sym = c.sym, companion = Some(newCompanion)) + val newCtor = impl.transformBlock(companion.ctor)(using new HashMap())(_ => End()) + val newCompanion = companion.copy(methods = companion.methods ++ stagedMethods, ctor = newCtor) + val newModule = c.copy(sym = sym, companion = S(newCompanion)) + // debug is printed without calling the instrumented function val debugBlock = debugPrintCode.foldRight(rest)(impl.concat) Define(newModule, debugBlock) case _ => d diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 5d10b7c2a1..09516e0a77 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -2,8 +2,10 @@ :js :staging // :ssjs -class B() -staged module A with +class A() +staged module B with + class C(a, b) + class D fun f() = 1 fun g() = let x = 42 @@ -13,13 +15,15 @@ staged module A with val x = 1 x fun i() = [1, 2] - fun j() = new B() + fun j() = new A() fun k() = [1].(0) +//│ > Define(ClsLikeDefn(Symbol("D")), End) +//│ > Define(ClsLikeDefn(Symbol("C")), End) //│ > Return(Lit(1), false) //│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) //│ > Assign(Symbol("x"), Lit(undefined), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false))) //│ > Return(Tuple([Lit(1), Lit(2)]), false) -//│ > Return(Instantiate(Select(Ref(Symbol("B")), Symbol("class")), []), false) +//│ > Return(Instantiate(Select(Ref(Symbol("A")), Symbol("class")), []), false) //│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) // collision with class name? @@ -30,3 +34,18 @@ class A() staged module A with fun f() = 1 //│ ═══[RUNTIME ERROR] TypeError: A3.f_gen is not a function + +// unable to reference the class when calling the instrumented function for debugging +:js +:staging +:fixme +module A with + staged module B with + fun f() = 1 +//│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' +//│ ╟── which references the symbol introduced here +//│ ║ l.43: staged module B with +//│ ║ ^^^^^^ +//│ ║ l.44: fun f() = 1 +//│ ╙── ^^^^^^^^^^^^^^^ +//│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From e1aedc7501bf9c9e25c7220329beaab1833b5cb2 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 21 Nov 2025 22:21:02 +0800 Subject: [PATCH 126/268] formatting --- .../scala/hkmc2/codegen/Instrumentation.scala | 58 ++++++++++--------- .../main/scala/hkmc2/codegen/Printer.scala | 1 - .../src/test/mlscript-compile/Block.mls | 2 +- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index e1093915de..8be72c6638 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -94,7 +94,7 @@ class InstrumentationImpl(using State): case class Shape(p: Path) // A StagedPath is a path that points to a (shape, code) tuple - class StagedPath(val p: Path): + case class StagedPath(p: Path): def shape: Shape = Shape(DynSelect(p, toValue(0), false)) def code: Path = DynSelect(p, toValue(1), false) def end: Block = Return(p, false) @@ -113,6 +113,15 @@ class InstrumentationImpl(using State): def fnUnion(s1: Shape, s2: Shape)(k: Shape => Block): Block = shapeCall("union", Ls(s1, s2))(s => k(Shape(s))) + // transformation helpers + + def transformSymbol(sym: Symbol)(k: Path => Block) = blockCtor("Symbol", Ls(toValue(sym.nme)))(k) + + def transformOption[A](xOpt: Opt[A], f: A => (Path => Block) => Block)(k: Path => Block): Block = + xOpt match + case S(x) => f(x)(optionSome(_)(k)) + case N => optionNone()(k) + // instrumentation rules def ruleLit(l: Value.Lit)(k: StagedPath => Block): Block = @@ -127,7 +136,7 @@ class InstrumentationImpl(using State): shapeCtor("Dyn", Ls()): sp => // keep dynamic for now StagedPath.mk(sp, cde, "var")(k) - def ruleTup(t: Tuple)(using ctx: Context)(k: StagedPath => Block): Block = + def ruleTup(t: Tuple)(using Context)(k: StagedPath => Block): Block = assert(!t.mut) transformArgs(t.elems): xs => tuple(xs.map(_.shape)): shapes => @@ -136,7 +145,7 @@ class InstrumentationImpl(using State): blockCtor("Tuple", Ls(codes)): cde => StagedPath.mk(sp, cde, "tup")(k) - def ruleSel(s: Select)(using ctx: Context)(k: StagedPath => Block): Block = + def ruleSel(s: Select)(using Context)(k: StagedPath => Block): Block = val Select(p, i @ Tree.Ident(name)) = s transformPath(p): x => shapeCtor("Lit", Ls(toValue(name))): n => @@ -145,7 +154,7 @@ class InstrumentationImpl(using State): blockCtor("Select", Ls(x.code, name)): cde => StagedPath.mk(sp, cde, "sel")(k) - def ruleDynSel(d: DynSelect)(using ctx: Context)(k: StagedPath => Block): Block = + def ruleDynSel(d: DynSelect)(using Context)(k: StagedPath => Block): Block = val DynSelect(qual, fld, arrayIdx) = d transformPath(qual): x => transformPath(fld): y => @@ -153,7 +162,7 @@ class InstrumentationImpl(using State): blockCtor("DynSelect", Ls(x.code, y.code, toValue(arrayIdx))): cde => StagedPath.mk(sp, cde, "dynsel")(k) - def ruleInst(i: Instantiate)(using ctx: Context)(k: StagedPath => Block): Block = + def ruleInst(i: Instantiate)(using Context)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i assert(!mut) transformArgs(args): xs => @@ -165,15 +174,15 @@ class InstrumentationImpl(using State): blockCtor("Instantiate", Ls(cls.code, codes)): cde => StagedPath.mk(sp, cde, "inst")(k) - def ruleReturn(r: Return)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def ruleReturn(r: Return)(using Context)(k: (StagedPath, Context) => Block): Block = transformResult(r.res): x => blockCtor("Return", Ls(x.code, toValue(false))): cde => - StagedPath.mk(x.shape, cde, "return")(k(_, ctx)) + StagedPath.mk(x.shape, cde, "return")(k(_, summon)) def ruleAssign(a: Assign)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Assign(x, r, b) = a transformResult(r): y => - blockCtor("Symbol", Ls(toValue(x.nme))): xSym => + transformSymbol(x): xSym => // if ctx contains x, x was defined earlier // otherwise, x is defined here ctx.get(x.asPath) match @@ -188,13 +197,13 @@ class InstrumentationImpl(using State): StagedPath.mk(z.shape, cde, "assign")(k(_, summon)) case N => (Assign(x, y.p, _)): - transformBlock(b): (z, ctx) => + transformBlock(b): z => // ignore ctx blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => StagedPath.mk(z.shape, cde, "assign")(k(_, summon)) def ruleLet(x: BlockMemberSymbol, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = shapeCtor("Bot", Ls()): bot => - blockCtor("Symbol", Ls(toValue(x.nme))): xSym => + transformSymbol(x): xSym => StagedPath.mk(bot, xSym): y => (Assign(x, y.p, _)): given Context = ctx.clone() += x.asPath -> y @@ -209,15 +218,14 @@ class InstrumentationImpl(using State): blockCtor("End", Ls()): cde => StagedPath.mk(sp, cde, "end")(k) - def ruleCls(cls: ClsLikeDefn, rest: Block)(using ctx: Context)(k: Path => Block): Block = + def ruleCls(cls: ClsLikeDefn, rest: Block)(using Context)(k: Path => Block): Block = (Define(cls, _)): transformBlock(rest): p => - blockCtor("Symbol", Ls(toValue(cls.sym.nme))): c => + transformSymbol(cls.sym): c => def stageParamList(ps: ParamList)(k: Path => Block) = - ps.params.map(p => transformSymbol(p.sym)).collectApply: params => - tuple(params)(k) + ps.params.map(p => transformSymbol(p.sym)).collectApply(tuple(_)(k)) transformOption(cls.paramsOpt, stageParamList): paramsOpt => - assert(cls.companion.isEmpty) // does not support nested module + assert(cls.companion.isEmpty) // nested module not supported optionNone(): none => blockCtor("ClsLikeDefn", Ls(c, paramsOpt, none)): cls => blockCtor("Define", Ls(cls, p.code))(k) @@ -225,12 +233,6 @@ class InstrumentationImpl(using State): // transformations of Block - - def transformOption[A](xOpt: Opt[A], f: A => (Path => Block) => Block)(k: Path => Block): Block = - xOpt match - case S(x) => f(x)(optionSome(_)(k)) - case N => optionNone()(k) - def transformPath(p: Path)(using ctx: Context)(k: StagedPath => Block): Block = // rulePath ctx.get(p).map(k).getOrElse: @@ -241,7 +243,7 @@ class InstrumentationImpl(using State): case d: DynSelect => ruleDynSel(d)(k) case _ => ??? // not supported - def transformResult(r: Result)(using ctx: Context)(k: StagedPath => Block): Block = + def transformResult(r: Result)(using Context)(k: StagedPath => Block): Block = r match case p: Path => transformPath(p): p => @@ -251,7 +253,7 @@ class InstrumentationImpl(using State): case i: Instantiate => ruleInst(i)(k) case _ => ??? // not supported - def transformArg(a: Arg)(using ctx: Context)(k: StagedPath => Block): Block = + def transformArg(a: Arg)(using Context)(k: StagedPath => Block): Block = val Arg(spread, value) = a optionNone(): opt => transformPath(value): value => @@ -259,12 +261,12 @@ class InstrumentationImpl(using State): StagedPath.mk(value.shape, cde)(k) // provides list of shapes and list of codes to continuation - def transformArgs(args: Ls[Arg])(using ctx: Context)(k: Ls[StagedPath] => Block): Block = + def transformArgs(args: Ls[Arg])(using Context)(k: Ls[StagedPath] => Block): Block = args.map(transformArg).collectApply(k) // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function // so we pass modSym instead - def transformFunDefn(modSym: BlockMemberSymbol, f: FunDefn)(using ctx: Context): (FunDefn, Block) = + def transformFunDefn(modSym: BlockMemberSymbol, f: FunDefn)(using Context): (FunDefn, Block) = val genSym = BlockMemberSymbol(f.sym.nme + "_gen", Nil, true) // TODO: remove it. only for test // TODO: put correct parameters instead of Nil @@ -287,12 +289,12 @@ class InstrumentationImpl(using State): ruleEnd(): b => fnPrintCode(p)(_ => k(b, ctx)) - def transformBlock(b: Block)(using ctx: Context)(k: StagedPath => Block): Block = + def transformBlock(b: Block)(using Context)(k: StagedPath => Block): Block = transformBlock(b)((p, _) => k(p)) - def transformBlock(b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def transformBlock(b: Block)(using Context)(k: (StagedPath, Context) => Block): Block = // ruleBlk? - val k2 = k(_, ctx) + val k2 = k(_, summon) b match case r: Return => ruleReturn(r)(k) case a: Assign => ruleAssign(a)(k) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index f8ac2202df..4f4a2b3f23 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -105,7 +105,6 @@ object Printer: then doc"${mkDocument(qual)}.at(${mkDocument(fld)})" else doc"${mkDocument(qual)}[${mkDocument(fld)}]" case x: Value => mkDocument(x) - case _ => TODO(path) def mkDocument(result: Result)(using Raise, Scope): Document = result match case Call(fun, args) => doc"${mkDocument(fun)}(${args.map(mkDocument).mkDocument(", ")})" diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index a441b233e5..402fd2b51a 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -36,7 +36,7 @@ class Case with Lit(val lit: Literal) Cls(val cls: Symbol, val path: Path) Tup(val len: Int, val inf: Bool) // TODO: remove inf? - Wildcard + Wildcard() class Result with constructor From ed85e757b90ca19e48baca26d48017932fda6cef Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 21 Nov 2025 23:24:35 +0800 Subject: [PATCH 127/268] progress on rest of the rules removed Wildcard from Shape, as we already store the branch in dflt --- .../scala/hkmc2/codegen/Instrumentation.scala | 76 ++++++++++++++++++- .../src/test/mlscript-compile/Block.mls | 2 - 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 8be72c6638..ca6a97446a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -53,6 +53,17 @@ class InstrumentationImpl(using State): k(head :: tail) )(f) + // possible to wrangle to the form above, but unweildy to do so in practice + extension [A, B](ls: Ls[B => ((A, B) => Block) => Block]) + def collectApply(b: B)(f: (Ls[A], B) => Block): Block = + ls.foldRight((b: B) => (f: (Ls[A], B) => Block) => f(Nil, b))((headCont, tailCont) => + b => + k => + headCont(b): (head, b) => + tailCont(b): (tail, b) => + k(head :: tail, b) + )(b)(f) + // helpers corresponding to constructors def assign(res: Result, symName: Str = "tmp")(k: Path => Block): Assign = @@ -108,8 +119,12 @@ class InstrumentationImpl(using State): def fnPrintCode(p: Path)(k: Path => Block): Block = // discard result, we only care about side effect blockCall("printCode", Ls(p))(k) + def fnMrg(s1: Shape, s2: Shape)(k: Shape => Block): Block = + shapeCall("mrg", Ls(s1, s2))(s => k(Shape(s))) def fnSel(s1: Shape, s2: Shape)(k: Shape => Block): Block = shapeCall("sel", Ls(s1, s2))(s => k(Shape(s))) + def fnFilter(s1: Shape, s2: Path)(k: Shape => Block): Block = + shapeCall("filter", Ls(s1, s2))(s => k(Shape(s))) def fnUnion(s1: Shape, s2: Shape)(k: Shape => Block): Block = shapeCall("union", Ls(s1, s2))(s => k(Shape(s))) @@ -179,6 +194,16 @@ class InstrumentationImpl(using State): blockCtor("Return", Ls(x.code, toValue(false))): cde => StagedPath.mk(x.shape, cde, "return")(k(_, summon)) + def ruleMatch(m: Match)(using Context)(k: (StagedPath, Context) => Block): Block = + val Match(p, ks, dflt, rest) = m + transformPath(p): x => + ruleBranches(x, p, ks, dflt): (sp, scrut, arms, dflt, ctx1) => + transformBlock(rest)(using ctx1): (z, ctx2) => + fnMrg(sp, z.shape): sp => + transformOption(dflt, p => (_(p))): dflt => + blockCtor("Match", Ls(scrut, arms, dflt, z.code)): cde => + StagedPath.mk(sp, cde)(k(_, ctx2)) + def ruleAssign(a: Assign)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Assign(x, r, b) = a transformResult(r): y => @@ -214,10 +239,14 @@ class InstrumentationImpl(using State): StagedPath.mk(z.shape, cde, "_let")(k(_, summon)) def ruleEnd()(k: StagedPath => Block): Block = - shapeCtor("Dyn", Ls()): sp => + shapeCtor("Bot", Ls()): sp => blockCtor("End", Ls()): cde => StagedPath.mk(sp, cde, "end")(k) + def ruleBlk(b: Block)(using Context)(k: Path => Block): Block = + transformBlock(b): x => + k(x.code) + def ruleCls(cls: ClsLikeDefn, rest: Block)(using Context)(k: Path => Block): Block = (Define(cls, _)): transformBlock(rest): p => @@ -230,6 +259,44 @@ class InstrumentationImpl(using State): blockCtor("ClsLikeDefn", Ls(c, paramsOpt, none)): cls => blockCtor("Define", Ls(cls, p.code))(k) + // horrible abstraction boundary + def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block])(using + ctx: Context + )(k: (Shape, Path, Path, Opt[Path], Context) => Block): Block = + // TODO: do filtering + def f(arm: Case -> Block)(ctx: Context)(k: (StagedPath, Context) => Block): Block = + ruleBranch(x, p, arm._1, arm._2)(using ctx)(k) + + arms.map(f).collectApply(summon): (arms, ctx) => + shapeCtor("Dyn", Ls()): sp => // TODO + tuple(arms.map(_.code)): arms => + dflt match + case S(dflt) => + transformBlock(dflt)(using ctx): (dflt, ctx) => + k(sp, x.code, arms, S(dflt.code), ctx) + case N => k(sp, x.code, arms, N, ctx) + + def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + transformCase(cse): cse => + fnFilter(x.shape, cse): sp => + StagedPath.mk(sp, x.code): x0 => + // val bot = summon[State].shapeSymbol.asPath.selSN("Bot"). + // we want the ClassLikeSymbol for Shape.Bot +//│ _1 = Cls: +//│ cls = class:Bot +//│ path = Select{class:Bot}: +//│ qual = Select{member:Bot}: +//│ qual = Ref of member:Shape +//│ name = Ident of "Bot" +//│ name = Ident of "class" + val arm = Case.Cls(???, shapeMod("Bot").selSN("class")) -> ruleEnd()(k(_, ctx)) + (Match(x.shape.p, Ls(arm), N, _)): + given Context = ctx.clone() += p -> x0 + transformBlock(b): (y1, ctx) => + blockCtor("End", Ls()): end => + // TODO: use Arm type instead of Tup + blockCtor("Tup", Ls(cse, y1.code)): cde => + StagedPath.mk(y1.shape, cde)(k(_, ctx.clone() -= p)) // transformations of Block @@ -264,6 +331,13 @@ class InstrumentationImpl(using State): def transformArgs(args: Ls[Arg])(using Context)(k: Ls[StagedPath] => Block): Block = args.map(transformArg).collectApply(k) + def transformCase(cse: Case)(k: Path => Block): Block = + cse match + case Case.Lit(lit) => blockCtor("Lit", Ls(Value.Lit(lit)))(k) + case Case.Cls(cls, path) => blockCtor("Cls", Ls(cls, path))(k) + case Case.Tup(len, inf) => blockCtor("Tup", Ls(len, inf).map(toValue))(k) + case Case.Field(name, safe) => ??? // not supported + // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function // so we pass modSym instead def transformFunDefn(modSym: BlockMemberSymbol, f: FunDefn)(using Context): (FunDefn, Block) = diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 402fd2b51a..e0a0bb4cbc 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -36,7 +36,6 @@ class Case with Lit(val lit: Literal) Cls(val cls: Symbol, val path: Path) Tup(val len: Int, val inf: Bool) // TODO: remove inf? - Wildcard() class Result with constructor @@ -98,7 +97,6 @@ fun showCase(c: Case): Str = Lit(lit) then "Lit(" + showLiteral(lit) + ")" Cls(cls, path) then "Cls(" + showSymbol(cls) + ", " + showPath(path) + ")" Tup(len, inf) then "Tup(" + len + ", " + showBool(inf) + ")" - Wildcard then "Wildcard" fun showResult(r: Result): Str = if r is From 53a0aa46944ea5912693b9485c97f565ad1eed2b Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 22 Nov 2025 00:28:44 +0800 Subject: [PATCH 128/268] replace Block.Case with Pattern they aren't the same thing --- .../src/test/mlscript-compile/Shape.mls | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index a30235d03b..cc47cad408 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -12,6 +12,13 @@ class ShapeSet(val s: Shape) fun union(s1: ShapeSet, s2: ShapeSet) = ShapeSet(Dyn()) +class Pattern with + constructor + PLit(val lit: Literal) + Cls(val cls: Symbol) + Tup(val len: Int) + Wildcard() + class Shape with constructor Dyn() @@ -83,20 +90,20 @@ fun static(s: Shape) = type SLit = Lit open Block -fun silh(p: Case): Shape = if p is - Lit(l) then SLit(l) +fun silh(p: Pattern): Shape = if p is + PLit(l) then SLit(l) // where to store size of argument array? - Cls(sym, path) then Class(sym, ???) + Cls(sym) then Class(sym, ???) // how to initialize array of Dyn? - Tup(n, inf) then Arr(Array(n).fill(Dyn)) + Tup(n) then Arr(Array(n).fill(Dyn)) Wildcard then Dyn() -fun filter(s: Shape, p: Case): Shape = +fun filter(s: Shape, p: Pattern): Shape = if [s, p] is [_, Wildcard] then s - [Lit(l1), Lit(l2)] and l1 == l2 then s - [Lit(l), Cls(c, _)] and isPrimitiveTypeOf(c, l) then s - [Arr(ls), Tup(n, _)] and ls.length == n then s - [Class(c1, _), Cls(c2, _)] and c1 == c2 then s + [Lit(l1), PLit(l2)] and l1 == l2 then s + [Lit(l), Cls(c)] and isPrimitiveTypeOf(c, l) then s + [Arr(ls), Tup(n)] and ls.length == n then s + [Class(c1, _), Cls(c2)] and c1 == c2 then s [Dyn, _] then silh(p) else Dyn() // TODO From 3a992ad684fc11949ca6eb5795e34cec6dd0fdfb Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 22 Nov 2025 00:29:54 +0800 Subject: [PATCH 129/268] implement ShapeSet and ShapeMap --- .../src/test/mlscript-compile/Shape.mls | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index cc47cad408..a9fa467e17 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -4,12 +4,10 @@ import "./Block.mls" open Predef type Literal = null | undefined | Str | Int | Num | Bool +type Symbol = Block.Symbol module Shape with... -// TODO: implement ShapeSet -class ShapeSet(val s: Shape) - fun union(s1: ShapeSet, s2: ShapeSet) = ShapeSet(Dyn()) class Pattern with @@ -27,6 +25,26 @@ class Shape with Class(val sym: Symbol, val params: Array[[Symbol, Shape]]) Bot() // temp stub for ShapeSet +class ShapeSet(val m: Map) with + fun add(s: Shape) = m.set(hash(s), s) + fun contains(s: Shape) = m.get(hash(s)) != () + fun union(s: ShapeSet) = new Map([...m, ...s.m]) + fun isEmpty() = m.size == 0 + +class ShapeMap(val m: Map) with + fun add(s: ShapeSet, code: Block.Path) = m.set([...s.m.keys()].toSorted().join(", "), code) + // returns () if does not exist, change to Option? + fun get(s: ShapeSet) = m.get([...s.m.keys()].toSorted().join(", ")) + +fun show(s: Shape) = if s is + Dyn then "Dyn" + Lit(lit) then "Lit(" + Block.showLiteral(lit) + ")" + Arr(shapes) then "Arr(" + shapes.map(show).join(", ") + ")" + Class(sym, params) then "Class(" + sym.name + ", [" + params.map(p => p.0.name + ":" + show(p.1)).join(", ") + "])" + Bot() then "Bot()" + +fun hash(s: Shape) = show(s) + fun isPrimitiveType(sym: Str) = if sym is "Str" then true From 5840db4b67274ce664eb70ce8d666c9815542403 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 22 Nov 2025 12:17:38 +0800 Subject: [PATCH 130/268] fix equality checks for Symbol --- .../src/test/mlscript-compile/Shape.mls | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index a9fa467e17..5566ca2637 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -5,18 +5,10 @@ open Predef type Literal = null | undefined | Str | Int | Num | Bool type Symbol = Block.Symbol +type Shape = Shape.Shape module Shape with... -fun union(s1: ShapeSet, s2: ShapeSet) = ShapeSet(Dyn()) - -class Pattern with - constructor - PLit(val lit: Literal) - Cls(val cls: Symbol) - Tup(val len: Int) - Wildcard() - class Shape with constructor Dyn() @@ -54,7 +46,7 @@ fun isPrimitiveType(sym: Str) = else false fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = - if [sym, l] is + if [sym.name, l] is ["Str", l] and l is Str then true ["Int", i] and i is Int then true ["Num", n] and n is Num then true @@ -64,7 +56,6 @@ fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = fun zipMrg[A](a: Array[A], b: Array[A]): Array[A] = a.map((a, i, _) => mrg2(a, b.at(i))) -// TODO: look at how Array is used fun mrg2(s1: Shape, s2: Shape) = if s1 == s2 then s1 is @@ -72,7 +63,7 @@ fun mrg2(s1: Shape, s2: Shape) = if s1 and isPrimitiveTypeOf(sym, l) then Class(sym, shapes) Class(sym1, s1) and s2 is Class(sym2, s2) - and sym1 == sym2 + and sym1.name == sym2.name then Class(sym1, zipMrg(s1, s2)) Arr(s1) and s2 is Arr(s2) and s1.length == s2.length @@ -107,12 +98,22 @@ fun static(s: Shape) = type SLit = Lit open Block +type Pattern = Pattern.Pattern + +module Pattern with... + +class Pattern with + constructor + PLit(val lit: Literal) + Cls(val cls: Symbol, val n: Int) + Tup(val len: Int) + Wildcard() + fun silh(p: Pattern): Shape = if p is PLit(l) then SLit(l) // where to store size of argument array? - Cls(sym) then Class(sym, ???) - // how to initialize array of Dyn? + Cls(sym, n) then Class(sym, Array(n).fill(Dyn)) Tup(n) then Arr(Array(n).fill(Dyn)) Wildcard then Dyn() @@ -120,8 +121,8 @@ fun filter(s: Shape, p: Pattern): Shape = if [s, p] is [_, Wildcard] then s [Lit(l1), PLit(l2)] and l1 == l2 then s - [Lit(l), Cls(c)] and isPrimitiveTypeOf(c, l) then s + [Lit(l), Cls(c, _)] and isPrimitiveTypeOf(c, l) then s [Arr(ls), Tup(n)] and ls.length == n then s - [Class(c1, _), Cls(c2)] and c1 == c2 then s + [Class(c1, _), Cls(c2, _)] and c1.name == c2.name then s [Dyn, _] then silh(p) else Dyn() // TODO From bc2f62421aa1c1306c77346891ce2121d1d6ce8b Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 22 Nov 2025 12:21:04 +0800 Subject: [PATCH 131/268] implement Shape{Map, Set} use pretty printing for the key for now --- .../src/test/mlscript-compile/Shape.mls | 17 ++---------- .../src/test/mlscript-compile/ShapeMap.mls | 19 +++++++++++++ .../src/test/mlscript-compile/ShapeSet.mls | 27 +++++++++++++++++++ 3 files changed, 48 insertions(+), 15 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript-compile/ShapeMap.mls create mode 100644 hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index 5566ca2637..a6fe3d6f76 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -17,17 +17,6 @@ class Shape with Class(val sym: Symbol, val params: Array[[Symbol, Shape]]) Bot() // temp stub for ShapeSet -class ShapeSet(val m: Map) with - fun add(s: Shape) = m.set(hash(s), s) - fun contains(s: Shape) = m.get(hash(s)) != () - fun union(s: ShapeSet) = new Map([...m, ...s.m]) - fun isEmpty() = m.size == 0 - -class ShapeMap(val m: Map) with - fun add(s: ShapeSet, code: Block.Path) = m.set([...s.m.keys()].toSorted().join(", "), code) - // returns () if does not exist, change to Option? - fun get(s: ShapeSet) = m.get([...s.m.keys()].toSorted().join(", ")) - fun show(s: Shape) = if s is Dyn then "Dyn" Lit(lit) then "Lit(" + Block.showLiteral(lit) + ")" @@ -35,8 +24,6 @@ fun show(s: Shape) = if s is Class(sym, params) then "Class(" + sym.name + ", [" + params.map(p => p.0.name + ":" + show(p.1)).join(", ") + "])" Bot() then "Bot()" -fun hash(s: Shape) = show(s) - fun isPrimitiveType(sym: Str) = if sym is "Str" then true @@ -93,8 +80,8 @@ fun static(s: Shape) = if s is Dyn then false Lit(l) then not (l is Str and isPrimitiveType(l)) // redundant bracket? - Class(_, shapes) then shapes.every((s, _, _) => static(s)) - Arr(shapes) then shapes.every((s, _, _) => static(s)) + Class(_, shapes) then shapes.every(static) + Arr(shapes) then shapes.every(static) type SLit = Lit open Block diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeMap.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeMap.mls new file mode 100644 index 0000000000..32b4faf997 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeMap.mls @@ -0,0 +1,19 @@ +import "./Option.mls" +import "./ShapeSet.mls" + +open Option { Some, None } +open ShapeSet + +type ShapeMap = ShapeMap.ShapeMap + +module ShapeMap with... + +class ShapeMap(val underlying: Map) with + fun hash(s: ShapeSet) = s.keys().join(", ") + + fun add(s: ShapeSet, code) = underlying.set(hash(s), code) + + fun get(s: ShapeSet) = + if underlying.get(hash(s)) + == () then None + is value then Some of value diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls new file mode 100644 index 0000000000..91faab3df5 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -0,0 +1,27 @@ +import "./Shape.mls" + +open Shape { show } + +type ShapeSet = ShapeSet.ShapeSet + +module ShapeSet with... + +fun hash(s: Shape) = show(s) + +class ShapeSet(val underlying: Map) with + set this.(Symbol.iterator) = + () => underlying.(Symbol.iterator)() + + fun keys() = [...underlying.keys()].toSorted() + + fun isEmpty() = underlying.size == 0 + + fun add(s: Shape) = underlying.set(hash(s), s) + + fun contains(s: Shape) = underlying.has(hash(s)) + +fun create() = ShapeSet(new Map) + +fun union(s1: ShapeSet, s2: ShapeSet) = new Map([...s1, ...s2]) + +fun unionArray(arr: Array[ShapeSet]) = arr.reduce(union) From e2454b4f92e528186a00ae352cc1e204d7a3d483 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 22 Nov 2025 17:41:08 +0800 Subject: [PATCH 132/268] fill out ShapeSet functionailty --- .../src/test/mlscript-compile/Shape.mls | 36 +++++------ .../src/test/mlscript-compile/ShapeMap.mls | 4 +- .../src/test/mlscript-compile/ShapeSet.mls | 59 ++++++++++++++++--- 3 files changed, 71 insertions(+), 28 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index a6fe3d6f76..0627e601c4 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -60,21 +60,23 @@ fun mrg2(s1: Shape, s2: Shape) = if s1 fun mrg(s1: Array[Shape]) = s1.reduceRight((acc, s, _, _) => mrg2(s, acc)) -fun sel(s1: Shape, s2: Shape) = +fun sel(s1: Shape, s2: Shape): Array[Shape] = if [s1, s2] is [Class(c, shapes), Lit(n)] and n is Str - then shapes.at(n) // field name election using Str? + then if shapes.find(_.0.name == n) + == () then [] + is param then [param.1] [Dyn, Lit(n)] and n is Str - then Dyn() + then [Dyn()] [Arr(shapes), Lit(n)] and n is Int - then shapes.at(n) + then [shapes.(n)] [Arr(shapes), Dyn] then - Dyn() // TODO + shapes [Dyn, Lit(n)] and n is Int - then Dyn() + then [Dyn()] [Dyn, Dyn] - then Dyn() - else Dyn() // temp, makes call not error + then [Dyn()] + else [] // TODO: return no possibility instead of err? fun static(s: Shape) = if s is @@ -84,7 +86,6 @@ fun static(s: Shape) = Arr(shapes) then shapes.every(static) type SLit = Lit -open Block type Pattern = Pattern.Pattern module Pattern with... @@ -96,7 +97,6 @@ class Pattern with Tup(val len: Int) Wildcard() - fun silh(p: Pattern): Shape = if p is PLit(l) then SLit(l) // where to store size of argument array? @@ -104,12 +104,12 @@ fun silh(p: Pattern): Shape = if p is Tup(n) then Arr(Array(n).fill(Dyn)) Wildcard then Dyn() -fun filter(s: Shape, p: Pattern): Shape = +fun filter(s: Shape, p: Pattern): Array[Shape] = if [s, p] is - [_, Wildcard] then s - [Lit(l1), PLit(l2)] and l1 == l2 then s - [Lit(l), Cls(c, _)] and isPrimitiveTypeOf(c, l) then s - [Arr(ls), Tup(n)] and ls.length == n then s - [Class(c1, _), Cls(c2, _)] and c1.name == c2.name then s - [Dyn, _] then silh(p) - else Dyn() // TODO + [_, Wildcard] then [s] + [Lit(l1), PLit(l2)] and l1 == l2 then [s] + [Lit(l), Cls(c, _)] and isPrimitiveTypeOf(c, l) then [s] + [Arr(ls), Tup(n)] and ls.length == n then [s] + [Class(c1, _), Cls(c2, _)] and c1.name == c2.name then [s] + [Dyn, _] then [silh(p)] + else [] diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeMap.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeMap.mls index 32b4faf997..6b73d8f826 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeMap.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeMap.mls @@ -8,9 +8,9 @@ type ShapeMap = ShapeMap.ShapeMap module ShapeMap with... -class ShapeMap(val underlying: Map) with - fun hash(s: ShapeSet) = s.keys().join(", ") +fun hash(s: ShapeSet) = s.keys().join(", ") +class ShapeMap(val underlying: Map) with fun add(s: ShapeSet, code) = underlying.set(hash(s), code) fun get(s: ShapeSet) = diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls index 91faab3df5..4ef4c83d23 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -1,6 +1,10 @@ +import "./Predef.mls" import "./Shape.mls" +import "./Block.mls" -open Shape { show } +open Predef +open Shape { show, Pattern } +open Block { Symbol } type ShapeSet = ShapeSet.ShapeSet @@ -9,19 +13,58 @@ module ShapeSet with... fun hash(s: Shape) = show(s) class ShapeSet(val underlying: Map) with - set this.(Symbol.iterator) = - () => underlying.(Symbol.iterator)() - fun keys() = [...underlying.keys()].toSorted() + fun values() = underlying.values().toArray() + fun isEmpty() = underlying.size == 0 - fun add(s: Shape) = underlying.set(hash(s), s) - fun contains(s: Shape) = underlying.has(hash(s)) + fun flatMap(f) = liftMany(values().flatMap(f)) + + fun filter(p: Pattern) = flatMap(Pattern.filter(_, p)) + + fun sel(s: ShapeSet) = + prod(values(), s.values()) + .flatMap(pair => Shape.sel(pair.0, pair.1)) + |> liftMany + fun create() = ShapeSet(new Map) -fun union(s1: ShapeSet, s2: ShapeSet) = new Map([...s1, ...s2]) +fun lift(s: Shape) = ShapeSet(new Map([[hash(s), s]])) + +fun liftMany(arr: Array[Shape]) = ShapeSet(new Map(arr.map(s => [hash(s), s]))) + +// combining ShapeSet + +fun union(s1: ShapeSet, s2: ShapeSet) = new Map([...s1.underlying, ...s2.underlying]) + +fun flat(arr: Array[ShapeSet]) = arr.reduce(union) + +// Cartesian product: https://stackoverflow.com/a/43053803 +fun prod(a, b) = a.flatMap(d => b.map(e => [d, e].flat())) + +open Shape + +// lifted constructors + +fun mkBot() = create() + +fun mkDyn() = lift(Dyn()) + +fun mkLit(l) = lift(Lit(l)) + +fun mkArr(shapes: Array[ShapeSet]) = + shapes + .map(_.underlying.values().toArray()) + .reduce(prod) + .map(Arr) + |> liftMany -fun unionArray(arr: Array[ShapeSet]) = arr.reduce(union) +fun mkClass(sym: Symbol, params: Array[[Symbol, ShapeSet]]) = + params + .map(p => p.1.underlying.values().map(s => [[p.0, s]]).toArray()) + .reduce(prod) + .map(Class(sym, _)) + |> liftMany From 746cbd38e6c5f2adbd30edc40e87f1341d6497b0 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 00:54:57 +0800 Subject: [PATCH 133/268] link ShapeSet symbols for instrumentation --- hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala | 1 + hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala | 2 ++ hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala | 1 + 3 files changed, 4 insertions(+) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index d6e92ef237..21a6f7cd21 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -235,6 +235,7 @@ object Elaborator: val termSymbol = TempSymbol(N, "Term") val blockSymbol = TempSymbol(N, "Block") val shapeSymbol = TempSymbol(N, "Shape") + val shapeSetSymbol = TempSymbol(N, "ShapeSet") val optionSymbol = TempSymbol(N, "Option") val wasmSymbol = TempSymbol(N, "wasm") val effectSigSymbol = ClassSymbol(DummyTypeDef(syntax.Cls), Ident("EffectSig")) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala index e86d5994df..398bcaeeb8 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala @@ -35,6 +35,7 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: val blockNme = baseScp.allocateName(Elaborator.State.blockSymbol) val shapeNme = baseScp.allocateName(Elaborator.State.shapeSymbol) val optionNme = baseScp.allocateName(Elaborator.State.optionSymbol) + val shapeSetNme = baseScp.allocateName(Elaborator.State.shapeSetSymbol) val definitionMetadataNme = baseScp.allocateName(Elaborator.State.definitionMetadataSymbol) val prettyPrintNme = baseScp.allocateName(Elaborator.State.prettyPrintSymbol) @@ -64,6 +65,7 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: importRuntimeModule(blockNme, blockFile) importRuntimeModule(shapeNme, shapeFile) importRuntimeModule(optionNme, optionFile) + importRuntimeModule(shapeSetNme, shapeSetFile) h private var hostCreated = false diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index 5bbb459cd7..e4cd7543a1 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -23,6 +23,7 @@ abstract class MLsDiffMaker extends DiffMaker: val blockFile: os.Path = predefFile/os.up/"Block.mjs" // * Contains MLscript runtime block definitions val shapeFile: os.Path = predefFile/os.up/"Shape.mjs" // * Contains MLscript runtime shape definitions val optionFile: os.Path = predefFile/os.up/"Option.mjs" // * Contains MLscript runtime shape definitions + val shapeSetFile: os.Path = predefFile/os.up/"ShapeSet.mjs" // * Contains MLscript runtime shape definitions val wd = file / os.up From 9915656d871d857db70f4dd5e21e27a95ce29320 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 00:55:45 +0800 Subject: [PATCH 134/268] fix Shape, ShapeSet implementations --- .../src/test/mlscript-compile/Shape.mls | 17 +++++---- .../src/test/mlscript-compile/ShapeSet.mls | 35 ++++++++++++------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index 0627e601c4..de6be1fc18 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -46,12 +46,12 @@ fun zipMrg[A](a: Array[A], b: Array[A]): Array[A] = fun mrg2(s1: Shape, s2: Shape) = if s1 == s2 then s1 is - Lit(l) and s2 is Class(sym, shapes) + Lit(l) and s2 is Class(sym, params) and isPrimitiveTypeOf(sym, l) - then Class(sym, shapes) - Class(sym1, s1) and s2 is Class(sym2, s2) + then Class(sym, params) + Class(sym1, ps) and s2 is Class(sym2, s2) and sym1.name == sym2.name - then Class(sym1, zipMrg(s1, s2)) + then Class(sym1, ps.map(p => [p.0, zipMrg(p.1, s2)])) Arr(s1) and s2 is Arr(s2) and s1.length == s2.length then Arr(zipMrg(s1, s2)) @@ -62,8 +62,8 @@ fun mrg(s1: Array[Shape]) = fun sel(s1: Shape, s2: Shape): Array[Shape] = if [s1, s2] is - [Class(c, shapes), Lit(n)] and n is Str - then if shapes.find(_.0.name == n) + [Class(c, params), Lit(n)] and n is Str + then if params.find(_.0.name == n) == () then [] is param then [param.1] [Dyn, Lit(n)] and n is Str @@ -82,7 +82,7 @@ fun static(s: Shape) = if s is Dyn then false Lit(l) then not (l is Str and isPrimitiveType(l)) // redundant bracket? - Class(_, shapes) then shapes.every(static) + Class(_, params) then params.every(static(_.1)) Arr(shapes) then shapes.every(static) type SLit = Lit @@ -99,8 +99,7 @@ class Pattern with fun silh(p: Pattern): Shape = if p is PLit(l) then SLit(l) - // where to store size of argument array? - Cls(sym, n) then Class(sym, Array(n).fill(Dyn)) + Cls(sym, n) then Class(sym, Array(n).fill(["TODO", Dyn])) Tup(n) then Arr(Array(n).fill(Dyn)) Wildcard then Dyn() diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls index 4ef4c83d23..49ff84fddb 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -12,6 +12,8 @@ module ShapeSet with... fun hash(s: Shape) = show(s) +fun printShapeSet(s: ShapeSet) = console.log([... s.keys()].join(", ")) + class ShapeSet(val underlying: Map) with fun keys() = [...underlying.keys()].toSorted() @@ -23,13 +25,6 @@ class ShapeSet(val underlying: Map) with fun flatMap(f) = liftMany(values().flatMap(f)) - fun filter(p: Pattern) = flatMap(Pattern.filter(_, p)) - - fun sel(s: ShapeSet) = - prod(values(), s.values()) - .flatMap(pair => Shape.sel(pair.0, pair.1)) - |> liftMany - fun create() = ShapeSet(new Map) fun lift(s: Shape) = ShapeSet(new Map([[hash(s), s]])) @@ -43,9 +38,13 @@ fun union(s1: ShapeSet, s2: ShapeSet) = new Map([...s1.underlying, ...s2.underly fun flat(arr: Array[ShapeSet]) = arr.reduce(union) // Cartesian product: https://stackoverflow.com/a/43053803 -fun prod(a, b) = a.flatMap(d => b.map(e => [d, e].flat())) +fun prod(xs) = + if xs.length == + 0 then [[]] + 1 then xs + else xs.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat()))) -open Shape +open Shape { Dyn, Lit, Arr, Class } // lifted constructors @@ -58,13 +57,25 @@ fun mkLit(l) = lift(Lit(l)) fun mkArr(shapes: Array[ShapeSet]) = shapes .map(_.underlying.values().toArray()) - .reduce(prod) - .map(Arr) + |> prod + .map(x => Arr(x)) |> liftMany fun mkClass(sym: Symbol, params: Array[[Symbol, ShapeSet]]) = params .map(p => p.1.underlying.values().map(s => [[p.0, s]]).toArray()) - .reduce(prod) + |> prod .map(Class(sym, _)) |> liftMany + +// helper functions + +fun filter(s: ShapeSet, p: Pattern) = s.flatMap(Pattern.filter(_, p)) + +fun sel(s1: ShapeSet, s2: ShapeSet) = + prod([s1.values(), s2.values()]) + .flatMap(pair => Shape.sel(pair.0, pair.1)) + |> liftMany + +fun mrg(s1: ShapeSet, s2: ShapeSet) = + mkDyn() // TODO From 49302529efdb5842007823c84d8f6c9688e22633 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 01:04:15 +0800 Subject: [PATCH 135/268] remove TrivialResult this helps avoid applying TrivialResult multiple times when retrieving a path from the Context --- .../scala/hkmc2/codegen/Instrumentation.scala | 10 +++------- .../src/test/mlscript-compile/Block.mls | 19 ++++++++----------- .../src/test/mlscript/staging/PrintCode.mls | 2 +- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index ca6a97446a..f9489baa7c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -234,9 +234,8 @@ class InstrumentationImpl(using State): given Context = ctx.clone() += x.asPath -> y transformBlock(b): (z, ctx) => blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => - blockCtor("TrivialResult", Ls(undefined)): undefined => - blockCtor("Assign", Ls(xSym, undefined, z.code)): cde => - StagedPath.mk(z.shape, cde, "_let")(k(_, summon)) + blockCtor("Assign", Ls(xSym, undefined, z.code)): cde => + StagedPath.mk(z.shape, cde, "_let")(k(_, summon)) def ruleEnd()(k: StagedPath => Block): Block = shapeCtor("Bot", Ls()): sp => @@ -312,10 +311,7 @@ class InstrumentationImpl(using State): def transformResult(r: Result)(using Context)(k: StagedPath => Block): Block = r match - case p: Path => - transformPath(p): p => - blockCtor("TrivialResult", Ls(p.code)): cde => - StagedPath.mk(p.shape, cde)(k) + case p: Path => transformPath(p)(k) case t: Tuple => ruleTup(t)(k) case i: Instantiate => ruleInst(i)(k) case _ => ??? // not supported diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index e0a0bb4cbc..60ce3c3db8 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -23,14 +23,6 @@ type ParamList = Array[Symbol] class Arg(val spread: Opt[Bool], val value: Path) -class Path with - constructor - Select(val qual: Path, val name: Ident) - DynSelect(val qual: Path, val fld: Path, val arrayIdx: Bool) - ValueRef(val l: Symbol) - ValueLit(val lit: Literal) - -// Match pattern for staged code class Case with constructor Lit(val lit: Literal) @@ -39,12 +31,17 @@ class Case with class Result with constructor - // unused? - TrivialResult(val path: Path) // only Path extends TrivialResult Call(val _fun: Path, val args: Array[Arg]) Instantiate(val cls: Path, val args: Array[Arg]) // assume immutable Tuple(val elems: Array[Arg]) // assume immutable +class Path extends Result with + constructor + Select(val qual: Path, val name: Ident) + DynSelect(val qual: Path, val fld: Path, val arrayIdx: Bool) // is arrayIdx used? + ValueRef(val l: Symbol) + ValueLit(val lit: Literal) + class Defn with constructor ValDefn(val sym: Symbol, val rhs: Path) @@ -100,7 +97,7 @@ fun showCase(c: Case): Str = fun showResult(r: Result): Str = if r is - TrivialResult(path) then showPath(path) + Path then showPath(r) Call(f, args) then "Call(" + showPath(f) + ", " + showArgs(args) + ")" Instantiate(cls, args) then "Instantiate(" + showPath(cls) + ", " + showArgs(args) + ")" Tuple(elems) then "Tuple(" + showArgs(elems) + ")" diff --git a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls index 0314c3488d..18be09c9c7 100644 --- a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls +++ b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls @@ -41,6 +41,6 @@ //│ Bot: fun Bot { class: class Bot } //│ } -Block.printCode(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x")], Block.Return(Block.TrivialResult(Block.ValueLit(1)), false))) +Block.printCode(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x")], Block.Return(Block.ValueLit(1), false))) //│ > FunDefn(Symbol("f"), [Symbol("x")], Return(Lit(1), false)) From b3c707f4b6e26c7484696725cfa0bb0df65bab28 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 10:42:14 +0800 Subject: [PATCH 136/268] replace Shape with ShapeSet during instrumentation --- .../scala/hkmc2/codegen/Instrumentation.scala | 176 ++++++++++-------- .../scala/hkmc2/semantics/Elaborator.scala | 1 - .../src/test/mlscript-compile/Shape.mls | 31 --- .../src/test/mlscript-compile/ShapeSet.mls | 35 +++- .../test/scala/hkmc2/JSBackendDiffMaker.scala | 2 - .../src/test/scala/hkmc2/MLsDiffMaker.scala | 7 +- 6 files changed, 136 insertions(+), 116 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index f9489baa7c..2b7c9df40c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -17,14 +17,14 @@ import syntax.{Literal, Tree} // but it doesn't accept the current context, so applications seem limited class InstrumentationImpl(using State): - type ArgWrappable = Path | Symbol | Shape + type ArgWrappable = Path | Symbol | ShapeSet type Context = HashMap[Path, StagedPath] def asArg(x: ArgWrappable): Arg = x match case p: Path => p.asArg case l: Symbol => l.asPath.asArg - case Shape(p) => p.asArg + case ShapeSet(p) => p.asArg // null and undefined are missing def toValue(lit: Str | Int | BigDecimal | Bool): Value = @@ -84,13 +84,14 @@ class InstrumentationImpl(using State): // helper for staging the constructors def blockMod(name: Str) = summon[State].blockSymbol.asPath.selSN(name) - def shapeMod(name: Str) = summon[State].shapeSymbol.asPath.selSN(name) def optionMod(name: Str) = summon[State].optionSymbol.asPath.selSN(name) + def patternMod(name: Str) = summon[State].shapeSetSymbol.asPath.selSN("Pattern").selSN(name) + def shapeSetMod(name: Str) = summon[State].shapeSetSymbol.asPath.selSN(name) def blockCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = ctor(blockMod(name), args, symName)(k) - def shapeCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Shape => Block): Block = - ctor(shapeMod(name), args, symName)(p => k(Shape(p))) + def patternCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = + ctor(patternMod(name), args, symName)(k) def optionSome(arg: ArgWrappable, symName: Str = "tmp")(k: Path => Block): Block = ctor(optionMod("Some"), Ls(arg), symName)(k) def optionNone(symName: Str = "tmp")(k: Path => Block): Block = @@ -98,35 +99,55 @@ class InstrumentationImpl(using State): def blockCall(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = call(blockMod(name), args, symName = symName)(k) - def shapeCall(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = - call(shapeMod(name), args, symName = symName)(k) + def shapeSetCall(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = + call(shapeSetMod(name), args, symName = symName)(k) // helpers to create and access the components of a staged value - case class Shape(p: Path) + case class ShapeSet(p: Path) - // A StagedPath is a path that points to a (shape, code) tuple + // A StagedPath is a path that points to a (ShapeSet, code) tuple case class StagedPath(p: Path): - def shape: Shape = Shape(DynSelect(p, toValue(0), false)) + def shapes: ShapeSet = ShapeSet(DynSelect(p, toValue(0), false)) def code: Path = DynSelect(p, toValue(1), false) def end: Block = Return(p, false) object StagedPath: - def mk(shape: Shape, code: Path, symName: Str = "tmp")(k: StagedPath => Block): Block = - tuple(Ls(shape.p, code), symName)(p => k(StagedPath(p))) + def mk(shapeSet: ShapeSet, code: Path, symName: Str = "tmp")(k: StagedPath => Block): Block = + tuple(Ls(shapeSet.p, code), symName)(p => k(StagedPath(p))) // linking functions defined in MLscipt def fnPrintCode(p: Path)(k: Path => Block): Block = // discard result, we only care about side effect blockCall("printCode", Ls(p))(k) - def fnMrg(s1: Shape, s2: Shape)(k: Shape => Block): Block = - shapeCall("mrg", Ls(s1, s2))(s => k(Shape(s))) - def fnSel(s1: Shape, s2: Shape)(k: Shape => Block): Block = - shapeCall("sel", Ls(s1, s2))(s => k(Shape(s))) - def fnFilter(s1: Shape, s2: Path)(k: Shape => Block): Block = - shapeCall("filter", Ls(s1, s2))(s => k(Shape(s))) - def fnUnion(s1: Shape, s2: Shape)(k: Shape => Block): Block = - shapeCall("union", Ls(s1, s2))(s => k(Shape(s))) + + def shapeBot()(k: ShapeSet => Block): Block = + shapeSetCall("mkBot", Ls())(s => k(ShapeSet(s))) + def shapeDyn()(k: ShapeSet => Block): Block = + shapeSetCall("mkDyn", Ls())(s => k(ShapeSet(s))) + def shapeLit(p: Path)(k: ShapeSet => Block): Block = + shapeSetCall("mkLit", Ls(p))(s => k(ShapeSet(s))) + def shapeArr(ps: Ls[ShapeSet])(k: ShapeSet => Block): Block = + tuple(ps, "test"): tup => + shapeSetCall("mkArr", Ls(tup))(s => k(ShapeSet(s))) + def shapeClass(cls: Path, params: Ls[(Symbol, ShapeSet)])(k: ShapeSet => Block): Block = + params.map((n, s) => + (k: Path => Block) => + transformSymbol(n): n => + tuple(Ls(n, s)): tup => + k(tup) + ).collectApply: ls => + tuple(ls): params => + shapeSetCall("mkClass", Ls(cls, params))(s => k(ShapeSet(s))) + + def fnMrg(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = + shapeSetCall("mrg", Ls(s1, s2))(s => k(ShapeSet(s))) + def fnSel(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = + shapeSetCall("sel", Ls(s1, s2))(s => k(ShapeSet(s))) + def fnFilter(s1: ShapeSet, s2: Path)(k: ShapeSet => Block): Block = + shapeSetCall("filter", Ls(s1, s2))(s => k(ShapeSet(s))) + def fnUnion(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = + shapeSetCall("union", Ls(s1, s2))(s => k(ShapeSet(s))) // transformation helpers @@ -140,31 +161,31 @@ class InstrumentationImpl(using State): // instrumentation rules def ruleLit(l: Value.Lit)(k: StagedPath => Block): Block = - shapeCtor("Lit", Ls(l)): sp => + shapeLit(l): sp => blockCtor("ValueLit", Ls(l)): cde => StagedPath.mk(sp, cde, "lit")(k) - // outdated + // not in formalization def ruleVar(r: Value.Ref)(k: StagedPath => Block): Block = blockCtor("Symbol", Ls(toValue(r.l.nme))): sym => blockCtor("ValueRef", Ls(sym)): cde => - shapeCtor("Dyn", Ls()): sp => // keep dynamic for now + // variable defined outside of scope, may be a reference to a class + shapeDyn(): sp => StagedPath.mk(sp, cde, "var")(k) def ruleTup(t: Tuple)(using Context)(k: StagedPath => Block): Block = assert(!t.mut) transformArgs(t.elems): xs => - tuple(xs.map(_.shape)): shapes => - shapeCtor("Arr", Ls(shapes)): sp => - tuple(xs.map(_.code)): codes => - blockCtor("Tuple", Ls(codes)): cde => - StagedPath.mk(sp, cde, "tup")(k) + shapeArr(xs.map(_.shapes)): sp => + tuple(xs.map(_.code)): codes => + blockCtor("Tuple", Ls(codes)): cde => + StagedPath.mk(sp, cde, "tup")(k) def ruleSel(s: Select)(using Context)(k: StagedPath => Block): Block = val Select(p, i @ Tree.Ident(name)) = s transformPath(p): x => - shapeCtor("Lit", Ls(toValue(name))): n => - fnSel(x.shape, n): sp => + shapeLit(toValue(name)): n => + fnSel(x.shapes, n): sp => blockCtor("Symbol", Ls(toValue(name))): name => blockCtor("Select", Ls(x.code, name)): cde => StagedPath.mk(sp, cde, "sel")(k) @@ -173,7 +194,7 @@ class InstrumentationImpl(using State): val DynSelect(qual, fld, arrayIdx) = d transformPath(qual): x => transformPath(fld): y => - fnSel(x.shape, y.shape): sp => + fnSel(x.shapes, y.shapes): sp => blockCtor("DynSelect", Ls(x.code, y.code, toValue(arrayIdx))): cde => StagedPath.mk(sp, cde, "dynsel")(k) @@ -181,25 +202,32 @@ class InstrumentationImpl(using State): val Instantiate(mut, cls, args) = i assert(!mut) transformArgs(args): xs => - tuple(xs.map(_.shape)): shapes => - tuple(xs.map(_.code)): codes => - // reuse instrumentation logic, shape of cls is discarded - transformPath(cls): cls => - shapeCtor("Class", Ls(cls.code, shapes)): sp => - blockCtor("Instantiate", Ls(cls.code, codes)): cde => - StagedPath.mk(sp, cde, "inst")(k) + tuple(xs.map(_.shapes)): shapes => + // reuse instrumentation logic, shape of cls is discarded + // possible to skip this? this triggers unnecessary "out of context" Dyn shape thing + val sym = cls match + case Select(Value.Ref(l), _) => l + case _ => ??? + transformSymbol(sym): sym => + // TODO: add back class names + val fieldName = new TempSymbol(N, "TODO") + shapeClass(sym, xs.map(x => (fieldName, x.shapes))): sp => + transformPath(cls): cls => + tuple(xs.map(_.code)): codes => + blockCtor("Instantiate", Ls(cls.code, codes)): cde => + StagedPath.mk(sp, cde, "inst")(k) def ruleReturn(r: Return)(using Context)(k: (StagedPath, Context) => Block): Block = transformResult(r.res): x => blockCtor("Return", Ls(x.code, toValue(false))): cde => - StagedPath.mk(x.shape, cde, "return")(k(_, summon)) + StagedPath.mk(x.shapes, cde, "return")(k(_, summon)) def ruleMatch(m: Match)(using Context)(k: (StagedPath, Context) => Block): Block = val Match(p, ks, dflt, rest) = m transformPath(p): x => ruleBranches(x, p, ks, dflt): (sp, scrut, arms, dflt, ctx1) => transformBlock(rest)(using ctx1): (z, ctx2) => - fnMrg(sp, z.shape): sp => + fnMrg(sp, z.shapes): sp => transformOption(dflt, p => (_(p))): dflt => blockCtor("Match", Ls(scrut, arms, dflt, z.code)): cde => StagedPath.mk(sp, cde)(k(_, ctx2)) @@ -208,26 +236,29 @@ class InstrumentationImpl(using State): val Assign(x, r, b) = a transformResult(r): y => transformSymbol(x): xSym => - // if ctx contains x, x was defined earlier - // otherwise, x is defined here - ctx.get(x.asPath) match - case S(x1) => - fnUnion(y.shape, x1.shape): sp => - blockCtor("ValueRef", Ls(xSym)): xStaged => + blockCtor("ValueRef", Ls(xSym)): xStaged => + // if ctx contains x, x was defined earlier + // otherwise, x is defined here + ctx.get(x.asPath) match + case S(x1) => + fnUnion(y.shapes, x1.shapes): sp => StagedPath.mk(sp, xStaged): x2 => - given Context = ctx.clone() += x.asPath -> x2 (Assign(x, x2.p, _)): + given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => - StagedPath.mk(z.shape, cde, "assign")(k(_, summon)) - case N => - (Assign(x, y.p, _)): - transformBlock(b): z => // ignore ctx - blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => - StagedPath.mk(z.shape, cde, "assign")(k(_, summon)) + StagedPath.mk(z.shapes, cde, "assign")(k(_, ctx)) + case N => + StagedPath.mk(y.shapes, xStaged): x2 => + // propagate shape information for future references to x + (Assign(x, y.p, _)): + given Context = ctx.clone() += x.asPath -> x2 + transformBlock(b): (z, ctx) => + blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => + StagedPath.mk(z.shapes, cde, "assign")(k(_, ctx)) def ruleLet(x: BlockMemberSymbol, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = - shapeCtor("Bot", Ls()): bot => + shapeBot(): bot => transformSymbol(x): xSym => StagedPath.mk(bot, xSym): y => (Assign(x, y.p, _)): @@ -235,10 +266,10 @@ class InstrumentationImpl(using State): transformBlock(b): (z, ctx) => blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => blockCtor("Assign", Ls(xSym, undefined, z.code)): cde => - StagedPath.mk(z.shape, cde, "_let")(k(_, summon)) + StagedPath.mk(z.shapes, cde, "_let")(k(_, summon)) def ruleEnd()(k: StagedPath => Block): Block = - shapeCtor("Bot", Ls()): sp => + shapeBot(): sp => blockCtor("End", Ls()): cde => StagedPath.mk(sp, cde, "end")(k) @@ -261,13 +292,13 @@ class InstrumentationImpl(using State): // horrible abstraction boundary def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block])(using ctx: Context - )(k: (Shape, Path, Path, Opt[Path], Context) => Block): Block = + )(k: (ShapeSet, Path, Path, Opt[Path], Context) => Block): Block = // TODO: do filtering def f(arm: Case -> Block)(ctx: Context)(k: (StagedPath, Context) => Block): Block = ruleBranch(x, p, arm._1, arm._2)(using ctx)(k) arms.map(f).collectApply(summon): (arms, ctx) => - shapeCtor("Dyn", Ls()): sp => // TODO + shapeDyn(): sp => // TODO tuple(arms.map(_.code)): arms => dflt match case S(dflt) => @@ -277,25 +308,16 @@ class InstrumentationImpl(using State): def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = transformCase(cse): cse => - fnFilter(x.shape, cse): sp => + fnFilter(x.shapes, cse): sp => StagedPath.mk(sp, x.code): x0 => - // val bot = summon[State].shapeSymbol.asPath.selSN("Bot"). - // we want the ClassLikeSymbol for Shape.Bot -//│ _1 = Cls: -//│ cls = class:Bot -//│ path = Select{class:Bot}: -//│ qual = Select{member:Bot}: -//│ qual = Ref of member:Shape -//│ name = Ident of "Bot" -//│ name = Ident of "class" - val arm = Case.Cls(???, shapeMod("Bot").selSN("class")) -> ruleEnd()(k(_, ctx)) - (Match(x.shape.p, Ls(arm), N, _)): + val arm = Case.Lit(Tree.BoolLit(true)) -> ruleEnd()(k(_, ctx)) + (Match(x0.shapes.p.selSN("isEmpty"), Ls(arm), N, _)): given Context = ctx.clone() += p -> x0 transformBlock(b): (y1, ctx) => blockCtor("End", Ls()): end => // TODO: use Arm type instead of Tup blockCtor("Tup", Ls(cse, y1.code)): cde => - StagedPath.mk(y1.shape, cde)(k(_, ctx.clone() -= p)) + StagedPath.mk(y1.shapes, cde)(k(_, ctx.clone() -= p)) // transformations of Block @@ -321,7 +343,7 @@ class InstrumentationImpl(using State): optionNone(): opt => transformPath(value): value => blockCtor("Arg", Ls(opt, value.code)): cde => - StagedPath.mk(value.shape, cde)(k) + StagedPath.mk(value.shapes, cde)(k) // provides list of shapes and list of codes to continuation def transformArgs(args: Ls[Arg])(using Context)(k: Ls[StagedPath] => Block): Block = @@ -329,9 +351,13 @@ class InstrumentationImpl(using State): def transformCase(cse: Case)(k: Path => Block): Block = cse match - case Case.Lit(lit) => blockCtor("Lit", Ls(Value.Lit(lit)))(k) - case Case.Cls(cls, path) => blockCtor("Cls", Ls(cls, path))(k) - case Case.Tup(len, inf) => blockCtor("Tup", Ls(len, inf).map(toValue))(k) + case Case.Lit(lit) => patternCtor("Lit", Ls(Value.Lit(lit)))(k) + // wrong 2nd argument + case Case.Cls(cls, path) => + // TODO: retrieve argument names from symbol? + transformSymbol(cls): cls => + patternCtor("Cls", Ls(cls, toValue(0)))(k) + case Case.Tup(len, inf) => patternCtor("Tup", Ls(len, inf).map(toValue))(k) case Case.Field(name, safe) => ??? // not supported // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index 21a6f7cd21..331e127ada 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -234,7 +234,6 @@ object Elaborator: val prettyPrintSymbol = TempSymbol(N, "prettyPrint") val termSymbol = TempSymbol(N, "Term") val blockSymbol = TempSymbol(N, "Block") - val shapeSymbol = TempSymbol(N, "Shape") val shapeSetSymbol = TempSymbol(N, "ShapeSet") val optionSymbol = TempSymbol(N, "Option") val wasmSymbol = TempSymbol(N, "wasm") diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index de6be1fc18..92634c2375 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -1,8 +1,5 @@ -import "./Predef.mls" import "./Block.mls" -open Predef - type Literal = null | undefined | Str | Int | Num | Bool type Symbol = Block.Symbol type Shape = Shape.Shape @@ -84,31 +81,3 @@ fun static(s: Shape) = Lit(l) then not (l is Str and isPrimitiveType(l)) // redundant bracket? Class(_, params) then params.every(static(_.1)) Arr(shapes) then shapes.every(static) - -type SLit = Lit -type Pattern = Pattern.Pattern - -module Pattern with... - -class Pattern with - constructor - PLit(val lit: Literal) - Cls(val cls: Symbol, val n: Int) - Tup(val len: Int) - Wildcard() - -fun silh(p: Pattern): Shape = if p is - PLit(l) then SLit(l) - Cls(sym, n) then Class(sym, Array(n).fill(["TODO", Dyn])) - Tup(n) then Arr(Array(n).fill(Dyn)) - Wildcard then Dyn() - -fun filter(s: Shape, p: Pattern): Array[Shape] = - if [s, p] is - [_, Wildcard] then [s] - [Lit(l1), PLit(l2)] and l1 == l2 then [s] - [Lit(l), Cls(c, _)] and isPrimitiveTypeOf(c, l) then [s] - [Arr(ls), Tup(n)] and ls.length == n then [s] - [Class(c1, _), Cls(c2, _)] and c1.name == c2.name then [s] - [Dyn, _] then [silh(p)] - else [] diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls index 49ff84fddb..fb98fec616 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -1,10 +1,10 @@ import "./Predef.mls" -import "./Shape.mls" import "./Block.mls" +import "./Shape.mls" open Predef -open Shape { show, Pattern } open Block { Symbol } +open Shape { show } type ShapeSet = ShapeSet.ShapeSet @@ -70,7 +70,7 @@ fun mkClass(sym: Symbol, params: Array[[Symbol, ShapeSet]]) = // helper functions -fun filter(s: ShapeSet, p: Pattern) = s.flatMap(Pattern.filter(_, p)) +fun filter(s: ShapeSet, p: Pattern.Pattern) = s.flatMap(Pattern.filter(_, p)) fun sel(s1: ShapeSet, s2: ShapeSet) = prod([s1.values(), s2.values()]) @@ -79,3 +79,32 @@ fun sel(s1: ShapeSet, s2: ShapeSet) = fun mrg(s1: ShapeSet, s2: ShapeSet) = mkDyn() // TODO + +open Block { Literal } +open Shape { isPrimitiveTypeOf } + +module Pattern with... + +class Pattern with + constructor + PLit(val lit: Literal) + Cls(val cls: Symbol, val n: Int) + Tup(val len: Int) + Wildcard() + +fun silh(p: Pattern): Shape = if p is + PLit(l) then Lit(l) + Cls(sym, n) then Class(sym, Array(n).fill(["TODO", Dyn])) + Tup(n) then Arr(Array(n).fill(Dyn)) + Wildcard then Dyn() + +fun filter(s: Shape, p: Pattern): Array[Shape] = + if [s, p] is + [_, Wildcard] then [s] + [Lit(l1), PLit(l2)] and l1 == l2 then [s] + [Lit(l), Cls(c, _)] and isPrimitiveTypeOf(c, l) then [s] + [Arr(ls), Tup(n)] and ls.length == n then [s] + [Class(c1, _), Cls(c2, _)] and c1.name == c2.name then [s] + [Dyn, _] then [silh(p)] + else [] + diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala index 398bcaeeb8..6c83efc5f5 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala @@ -33,7 +33,6 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: val runtimeNme = baseScp.allocateName(Elaborator.State.runtimeSymbol) val termNme = baseScp.allocateName(Elaborator.State.termSymbol) val blockNme = baseScp.allocateName(Elaborator.State.blockSymbol) - val shapeNme = baseScp.allocateName(Elaborator.State.shapeSymbol) val optionNme = baseScp.allocateName(Elaborator.State.optionSymbol) val shapeSetNme = baseScp.allocateName(Elaborator.State.shapeSetSymbol) val definitionMetadataNme = baseScp.allocateName(Elaborator.State.definitionMetadataSymbol) @@ -63,7 +62,6 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: if importQQ.isSet then importRuntimeModule(termNme, termFile) if stageCode.isSet then importRuntimeModule(blockNme, blockFile) - importRuntimeModule(shapeNme, shapeFile) importRuntimeModule(optionNme, optionFile) importRuntimeModule(shapeSetNme, shapeSetFile) h diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index e4cd7543a1..ff26bd1423 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -21,9 +21,8 @@ abstract class MLsDiffMaker extends DiffMaker: val runtimeFile: os.Path = predefFile/os.up/"Runtime.mjs" // * Contains MLscript runtime definitions val termFile: os.Path = predefFile/os.up/"Term.mjs" // * Contains MLscript runtime term definitions val blockFile: os.Path = predefFile/os.up/"Block.mjs" // * Contains MLscript runtime block definitions - val shapeFile: os.Path = predefFile/os.up/"Shape.mjs" // * Contains MLscript runtime shape definitions - val optionFile: os.Path = predefFile/os.up/"Option.mjs" // * Contains MLscript runtime shape definitions - val shapeSetFile: os.Path = predefFile/os.up/"ShapeSet.mjs" // * Contains MLscript runtime shape definitions + val optionFile: os.Path = predefFile/os.up/"Option.mjs" // * Contains MLscipt runtime option definition + val shapeSetFile: os.Path = predefFile/os.up/"ShapeSet.mjs" // * Contains MLscript runtime shapeset definitions val wd = file / os.up @@ -166,7 +165,7 @@ abstract class MLsDiffMaker extends DiffMaker: given Config = mkConfig processTrees( PrefixApp(Keywrd(`import`), StrLit(blockFile.toString)) - :: PrefixApp(Keywrd(`import`), StrLit(shapeFile.toString)) + :: PrefixApp(Keywrd(`import`), StrLit(shapeSetFile.toString)) :: Nil) super.init() From e76c1fd8c486e16ecb6eee1e11e6eccb04db5f54 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 11:13:43 +0800 Subject: [PATCH 137/268] add message to assertions --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 2b7c9df40c..6ffeddf32b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -174,7 +174,7 @@ class InstrumentationImpl(using State): StagedPath.mk(sp, cde, "var")(k) def ruleTup(t: Tuple)(using Context)(k: StagedPath => Block): Block = - assert(!t.mut) + assert(!t.mut, "mutable tuple not supported") transformArgs(t.elems): xs => shapeArr(xs.map(_.shapes)): sp => tuple(xs.map(_.code)): codes => @@ -200,7 +200,7 @@ class InstrumentationImpl(using State): def ruleInst(i: Instantiate)(using Context)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i - assert(!mut) + assert(!mut, "mutable instantiation not supported") transformArgs(args): xs => tuple(xs.map(_.shapes)): shapes => // reuse instrumentation logic, shape of cls is discarded @@ -284,7 +284,7 @@ class InstrumentationImpl(using State): def stageParamList(ps: ParamList)(k: Path => Block) = ps.params.map(p => transformSymbol(p.sym)).collectApply(tuple(_)(k)) transformOption(cls.paramsOpt, stageParamList): paramsOpt => - assert(cls.companion.isEmpty) // nested module not supported + assert(cls.companion.isEmpty, "nested module not supported") optionNone(): none => blockCtor("ClsLikeDefn", Ls(c, paramsOpt, none)): cls => blockCtor("Define", Ls(cls, p.code))(k) From d7925537baec64774a9a6168ebb1e1b804e81d11 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 11:18:11 +0800 Subject: [PATCH 138/268] refactor match rules --- .../scala/hkmc2/codegen/Instrumentation.scala | 54 ++++++++++--------- .../src/test/mlscript-compile/Block.mls | 7 +++ 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 6ffeddf32b..b05b45b504 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -119,7 +119,8 @@ class InstrumentationImpl(using State): def fnPrintCode(p: Path)(k: Path => Block): Block = // discard result, we only care about side effect - blockCall("printCode", Ls(p))(k) + def fnConcat(p1: Path, p2: Path)(k: Path => Block): Block = + blockCall("concat", Ls(p1, p2))(k) def shapeBot()(k: ShapeSet => Block): Block = shapeSetCall("mkBot", Ls())(s => k(ShapeSet(s))) @@ -225,12 +226,11 @@ class InstrumentationImpl(using State): def ruleMatch(m: Match)(using Context)(k: (StagedPath, Context) => Block): Block = val Match(p, ks, dflt, rest) = m transformPath(p): x => - ruleBranches(x, p, ks, dflt): (sp, scrut, arms, dflt, ctx1) => + ruleBranches(x, p, ks, dflt): (stagedMatch, ctx1) => transformBlock(rest)(using ctx1): (z, ctx2) => - fnMrg(sp, z.shapes): sp => - transformOption(dflt, p => (_(p))): dflt => - blockCtor("Match", Ls(scrut, arms, dflt, z.code)): cde => - StagedPath.mk(sp, cde)(k(_, ctx2)) + fnMrg(stagedMatch.shapes, z.shapes): sp => + fnConcat(stagedMatch.code, z.code): cde => + StagedPath.mk(sp, cde)(k(_, ctx2)) def ruleAssign(a: Assign)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Assign(x, r, b) = a @@ -289,35 +289,37 @@ class InstrumentationImpl(using State): blockCtor("ClsLikeDefn", Ls(c, paramsOpt, none)): cls => blockCtor("Define", Ls(cls, p.code))(k) - // horrible abstraction boundary def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block])(using - ctx: Context - )(k: (ShapeSet, Path, Path, Opt[Path], Context) => Block): Block = - // TODO: do filtering - def f(arm: Case -> Block)(ctx: Context)(k: (StagedPath, Context) => Block): Block = - ruleBranch(x, p, arm._1, arm._2)(using ctx)(k) - - arms.map(f).collectApply(summon): (arms, ctx) => + Context + )(k: (StagedPath, Context) => Block): Block = + arms.map((cse, block) => ruleBranch(x, p, cse, block)(using _)).collectApply(summon): (arms, ctx) => shapeDyn(): sp => // TODO tuple(arms.map(_.code)): arms => - dflt match - case S(dflt) => - transformBlock(dflt)(using ctx): (dflt, ctx) => - k(sp, x.code, arms, S(dflt.code), ctx) - case N => k(sp, x.code, arms, N, ctx) + blockCtor("End", Ls()): e => + dflt match + case S(dflt) => + transformBlock(dflt)(using ctx): (dflt, ctx) => + optionSome(dflt.code): dflt => + blockCtor("Match", Ls(x.code, arms, dflt, e)): m => + StagedPath.mk(sp, m)(k(_, ctx)) + case N => + optionNone(): none => + blockCtor("Match", Ls(x.code, arms, none, e)): m => + StagedPath.mk(sp, m)(k(_, ctx)) def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = transformCase(cse): cse => fnFilter(x.shapes, cse): sp => StagedPath.mk(sp, x.code): x0 => val arm = Case.Lit(Tree.BoolLit(true)) -> ruleEnd()(k(_, ctx)) - (Match(x0.shapes.p.selSN("isEmpty"), Ls(arm), N, _)): - given Context = ctx.clone() += p -> x0 - transformBlock(b): (y1, ctx) => - blockCtor("End", Ls()): end => - // TODO: use Arm type instead of Tup - blockCtor("Tup", Ls(cse, y1.code)): cde => - StagedPath.mk(y1.shapes, cde)(k(_, ctx.clone() -= p)) + call(x0.shapes.p.selSN("isEmpty"), Ls()): scrut => + (Match(scrut, Ls(arm), N, _)): + given Context = ctx.clone() += p -> x0 + transformBlock(b): (y1, ctx) => + blockCtor("End", Ls()): end => + // TODO: use Arm type instead of Tup + blockCtor("Tup", Ls(cse, y1.code)): cde => + StagedPath.mk(y1.shapes, cde)(k(_, ctx.clone() -= p)) // transformations of Block diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 60ce3c3db8..a22efc7179 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -57,6 +57,13 @@ class Block with Assign(val lhs: Symbol, val rhs: Result, val rest: Block) Define(val defn: Defn, val rest: Block) End() + +fun concat(b1: Block, b2: Block) = if b1 is + Match(scrut, arms, dflt, rest) then Match(scrut, arms, dflt, concat(rest, b2)) + Return(res, implct) then b2 // discard return? + Assign(lhs, rhs, rest) then Assign(lhs, rhs, concat(rest, b2)) + Define(defn, rest) then Define(defn, concat(rest, b2)) + End() then b2 fun showBool(b: Bool) = if b then "true" else "false" From 1020d381776d3cabff0d4b780f21439aa3d3b62c Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 11:29:34 +0800 Subject: [PATCH 139/268] add debug print Shape --- .../main/scala/hkmc2/codegen/Instrumentation.scala | 11 ++++++++--- hkmc2/shared/src/test/mlscript/staging/Functions.mls | 8 ++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index b05b45b504..c15355d8b7 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -117,8 +117,11 @@ class InstrumentationImpl(using State): // linking functions defined in MLscipt - def fnPrintCode(p: Path)(k: Path => Block): Block = + def fnPrintCode(p: Path)(k: Block): Block = // discard result, we only care about side effect + blockCall("printCode", Ls(p))(_ => k) + def fnPrintShapeSet(p: ShapeSet)(rest: Block): Block = + shapeSetCall("printShapeSet", Ls(p.p))(_ => rest) def fnConcat(p1: Path, p2: Path)(k: Path => Block): Block = blockCall("concat", Ls(p1, p2))(k) @@ -371,7 +374,9 @@ class InstrumentationImpl(using State): val sym = modSym.asPath.selSN(genSym.nme) val debug = call(sym, Nil): ret => - fnPrintCode(StagedPath(ret).code)(_ => End()) + val p = StagedPath(ret) + (fnPrintShapeSet(p.shapes)(_)): + fnPrintCode(p.code)(End()) // NOTE: this debug printing only works for top-level modules, nested modules don't work (f.copy(sym = genSym, body = transformBlock(f.body)(_.end)), debug) @@ -385,7 +390,7 @@ class InstrumentationImpl(using State): case c: ClsLikeDefn => ruleCls(c, d.rest): p => ruleEnd(): b => - fnPrintCode(p)(_ => k(b, ctx)) + fnPrintCode(p)(k(b, ctx)) def transformBlock(b: Block)(using Context)(k: StagedPath => Block): Block = transformBlock(b)((p, _) => k(p)) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 09516e0a77..ebe21b3992 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -17,13 +17,17 @@ staged module B with fun i() = [1, 2] fun j() = new A() fun k() = [1].(0) -//│ > Define(ClsLikeDefn(Symbol("D")), End) -//│ > Define(ClsLikeDefn(Symbol("C")), End) +//│ > Lit(1) //│ > Return(Lit(1), false) +//│ > Lit(42) //│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) +//│ > Lit(1) //│ > Assign(Symbol("x"), Lit(undefined), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false))) +//│ > Arr(Lit(1), Lit(2)) //│ > Return(Tuple([Lit(1), Lit(2)]), false) +//│ > Class(A, []) //│ > Return(Instantiate(Select(Ref(Symbol("A")), Symbol("class")), []), false) +//│ > Lit(1) //│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) // collision with class name? From eece7ac391949118b31ecbf775954341219d90fe Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 11:30:40 +0800 Subject: [PATCH 140/268] print more information for ClsLikeDefn --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 9 +++++++-- hkmc2/shared/src/test/mlscript/staging/Functions.mls | 6 ++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index a22efc7179..fce01ebba4 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -121,8 +121,13 @@ fun showDefn(d: Defn): Str = showParamList(params) + ", " + showBlock(body) + ")" ClsLikeDefn(sym, paramsOpt, companion) then - // minimal, since this is unused in your staged Block for now - "ClsLikeDefn(" + showSymbol(sym) + ")" + // TODO: print rest of the arguments + "ClsLikeDefn(" + showSymbol(sym) + ", " + + if paramsOpt is + Some(params) then "(" + showParamList(params) + ")" + None then "([])" + + ", " + + "TODO" + ")" fun showOptBlock(ob: Opt[Block]) = if ob is Some(b) then showBlock(b) else "None" diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index ebe21b3992..defe12a1c6 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -17,6 +17,8 @@ staged module B with fun i() = [1, 2] fun j() = new A() fun k() = [1].(0) +//│ > Define(ClsLikeDefn(Symbol("D"), ([]), TODO), End) +//│ > Define(ClsLikeDefn(Symbol("C"), ([Symbol("a"), Symbol("b")]), TODO), End) //│ > Lit(1) //│ > Return(Lit(1), false) //│ > Lit(42) @@ -48,8 +50,8 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.43: staged module B with +//│ ║ l.49: staged module B with //│ ║ ^^^^^^ -//│ ║ l.44: fun f() = 1 +//│ ║ l.50: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From df68b1d1e4702bc1c98334b62ff86eec65e85c0f Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 15:40:19 +0800 Subject: [PATCH 141/268] combine Pattern with Case we transform Some(dflt) branch in a Match statement without calling the filter function at JS runtime --- .../scala/hkmc2/codegen/Instrumentation.scala | 39 +++++++++++-------- .../src/test/mlscript-compile/Block.mls | 4 +- .../src/test/mlscript-compile/Shape.mls | 16 ++++++++ .../src/test/mlscript-compile/ShapeSet.mls | 33 +--------------- 4 files changed, 43 insertions(+), 49 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index c15355d8b7..fc0cc58478 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -85,13 +85,10 @@ class InstrumentationImpl(using State): def blockMod(name: Str) = summon[State].blockSymbol.asPath.selSN(name) def optionMod(name: Str) = summon[State].optionSymbol.asPath.selSN(name) - def patternMod(name: Str) = summon[State].shapeSetSymbol.asPath.selSN("Pattern").selSN(name) def shapeSetMod(name: Str) = summon[State].shapeSetSymbol.asPath.selSN(name) def blockCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = ctor(blockMod(name), args, symName)(k) - def patternCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = - ctor(patternMod(name), args, symName)(k) def optionSome(arg: ArgWrappable, symName: Str = "tmp")(k: Path => Block): Block = ctor(optionMod("Some"), Ls(arg), symName)(k) def optionNone(symName: Str = "tmp")(k: Path => Block): Block = @@ -299,9 +296,10 @@ class InstrumentationImpl(using State): shapeDyn(): sp => // TODO tuple(arms.map(_.code)): arms => blockCtor("End", Ls()): e => + // unable to use transformOption here because ctx is changed here dflt match case S(dflt) => - transformBlock(dflt)(using ctx): (dflt, ctx) => + ruleWildCard(x, p, dflt): (dflt, ctx) => optionSome(dflt.code): dflt => blockCtor("Match", Ls(x.code, arms, dflt, e)): m => StagedPath.mk(sp, m)(k(_, ctx)) @@ -314,15 +312,25 @@ class InstrumentationImpl(using State): transformCase(cse): cse => fnFilter(x.shapes, cse): sp => StagedPath.mk(sp, x.code): x0 => - val arm = Case.Lit(Tree.BoolLit(true)) -> ruleEnd()(k(_, ctx)) call(x0.shapes.p.selSN("isEmpty"), Ls()): scrut => + val arm = Case.Lit(Tree.BoolLit(true)) -> ruleEnd()(p => Return(p.p, false)) (Match(scrut, Ls(arm), N, _)): given Context = ctx.clone() += p -> x0 transformBlock(b): (y1, ctx) => - blockCtor("End", Ls()): end => - // TODO: use Arm type instead of Tup - blockCtor("Tup", Ls(cse, y1.code)): cde => - StagedPath.mk(y1.shapes, cde)(k(_, ctx.clone() -= p)) + // TODO: use Arm type instead of Tup + tuple(Ls(cse, y1.code)): cde => + StagedPath.mk(y1.shapes, cde)(k(_, ctx.clone() -= p)) + + // this partially performs rules from filter to account for difference in Block.Case and Match pattern in the formalization + // to avoid defining the `_` pattern in Block.Case, we use the fact that filter(s, _) = s + def ruleWildCard(x: StagedPath, p: Path, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + // when pattern = _, x0 = x + call(x.shapes.p.selSN("isEmpty"), Ls()): scrut => + val arm = Case.Lit(Tree.BoolLit(true)) -> ruleEnd()(p => Return(p.p, false)) + (Match(scrut, Ls(arm), N, _)): + given Context = ctx.clone() += p -> x + transformBlock(b): (y1, ctx) => + k(y1, ctx.clone() -= p) // transformations of Block @@ -354,15 +362,14 @@ class InstrumentationImpl(using State): def transformArgs(args: Ls[Arg])(using Context)(k: Ls[StagedPath] => Block): Block = args.map(transformArg).collectApply(k) - def transformCase(cse: Case)(k: Path => Block): Block = + def transformCase(cse: Case)(using Context)(k: Path => Block): Block = cse match - case Case.Lit(lit) => patternCtor("Lit", Ls(Value.Lit(lit)))(k) - // wrong 2nd argument + case Case.Lit(lit) => blockCtor("Lit", Ls(Value.Lit(lit)))(k) case Case.Cls(cls, path) => - // TODO: retrieve argument names from symbol? transformSymbol(cls): cls => - patternCtor("Cls", Ls(cls, toValue(0)))(k) - case Case.Tup(len, inf) => patternCtor("Tup", Ls(len, inf).map(toValue))(k) + transformPath(path): path => + blockCtor("Cls", Ls(cls, path.code))(k) + case Case.Tup(len, inf) => blockCtor("Tup", Ls(len, inf).map(toValue))(k) case Case.Field(name, safe) => ??? // not supported // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function @@ -403,7 +410,7 @@ class InstrumentationImpl(using State): case a: Assign => ruleAssign(a)(k) case d: Define => transformDefine(d)(k) case End(_) => ruleEnd()(k2) - case _: Match => ??? + case m: Match => ruleMatch(m)(k) // temporary measure to accept returning an array // use BlockTransformer here? case Begin(b1, b2) => transformBlock(concat(b1, b2))(k) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index fce01ebba4..d0d3e36a50 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -27,7 +27,7 @@ class Case with constructor Lit(val lit: Literal) Cls(val cls: Symbol, val path: Path) - Tup(val len: Int, val inf: Bool) // TODO: remove inf? + Tup(val len: Int) // TODO: remove inf? class Result with constructor @@ -100,7 +100,7 @@ fun showCase(c: Case): Str = if c is Lit(lit) then "Lit(" + showLiteral(lit) + ")" Cls(cls, path) then "Cls(" + showSymbol(cls) + ", " + showPath(path) + ")" - Tup(len, inf) then "Tup(" + len + ", " + showBool(inf) + ")" + Tup(len) then "Tup(" + len + ")" fun showResult(r: Result): Str = if r is diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index 92634c2375..a82d5ff13b 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -81,3 +81,19 @@ fun static(s: Shape) = Lit(l) then not (l is Str and isPrimitiveType(l)) // redundant bracket? Class(_, params) then params.every(static(_.1)) Arr(shapes) then shapes.every(static) + +open Block { Case } + +fun silh(p: Case): Shape = if p is + Block.Lit(l) then Lit(l) + Block.Cls(sym, path) then Class(sym, Array(1).fill(["TODO", Dyn])) + Block.Tup(n) then Arr(Array(n).fill(Dyn)) + +fun filter(s: Shape, p: Case): Array[Shape] = + if [s, p] is + [Lit(l1), Block.Lit(l2)] and l1 == l2 then [s] + [Lit(l), Block.Cls(c, _)] and isPrimitiveTypeOf(c, l) then [s] + [Arr(ls), Block.Tup(n)] and ls.length == n then [s] + [Class(c1, _), Block.Cls(c2, _)] and c1.name == c2.name then [s] + [Dyn, _] then [silh(p)] + else [] diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls index fb98fec616..a5d257bf31 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -35,7 +35,7 @@ fun liftMany(arr: Array[Shape]) = ShapeSet(new Map(arr.map(s => [hash(s), s]))) fun union(s1: ShapeSet, s2: ShapeSet) = new Map([...s1.underlying, ...s2.underlying]) -fun flat(arr: Array[ShapeSet]) = arr.reduce(union) +fun flat(arr: Array[ShapeSet]) = new Map(arr.map(_.underlying).flat()) // Cartesian product: https://stackoverflow.com/a/43053803 fun prod(xs) = @@ -70,7 +70,7 @@ fun mkClass(sym: Symbol, params: Array[[Symbol, ShapeSet]]) = // helper functions -fun filter(s: ShapeSet, p: Pattern.Pattern) = s.flatMap(Pattern.filter(_, p)) +fun filter(s: ShapeSet, p: Block.Case) = s.flatMap(Shape.filter(_, p)) fun sel(s1: ShapeSet, s2: ShapeSet) = prod([s1.values(), s2.values()]) @@ -79,32 +79,3 @@ fun sel(s1: ShapeSet, s2: ShapeSet) = fun mrg(s1: ShapeSet, s2: ShapeSet) = mkDyn() // TODO - -open Block { Literal } -open Shape { isPrimitiveTypeOf } - -module Pattern with... - -class Pattern with - constructor - PLit(val lit: Literal) - Cls(val cls: Symbol, val n: Int) - Tup(val len: Int) - Wildcard() - -fun silh(p: Pattern): Shape = if p is - PLit(l) then Lit(l) - Cls(sym, n) then Class(sym, Array(n).fill(["TODO", Dyn])) - Tup(n) then Arr(Array(n).fill(Dyn)) - Wildcard then Dyn() - -fun filter(s: Shape, p: Pattern): Array[Shape] = - if [s, p] is - [_, Wildcard] then [s] - [Lit(l1), PLit(l2)] and l1 == l2 then [s] - [Lit(l), Cls(c, _)] and isPrimitiveTypeOf(c, l) then [s] - [Arr(ls), Tup(n)] and ls.length == n then [s] - [Class(c1, _), Cls(c2, _)] and c1.name == c2.name then [s] - [Dyn, _] then [silh(p)] - else [] - From aa3b19a174c68809151aacfc5d185ee5722bf19a Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:37:39 +0800 Subject: [PATCH 142/268] fill out more match instrumentation --- .../scala/hkmc2/codegen/Instrumentation.scala | 26 +++++++++++-------- .../src/test/mlscript/staging/Functions.mls | 14 ++++++++-- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index fc0cc58478..128c97fea7 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -37,7 +37,6 @@ class InstrumentationImpl(using State): def concat(b1: Block, b2: Block): Block = b1.mapTail { - case _: Return => b2 case _: End => b2 case _ => ??? } @@ -135,8 +134,7 @@ class InstrumentationImpl(using State): params.map((n, s) => (k: Path => Block) => transformSymbol(n): n => - tuple(Ls(n, s)): tup => - k(tup) + tuple(Ls(n, s))(k) ).collectApply: ls => tuple(ls): params => shapeSetCall("mkClass", Ls(cls, params))(s => k(ShapeSet(s))) @@ -149,6 +147,9 @@ class InstrumentationImpl(using State): shapeSetCall("filter", Ls(s1, s2))(s => k(ShapeSet(s))) def fnUnion(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = shapeSetCall("union", Ls(s1, s2))(s => k(ShapeSet(s))) + def fnFlat(s: Ls[ShapeSet])(k: ShapeSet => Block): Block = + tuple(s): tup => + shapeSetCall("flat", Ls(tup))(s => k(ShapeSet(s))) // transformation helpers @@ -293,7 +294,7 @@ class InstrumentationImpl(using State): Context )(k: (StagedPath, Context) => Block): Block = arms.map((cse, block) => ruleBranch(x, p, cse, block)(using _)).collectApply(summon): (arms, ctx) => - shapeDyn(): sp => // TODO + fnFlat(arms.map(_.shapes)): sp => tuple(arms.map(_.code)): arms => blockCtor("End", Ls()): e => // unable to use transformOption here because ctx is changed here @@ -313,13 +314,16 @@ class InstrumentationImpl(using State): fnFilter(x.shapes, cse): sp => StagedPath.mk(sp, x.code): x0 => call(x0.shapes.p.selSN("isEmpty"), Ls()): scrut => - val arm = Case.Lit(Tree.BoolLit(true)) -> ruleEnd()(p => Return(p.p, false)) - (Match(scrut, Ls(arm), N, _)): - given Context = ctx.clone() += p -> x0 - transformBlock(b): (y1, ctx) => - // TODO: use Arm type instead of Tup - tuple(Ls(cse, y1.code)): cde => - StagedPath.mk(y1.shapes, cde)(k(_, ctx.clone() -= p)) + ruleEnd(): e => + tuple(Ls(cse, e.code)): armStaged => + StagedPath.mk(e.shapes, armStaged): badArm => + val arm = Case.Lit(Tree.BoolLit(true)) -> k(badArm, ctx) + (Match(scrut, Ls(arm), N, _)): + given Context = ctx.clone() += p -> x0 + transformBlock(b): (y1, ctx) => + // TODO: use Arm type instead of Tup + tuple(Ls(cse, y1.code)): cde => + StagedPath.mk(y1.shapes, cde)(k(_, ctx.clone() -= p)) // this partially performs rules from filter to account for difference in Block.Case and Match pattern in the formalization // to avoid defining the `_` pattern in Block.Case, we use the fact that filter(s, _) = s diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index defe12a1c6..a21b91a7dd 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -17,6 +17,14 @@ staged module B with fun i() = [1, 2] fun j() = new A() fun k() = [1].(0) + fun l() = + if 9 is + 8 then 1 + 9 then 2 + Int then 3 + Bool then 4 + // TODO: Case.Tup + else 0 //│ > Define(ClsLikeDefn(Symbol("D"), ([]), TODO), End) //│ > Define(ClsLikeDefn(Symbol("C"), ([Symbol("a"), Symbol("b")]), TODO), End) //│ > Lit(1) @@ -31,6 +39,8 @@ staged module B with //│ > Return(Instantiate(Select(Ref(Symbol("A")), Symbol("class")), []), false) //│ > Lit(1) //│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) +//│ > Dyn +//│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Lit(8) -> End, Lit(9) -> Return(Lit(2), false), Cls(Symbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false), Cls(Symbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> End], Return(Lit(0), false), End)) // collision with class name? :js @@ -50,8 +60,8 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.49: staged module B with +//│ ║ l.59: staged module B with //│ ║ ^^^^^^ -//│ ║ l.50: fun f() = 1 +//│ ║ l.60: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From 4af583909721a82ff3e045c651c5271b372cc70a Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:44:55 +0800 Subject: [PATCH 143/268] update comments --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 128c97fea7..9fbda47efd 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -16,6 +16,9 @@ import syntax.{Literal, Tree} // it seems some logic should be deferred to BlockTransformer to dedup code // but it doesn't accept the current context, so applications seem limited +// it should be possible to cache some common constructions (End, Option) into the context +// this avoids having to rebuild the same structure everytime + class InstrumentationImpl(using State): type ArgWrappable = Path | Symbol | ShapeSet type Context = HashMap[Path, StagedPath] @@ -52,7 +55,7 @@ class InstrumentationImpl(using State): k(head :: tail) )(f) - // possible to wrangle to the form above, but unweildy to do so in practice + // possible to wrangle to the form above, but unwieldy to do so in practice extension [A, B](ls: Ls[B => ((A, B) => Block) => Block]) def collectApply(b: B)(f: (Ls[A], B) => Block): Block = ls.foldRight((b: B) => (f: (Ls[A], B) => Block) => f(Nil, b))((headCont, tailCont) => From 2c67c8e175935de3cf9326c81b5c7bad94451f3a Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:47:40 +0800 Subject: [PATCH 144/268] update PrintCode.mls --- .../src/test/mlscript/staging/PrintCode.mls | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls index 18be09c9c7..21e4d1e5aa 100644 --- a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls +++ b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls @@ -4,21 +4,19 @@ //│ Block = class Block { //│ Symbol: fun Symbol { class: class Symbol }, //│ Arg: fun Arg { class: class Arg }, -//│ Path: class Path, -//│ Select: fun Select { class: class Select }, -//│ DynSelect: fun DynSelect { class: class DynSelect }, -//│ ValueRef: fun ValueRef { class: class ValueRef }, -//│ ValueLit: fun ValueLit { class: class ValueLit }, //│ Case: class Case, //│ Lit: fun Lit { class: class Lit }, //│ Cls: fun Cls { class: class Cls }, //│ Tup: fun Tup { class: class Tup }, -//│ Wildcard: fun Wildcard { class: class Wildcard }, //│ Result: class Result, -//│ TrivialResult: fun TrivialResult { class: class TrivialResult }, //│ Call: fun Call { class: class Call }, //│ Instantiate: fun Instantiate { class: class Instantiate }, //│ Tuple: fun Tuple { class: class Tuple }, +//│ Path: class Path, +//│ Select: fun Select { class: class Select }, +//│ DynSelect: fun DynSelect { class: class DynSelect }, +//│ ValueRef: fun ValueRef { class: class ValueRef }, +//│ ValueLit: fun ValueLit { class: class ValueLit }, //│ Defn: class Defn, //│ ValDefn: fun ValDefn { class: class ValDefn }, //│ ClsLikeDefn: fun ClsLikeDefn { class: class ClsLikeDefn }, @@ -31,15 +29,7 @@ //│ Define: fun Define { class: class Define }, //│ End: fun End { class: class End } //│ } -//│ Shape = class Shape { -//│ ShapeSet: fun ShapeSet { class: class ShapeSet }, -//│ Shape: class Shape, -//│ Dyn: fun Dyn { class: class Dyn }, -//│ Lit: fun Lit { class: class Lit }, -//│ Arr: fun Arr { class: class Arr }, -//│ Class: fun Class { class: class Class }, -//│ Bot: fun Bot { class: class Bot } -//│ } +//│ ShapeSet = class ShapeSet { ShapeSet: fun ShapeSet { class: class ShapeSet } } Block.printCode(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x")], Block.Return(Block.ValueLit(1), false))) //│ > FunDefn(Symbol("f"), [Symbol("x")], Return(Lit(1), false)) From c90118c54ac819133d4ae44016714730c2d1ae0f Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:53:49 +0800 Subject: [PATCH 145/268] move optionNme inside stageCode scope this avoids renaming Option in test files that import Option separately, see ImportMLS.mls, Imports.mls, OpenWildcard.mls --- hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala index 6c83efc5f5..f2c62e7b5d 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala @@ -33,7 +33,6 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: val runtimeNme = baseScp.allocateName(Elaborator.State.runtimeSymbol) val termNme = baseScp.allocateName(Elaborator.State.termSymbol) val blockNme = baseScp.allocateName(Elaborator.State.blockSymbol) - val optionNme = baseScp.allocateName(Elaborator.State.optionSymbol) val shapeSetNme = baseScp.allocateName(Elaborator.State.shapeSetSymbol) val definitionMetadataNme = baseScp.allocateName(Elaborator.State.definitionMetadataSymbol) val prettyPrintNme = baseScp.allocateName(Elaborator.State.prettyPrintSymbol) @@ -61,6 +60,7 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: h.execute(s"const $prettyPrintNme = Symbol.for(\"mlscript.prettyPrint\");") if importQQ.isSet then importRuntimeModule(termNme, termFile) if stageCode.isSet then + val optionNme = baseScp.allocateName(Elaborator.State.optionSymbol) importRuntimeModule(blockNme, blockFile) importRuntimeModule(optionNme, optionFile) importRuntimeModule(shapeSetNme, shapeSetFile) From aae0086c576f3af053909ef64b357de11d27bb0c Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 17:30:03 +0800 Subject: [PATCH 146/268] Revert "move optionNme inside stageCode scope" This reverts commit c90118c54ac819133d4ae44016714730c2d1ae0f. this leads to Option not being available, updating the diff tests affected by the renaming --- hkmc2/shared/src/test/mlscript/codegen/ImportMLs.mls | 4 ++-- .../shared/src/test/mlscript/codegen/OpenWildcard.mls | 10 +++++----- hkmc2/shared/src/test/mlscript/lifter/Imports.mls | 2 +- .../src/test/scala/hkmc2/JSBackendDiffMaker.scala | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/codegen/ImportMLs.mls b/hkmc2/shared/src/test/mlscript/codegen/ImportMLs.mls index 07b13f5dfb..9b3f007882 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/ImportMLs.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/ImportMLs.mls @@ -20,7 +20,7 @@ open Option :sjs None isDefined() //│ JS (unsanitized): -//│ Option.isDefined(Option.None) +//│ Option1.isDefined(Option1.None) //│ = false case Some(x) then x @@ -39,7 +39,7 @@ Some(1) :sjs (new Some(1)) isDefined() //│ JS (unsanitized): -//│ let tmp3; tmp3 = globalThis.Object.freeze(new Option.Some.class(1)); Option.isDefined(tmp3) +//│ let tmp3; tmp3 = globalThis.Object.freeze(new Option1.Some.class(1)); Option1.isDefined(tmp3) //│ = true new Some(1) isDefined() diff --git a/hkmc2/shared/src/test/mlscript/codegen/OpenWildcard.mls b/hkmc2/shared/src/test/mlscript/codegen/OpenWildcard.mls index 59ec70080c..adcac476c6 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/OpenWildcard.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/OpenWildcard.mls @@ -15,7 +15,7 @@ open Option :sjs None isDefined() //│ JS (unsanitized): -//│ Option.isDefined(Option.None) +//│ Option1.isDefined(Option1.None) //│ = false Some(1) isDefined() @@ -52,13 +52,13 @@ none() :sjs val Option = "Oops" //│ JS (unsanitized): -//│ let Option1; Option1 = "Oops"; +//│ let Option2; Option2 = "Oops"; //│ Option = "Oops" :sjs Some(123) //│ JS (unsanitized): -//│ Option.Some(123) +//│ Option1.Some(123) //│ = Some(123) module Option with @@ -72,13 +72,13 @@ open Option :sjs Some //│ JS (unsanitized): -//│ Option.Some +//│ Option1.Some //│ = fun Some { class: class Some } :sjs None //│ JS (unsanitized): -//│ Option3.None +//│ Option4.None //│ = 123 diff --git a/hkmc2/shared/src/test/mlscript/lifter/Imports.mls b/hkmc2/shared/src/test/mlscript/lifter/Imports.mls index d5bc28e321..30f7c73d70 100644 --- a/hkmc2/shared/src/test/mlscript/lifter/Imports.mls +++ b/hkmc2/shared/src/test/mlscript/lifter/Imports.mls @@ -16,7 +16,7 @@ module A with //│ runtime.Unit; //│ } //│ static f(x) { -//│ if (x instanceof Option.Some.class) { +//│ if (x instanceof Option1.Some.class) { //│ return true //│ } else { //│ return false diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala index f2c62e7b5d..6c83efc5f5 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala @@ -33,6 +33,7 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: val runtimeNme = baseScp.allocateName(Elaborator.State.runtimeSymbol) val termNme = baseScp.allocateName(Elaborator.State.termSymbol) val blockNme = baseScp.allocateName(Elaborator.State.blockSymbol) + val optionNme = baseScp.allocateName(Elaborator.State.optionSymbol) val shapeSetNme = baseScp.allocateName(Elaborator.State.shapeSetSymbol) val definitionMetadataNme = baseScp.allocateName(Elaborator.State.definitionMetadataSymbol) val prettyPrintNme = baseScp.allocateName(Elaborator.State.prettyPrintSymbol) @@ -60,7 +61,6 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: h.execute(s"const $prettyPrintNme = Symbol.for(\"mlscript.prettyPrint\");") if importQQ.isSet then importRuntimeModule(termNme, termFile) if stageCode.isSet then - val optionNme = baseScp.allocateName(Elaborator.State.optionSymbol) importRuntimeModule(blockNme, blockFile) importRuntimeModule(optionNme, optionFile) importRuntimeModule(shapeSetNme, shapeSetFile) From 986ace7a5d038c3dfeb1aabf837ee2dd9f8eb7d9 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 17:46:28 +0800 Subject: [PATCH 147/268] use more meaningful names in Functions.mls --- .../src/test/mlscript/staging/Functions.mls | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index a21b91a7dd..32170cc0b5 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -1,23 +1,22 @@ :js :staging -// :ssjs class A() staged module B with - class C(a, b) - class D - fun f() = 1 - fun g() = + class Class(a, b) + class NoArg + fun lit() = 1 + fun assign() = let x = 42 let y = x y - fun h() = + fun _var() = val x = 1 x - fun i() = [1, 2] - fun j() = new A() - fun k() = [1].(0) - fun l() = + fun tup() = [1, 2] + fun inst() = new A() + fun dynsel() = [1].(0) + fun match() = if 9 is 8 then 1 9 then 2 @@ -25,8 +24,8 @@ staged module B with Bool then 4 // TODO: Case.Tup else 0 -//│ > Define(ClsLikeDefn(Symbol("D"), ([]), TODO), End) -//│ > Define(ClsLikeDefn(Symbol("C"), ([Symbol("a"), Symbol("b")]), TODO), End) +//│ > Define(ClsLikeDefn(Symbol("NoArg"), ([]), TODO), End) +//│ > Define(ClsLikeDefn(Symbol("Class"), ([Symbol("a"), Symbol("b")]), TODO), End) //│ > Lit(1) //│ > Return(Lit(1), false) //│ > Lit(42) @@ -60,8 +59,8 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.59: staged module B with +//│ ║ l.58: staged module B with //│ ║ ^^^^^^ -//│ ║ l.60: fun f() = 1 +//│ ║ l.59: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From f0456e13383acda8851698c8d868e321e2265acd Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 23:03:03 +0800 Subject: [PATCH 148/268] refactor collectApply --- .../scala/hkmc2/codegen/Instrumentation.scala | 55 +++++++++---------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 9fbda47efd..1ae12102df 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -5,6 +5,7 @@ import utils.* import hkmc2.Message.MessageContext import scala.collection.mutable.HashMap +import scala.util.chaining._ import mlscript.utils.*, shorthands.* @@ -44,27 +45,18 @@ class InstrumentationImpl(using State): case _ => ??? } - // TODO: use BlockTransformer.applyListOf? - extension [A](ls: Ls[(A => Block) => Block]) - def collectApply(f: Ls[A] => Block): Block = - // defer applying k while prepending new paths to the list - ls.foldRight((_: Ls[A] => Block)(Nil))((headCont, tailCont) => + extension [A, B](ls: Ls[(A => B) => B]) + def collectApply(f: Ls[A] => B): B = + // defer applying k while prepending new elements to the list + ls.foldRight((_: Ls[A] => B)(Nil))((headCont, tailCont) => k => headCont: head => tailCont: tail => k(head :: tail) )(f) - // possible to wrangle to the form above, but unwieldy to do so in practice - extension [A, B](ls: Ls[B => ((A, B) => Block) => Block]) - def collectApply(b: B)(f: (Ls[A], B) => Block): Block = - ls.foldRight((b: B) => (f: (Ls[A], B) => Block) => f(Nil, b))((headCont, tailCont) => - b => - k => - headCont(b): (head, b) => - tailCont(b): (tail, b) => - k(head :: tail, b) - )(b)(f) + extension [A, B, C](f: A => B => C) + def flip: B => A => C = b => f(_)(b) // helpers corresponding to constructors @@ -296,21 +288,24 @@ class InstrumentationImpl(using State): def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block])(using Context )(k: (StagedPath, Context) => Block): Block = - arms.map((cse, block) => ruleBranch(x, p, cse, block)(using _)).collectApply(summon): (arms, ctx) => - fnFlat(arms.map(_.shapes)): sp => - tuple(arms.map(_.code)): arms => - blockCtor("End", Ls()): e => - // unable to use transformOption here because ctx is changed here - dflt match - case S(dflt) => - ruleWildCard(x, p, dflt): (dflt, ctx) => - optionSome(dflt.code): dflt => - blockCtor("Match", Ls(x.code, arms, dflt, e)): m => - StagedPath.mk(sp, m)(k(_, ctx)) - case N => - optionNone(): none => - blockCtor("Match", Ls(x.code, arms, none, e)): m => - StagedPath.mk(sp, m)(k(_, ctx)) + arms.map((cse, block) => (f: StagedPath => Context => Block) => (ruleBranch(x, p, cse, block)(using _)).flip(f(_)(_))) + .collectApply + .pipe(_.flip(summon)): arms => + ctx => + fnFlat(arms.map(_.shapes)): sp => + tuple(arms.map(_.code)): arms => + blockCtor("End", Ls()): e => + // unable to use transformOption here because ctx is changed here + dflt match + case S(dflt) => + ruleWildCard(x, p, dflt): (dflt, ctx) => + optionSome(dflt.code): dflt => + blockCtor("Match", Ls(x.code, arms, dflt, e)): m => + StagedPath.mk(sp, m)(k(_, ctx)) + case N => + optionNone(): none => + blockCtor("Match", Ls(x.code, arms, none, e)): m => + StagedPath.mk(sp, m)(k(_, ctx)) def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = transformCase(cse): cse => From d5104524379be4da3e41e698bc9cf7a65b0119c7 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 23:03:38 +0800 Subject: [PATCH 149/268] formatting --- .../scala/hkmc2/codegen/Instrumentation.scala | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 1ae12102df..f1e64ee5fa 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -188,11 +188,10 @@ class InstrumentationImpl(using State): StagedPath.mk(sp, cde, "sel")(k) def ruleDynSel(d: DynSelect)(using Context)(k: StagedPath => Block): Block = - val DynSelect(qual, fld, arrayIdx) = d - transformPath(qual): x => - transformPath(fld): y => + transformPath(d.qual): x => + transformPath(d.fld): y => fnSel(x.shapes, y.shapes): sp => - blockCtor("DynSelect", Ls(x.code, y.code, toValue(arrayIdx))): cde => + blockCtor("DynSelect", Ls(x.code, y.code, toValue(d.arrayIdx))): cde => StagedPath.mk(sp, cde, "dynsel")(k) def ruleInst(i: Instantiate)(using Context)(k: StagedPath => Block): Block = @@ -200,8 +199,6 @@ class InstrumentationImpl(using State): assert(!mut, "mutable instantiation not supported") transformArgs(args): xs => tuple(xs.map(_.shapes)): shapes => - // reuse instrumentation logic, shape of cls is discarded - // possible to skip this? this triggers unnecessary "out of context" Dyn shape thing val sym = cls match case Select(Value.Ref(l), _) => l case _ => ??? @@ -209,6 +206,8 @@ class InstrumentationImpl(using State): // TODO: add back class names val fieldName = new TempSymbol(N, "TODO") shapeClass(sym, xs.map(x => (fieldName, x.shapes))): sp => + // reuse instrumentation logic, shape of cls is discarded + // possible to skip this? this uses ruleVar, which is not in formalization transformPath(cls): cls => tuple(xs.map(_.code)): codes => blockCtor("Instantiate", Ls(cls.code, codes)): cde => @@ -270,8 +269,7 @@ class InstrumentationImpl(using State): StagedPath.mk(sp, cde, "end")(k) def ruleBlk(b: Block)(using Context)(k: Path => Block): Block = - transformBlock(b): x => - k(x.code) + transformBlock(b)(k apply _.code) def ruleCls(cls: ClsLikeDefn, rest: Block)(using Context)(k: Path => Block): Block = (Define(cls, _)): @@ -285,9 +283,7 @@ class InstrumentationImpl(using State): blockCtor("ClsLikeDefn", Ls(c, paramsOpt, none)): cls => blockCtor("Define", Ls(cls, p.code))(k) - def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block])(using - Context - )(k: (StagedPath, Context) => Block): Block = + def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block])(using Context)(k: (StagedPath, Context) => Block): Block = arms.map((cse, block) => (f: StagedPath => Context => Block) => (ruleBranch(x, p, cse, block)(using _)).flip(f(_)(_))) .collectApply .pipe(_.flip(summon)): arms => @@ -390,16 +386,16 @@ class InstrumentationImpl(using State): // NOTE: this debug printing only works for top-level modules, nested modules don't work (f.copy(sym = genSym, body = transformBlock(f.body)(_.end)), debug) - def transformDefine(d: Define)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def transformDefine(d: Define)(using Context)(k: (StagedPath, Context) => Block): Block = d.defn match case f: FunDefn => ??? case v: ValDefn => - val ValDefn(t, x, r) = v + val ValDefn(_, x, r) = v ruleLet(x, Assign(x, r, d.rest))(k) case c: ClsLikeDefn => ruleCls(c, d.rest): p => ruleEnd(): b => - fnPrintCode(p)(k(b, ctx)) + fnPrintCode(p)(k(b, summon)) def transformBlock(b: Block)(using Context)(k: StagedPath => Block): Block = transformBlock(b)((p, _) => k(p)) @@ -416,6 +412,7 @@ class InstrumentationImpl(using State): // temporary measure to accept returning an array // use BlockTransformer here? case Begin(b1, b2) => transformBlock(concat(b1, b2))(k) + case _ => ??? // not supported // TODO: rename as InstrumentationTransformer? class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): From 0b2b7ea631dbf628d231162bc034b169ebd4b3be Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sun, 23 Nov 2025 23:04:00 +0800 Subject: [PATCH 150/268] update comments and debug info --- .../main/scala/hkmc2/codegen/Instrumentation.scala | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index f1e64ee5fa..30bcab2ddc 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -18,7 +18,7 @@ import syntax.{Literal, Tree} // but it doesn't accept the current context, so applications seem limited // it should be possible to cache some common constructions (End, Option) into the context -// this avoids having to rebuild the same structure everytime +// this avoids having to rebuild the same shapes everytime they are needed class InstrumentationImpl(using State): type ArgWrappable = Path | Symbol | ShapeSet @@ -297,11 +297,11 @@ class InstrumentationImpl(using State): ruleWildCard(x, p, dflt): (dflt, ctx) => optionSome(dflt.code): dflt => blockCtor("Match", Ls(x.code, arms, dflt, e)): m => - StagedPath.mk(sp, m)(k(_, ctx)) + StagedPath.mk(sp, m, "branches")(k(_, ctx)) case N => optionNone(): none => blockCtor("Match", Ls(x.code, arms, none, e)): m => - StagedPath.mk(sp, m)(k(_, ctx)) + StagedPath.mk(sp, m, "branches")(k(_, ctx)) def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = transformCase(cse): cse => @@ -310,6 +310,7 @@ class InstrumentationImpl(using State): call(x0.shapes.p.selSN("isEmpty"), Ls()): scrut => ruleEnd(): e => tuple(Ls(cse, e.code)): armStaged => + // returns Case -> Block, instead of End as in formalization StagedPath.mk(e.shapes, armStaged): badArm => val arm = Case.Lit(Tree.BoolLit(true)) -> k(badArm, ctx) (Match(scrut, Ls(arm), N, _)): @@ -317,9 +318,10 @@ class InstrumentationImpl(using State): transformBlock(b): (y1, ctx) => // TODO: use Arm type instead of Tup tuple(Ls(cse, y1.code)): cde => - StagedPath.mk(y1.shapes, cde)(k(_, ctx.clone() -= p)) + StagedPath.mk(y1.shapes, cde, "branch")(k(_, ctx.clone() -= p)) - // this partially performs rules from filter to account for difference in Block.Case and Match pattern in the formalization + // not in formalization + // this partially applies rules from filter to account for difference in Block.Case and Match pattern in the formalization // to avoid defining the `_` pattern in Block.Case, we use the fact that filter(s, _) = s def ruleWildCard(x: StagedPath, p: Path, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = // when pattern = _, x0 = x From b6c86e15f5a98f6b5bd4bd6291a41194a85f189a Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 24 Nov 2025 09:13:57 +0800 Subject: [PATCH 151/268] remove redundant import --- hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index 1dd5a64505..6947d617ad 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -9,8 +9,6 @@ import sourcecode.Line import mlscript.utils.*, shorthands.* import utils.* -import hkmc2.codegen.Instrumentation - import hkmc2.Message.MessageContext import codegen.Instrumentation From 869c519741674d8afe623e49c637489c2fa69f76 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 24 Nov 2025 09:21:38 +0800 Subject: [PATCH 152/268] match pretty printing syntax for DynSelect with formalization --- hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index 3bdcc636ce..ac1051ffe1 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -101,9 +101,7 @@ object Printer: val docQual = mkDocument(qual) doc"${docQual}.${name.name}" case DynSelect(qual, fld, ai) => - if ai - then doc"${mkDocument(qual)}.at(${mkDocument(fld)})" - else doc"${mkDocument(qual)}[${mkDocument(fld)}]" + doc"${mkDocument(qual)}.(${mkDocument(fld)})" case x: Value => mkDocument(x) def mkDocument(result: Result)(using Raise, Scope): Document = result match From cff8896a973590ddb5ccac9213063146a62e76b5 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 24 Nov 2025 10:06:23 +0800 Subject: [PATCH 153/268] fix mkClass --- hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls | 2 +- hkmc2/shared/src/test/mlscript/staging/Functions.mls | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls index a5d257bf31..2d85496c8c 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -63,7 +63,7 @@ fun mkArr(shapes: Array[ShapeSet]) = fun mkClass(sym: Symbol, params: Array[[Symbol, ShapeSet]]) = params - .map(p => p.1.underlying.values().map(s => [[p.0, s]]).toArray()) + .map(p => p.1.underlying.values().map(s => [p.0, s]).toArray()) |> prod .map(Class(sym, _)) |> liftMany diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 32170cc0b5..12d4d17c1e 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -1,7 +1,7 @@ :js :staging -class A() +class A(a) staged module B with class Class(a, b) class NoArg @@ -14,7 +14,7 @@ staged module B with val x = 1 x fun tup() = [1, 2] - fun inst() = new A() + fun inst() = new A(1) fun dynsel() = [1].(0) fun match() = if 9 is @@ -34,8 +34,8 @@ staged module B with //│ > Assign(Symbol("x"), Lit(undefined), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false))) //│ > Arr(Lit(1), Lit(2)) //│ > Return(Tuple([Lit(1), Lit(2)]), false) -//│ > Class(A, []) -//│ > Return(Instantiate(Select(Ref(Symbol("A")), Symbol("class")), []), false) +//│ > Class(A, [TODO:Lit(1)]) +//│ > Return(Instantiate(Select(Ref(Symbol("A")), Symbol("class")), [Lit(1)]), false) //│ > Lit(1) //│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) //│ > Dyn From 885337187cd6408926431f2437a3b54d20d4a7a2 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 24 Nov 2025 10:27:03 +0800 Subject: [PATCH 154/268] formatting --- .../scala/hkmc2/codegen/Instrumentation.scala | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 30bcab2ddc..26b9ce8d38 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -58,12 +58,12 @@ class InstrumentationImpl(using State): extension [A, B, C](f: A => B => C) def flip: B => A => C = b => f(_)(b) - // helpers corresponding to constructors + // helpers for constructing Block def assign(res: Result, symName: Str = "tmp")(k: Path => Block): Assign = // TODO: skip assignment if res: Path? - val tmp = new TempSymbol(N, symName) - Assign(tmp, res, k(tmp.asPath)) + val sym = new TempSymbol(N, symName) + Assign(sym, res, k(sym.asPath)) def tuple(elems: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = assign(Tuple(false, elems.map(asArg)), symName)(k) @@ -75,7 +75,7 @@ class InstrumentationImpl(using State): def call(fun: Path, args: Ls[ArgWrappable], isMlsFun: Bool = true, symName: Str = "tmp")(k: Path => Block): Block = assign(Call(fun, args.map(asArg))(isMlsFun, false), symName)(k) - // helper for staging the constructors + // helpers for instrumenting Block def blockMod(name: Str) = summon[State].blockSymbol.asPath.selSN(name) def optionMod(name: Str) = summon[State].optionSymbol.asPath.selSN(name) @@ -113,8 +113,6 @@ class InstrumentationImpl(using State): blockCall("printCode", Ls(p))(_ => k) def fnPrintShapeSet(p: ShapeSet)(rest: Block): Block = shapeSetCall("printShapeSet", Ls(p.p))(_ => rest) - def fnConcat(p1: Path, p2: Path)(k: Path => Block): Block = - blockCall("concat", Ls(p1, p2))(k) def shapeBot()(k: ShapeSet => Block): Block = shapeSetCall("mkBot", Ls())(s => k(ShapeSet(s))) @@ -134,6 +132,8 @@ class InstrumentationImpl(using State): tuple(ls): params => shapeSetCall("mkClass", Ls(cls, params))(s => k(ShapeSet(s))) + def fnConcat(p1: Path, p2: Path)(k: Path => Block): Block = + blockCall("concat", Ls(p1, p2))(k) def fnMrg(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = shapeSetCall("mrg", Ls(s1, s2))(s => k(ShapeSet(s))) def fnSel(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = @@ -349,6 +349,7 @@ class InstrumentationImpl(using State): case p: Path => transformPath(p)(k) case t: Tuple => ruleTup(t)(k) case i: Instantiate => ruleInst(i)(k) + case c: Call => ??? case _ => ??? // not supported def transformArg(a: Arg)(using Context)(k: StagedPath => Block): Block = @@ -399,11 +400,11 @@ class InstrumentationImpl(using State): ruleEnd(): b => fnPrintCode(p)(k(b, summon)) + // ruleBlk? def transformBlock(b: Block)(using Context)(k: StagedPath => Block): Block = transformBlock(b)((p, _) => k(p)) def transformBlock(b: Block)(using Context)(k: (StagedPath, Context) => Block): Block = - // ruleBlk? val k2 = k(_, summon) b match case r: Return => ruleReturn(r)(k) From a343c36a756adf6f1dd321dec612c8e4a1d46164 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 24 Nov 2025 11:54:45 +0800 Subject: [PATCH 155/268] fix syntax errors the staged modifier is lost somewhere during lowering --- .../scala/hkmc2/codegen/Instrumentation.scala | 8 +++--- .../src/test/mlscript/staging/Functions.mls | 26 ++----------------- .../src/test/mlscript/staging/Syntax.mls | 4 ++- 3 files changed, 9 insertions(+), 29 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 26b9ce8d38..0b2005604a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -73,7 +73,7 @@ class InstrumentationImpl(using State): // isMlsFun is probably always true? def call(fun: Path, args: Ls[ArgWrappable], isMlsFun: Bool = true, symName: Str = "tmp")(k: Path => Block): Block = - assign(Call(fun, args.map(asArg))(isMlsFun, false), symName)(k) + assign(Call(fun, args.map(asArg))(isMlsFun, false, false), symName)(k) // helpers for instrumenting Block @@ -200,7 +200,7 @@ class InstrumentationImpl(using State): transformArgs(args): xs => tuple(xs.map(_.shapes)): shapes => val sym = cls match - case Select(Value.Ref(l), _) => l + case Select(Value.Ref(l, _), _) => l case _ => ??? transformSymbol(sym): sym => // TODO: add back class names @@ -387,7 +387,7 @@ class InstrumentationImpl(using State): fnPrintCode(p.code)(End()) // NOTE: this debug printing only works for top-level modules, nested modules don't work - (f.copy(sym = genSym, body = transformBlock(f.body)(_.end)), debug) + (f.copy(sym = genSym, body = transformBlock(f.body)(_.end))(false), debug) def transformDefine(d: Define)(using Context)(k: (StagedPath, Context) => Block): Block = d.defn match @@ -425,7 +425,7 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): case d @ Define(defn, rest) => defn match // find modules with staged annotation - case c: ClsLikeDefn if c.sym.defn.exists(_.hasStagedModifier.isDefined) && c.companion.isDefined => + case c: ClsLikeDefn if c.isym.defn.exists(_.hasStagedModifier.isDefined) && c.companion.isDefined => val sym = c.sym.subst val companion = c.companion.get val (stagedMethods, debugPrintCode) = companion.methods diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 12d4d17c1e..3eae34c32c 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -24,22 +24,6 @@ staged module B with Bool then 4 // TODO: Case.Tup else 0 -//│ > Define(ClsLikeDefn(Symbol("NoArg"), ([]), TODO), End) -//│ > Define(ClsLikeDefn(Symbol("Class"), ([Symbol("a"), Symbol("b")]), TODO), End) -//│ > Lit(1) -//│ > Return(Lit(1), false) -//│ > Lit(42) -//│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) -//│ > Lit(1) -//│ > Assign(Symbol("x"), Lit(undefined), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false))) -//│ > Arr(Lit(1), Lit(2)) -//│ > Return(Tuple([Lit(1), Lit(2)]), false) -//│ > Class(A, [TODO:Lit(1)]) -//│ > Return(Instantiate(Select(Ref(Symbol("A")), Symbol("class")), [Lit(1)]), false) -//│ > Lit(1) -//│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) -//│ > Dyn -//│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Lit(8) -> End, Lit(9) -> Return(Lit(2), false), Cls(Symbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false), Cls(Symbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> End], Return(Lit(0), false), End)) // collision with class name? :js @@ -48,7 +32,7 @@ staged module B with class A() staged module A with fun f() = 1 -//│ ═══[RUNTIME ERROR] TypeError: A3.f_gen is not a function +//│ FAILURE: Unexpected lack of error to fix // unable to reference the class when calling the instrumented function for debugging :js @@ -57,10 +41,4 @@ staged module A with module A with staged module B with fun f() = 1 -//│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' -//│ ╟── which references the symbol introduced here -//│ ║ l.58: staged module B with -//│ ║ ^^^^^^ -//│ ║ l.59: fun f() = 1 -//│ ╙── ^^^^^^^^^^^^^^^ -//│ ═══[RUNTIME ERROR] ReferenceError: B is not defined +//│ FAILURE: Unexpected lack of error to fix diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index 2f5c8aab11..fb996b71f6 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -1,5 +1,7 @@ :pt +:js +// :lot staged module A //│ Parsed tree: //│ Modified: @@ -21,4 +23,4 @@ staged fun f() = 0 :staging staged module A //│ Pretty Lowered: -//│ define staged class A in set block$res = undefined in end +//│ define class A in set block$res1 = undefined in end From 3c4faec660df12baae4a93f8abdb958c1034007e Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:22:44 +0800 Subject: [PATCH 156/268] patch in instrumentation temporarily stage all modules until i can find where the staged modifier went --- .../scala/hkmc2/codegen/Instrumentation.scala | 10 +++++----- .../src/test/mlscript/staging/Functions.mls | 20 +++++++++++++++++-- .../src/test/mlscript/staging/Syntax.mls | 1 - 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 0b2005604a..452723575b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -199,10 +199,10 @@ class InstrumentationImpl(using State): assert(!mut, "mutable instantiation not supported") transformArgs(args): xs => tuple(xs.map(_.shapes)): shapes => - val sym = cls match - case Select(Value.Ref(l, _), _) => l - case _ => ??? - transformSymbol(sym): sym => + // val sym = cls match + // case Select(Value.Ref(l, _), _) => l + // case _ => ??? + transformSymbol(TempSymbol(N, "TODO")): sym => // TODO: add back class names val fieldName = new TempSymbol(N, "TODO") shapeClass(sym, xs.map(x => (fieldName, x.shapes))): sp => @@ -425,7 +425,7 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): case d @ Define(defn, rest) => defn match // find modules with staged annotation - case c: ClsLikeDefn if c.isym.defn.exists(_.hasStagedModifier.isDefined) && c.companion.isDefined => + case c: ClsLikeDefn if c.companion.isDefined => val sym = c.sym.subst val companion = c.companion.get val (stagedMethods, debugPrintCode) = companion.methods diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 3eae34c32c..8e4338e818 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -24,6 +24,22 @@ staged module B with Bool then 4 // TODO: Case.Tup else 0 +//│ > Define(ClsLikeDefn(Symbol("NoArg"), ([]), TODO), End) +//│ > Define(ClsLikeDefn(Symbol("Class"), ([Symbol("a"), Symbol("b")]), TODO), End) +//│ > Lit(1) +//│ > Return(Lit(1), false) +//│ > Lit(42) +//│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) +//│ > Dyn +//│ > Assign(Symbol("x"), Lit(undefined), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false))) +//│ > Arr(Lit(1), Lit(2)) +//│ > Return(Tuple([Lit(1), Lit(2)]), false) +//│ > Class(TODO, [TODO:Lit(1)]) +//│ > Return(Instantiate(Ref(Symbol("A")), [Lit(1)]), false) +//│ > Lit(1) +//│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) +//│ > Dyn +//│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Lit(8) -> End, Lit(9) -> Return(Lit(2), false), Cls(Symbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false), Cls(Symbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> End], Return(Lit(0), false), End)) // collision with class name? :js @@ -32,7 +48,7 @@ staged module B with class A() staged module A with fun f() = 1 -//│ FAILURE: Unexpected lack of error to fix +//│ ═══[RUNTIME ERROR] TypeError: A3.f_gen is not a function // unable to reference the class when calling the instrumented function for debugging :js @@ -41,4 +57,4 @@ staged module A with module A with staged module B with fun f() = 1 -//│ FAILURE: Unexpected lack of error to fix +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index fb996b71f6..163193d6df 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -20,7 +20,6 @@ staged fun f() = 0 :js :slot -:staging staged module A //│ Pretty Lowered: //│ define class A in set block$res1 = undefined in end From b7c3698bd698c78f7110829af452ae506a6e0c67 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:27:07 +0800 Subject: [PATCH 157/268] unreserve Option in Elaborator --- .../src/main/scala/hkmc2/semantics/Elaborator.scala | 4 ++-- hkmc2/shared/src/test/mlscript/codegen/ImportMLs.mls | 4 ++-- .../shared/src/test/mlscript/codegen/OpenWildcard.mls | 10 +++++----- hkmc2/shared/src/test/mlscript/lifter/Imports.mls | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index 84fcadb817..5357b8d01e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -237,8 +237,8 @@ object Elaborator: val prettyPrintSymbol = TempSymbol(N, "prettyPrint") val termSymbol = TempSymbol(N, "Term") val blockSymbol = TempSymbol(N, "Block") - val shapeSetSymbol = TempSymbol(N, "ShapeSet") - val optionSymbol = TempSymbol(N, "Option") + val shapeSetSymbol = TempSymbol(N, "shapeSet") + val optionSymbol = TempSymbol(N, "option") val wasmSymbol = TempSymbol(N, "wasm") val effectSigSymbol = ClassSymbol(DummyTypeDef(syntax.Cls), Ident("EffectSig")) val nonLocalRetHandlerTrm = diff --git a/hkmc2/shared/src/test/mlscript/codegen/ImportMLs.mls b/hkmc2/shared/src/test/mlscript/codegen/ImportMLs.mls index 9b3f007882..07b13f5dfb 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/ImportMLs.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/ImportMLs.mls @@ -20,7 +20,7 @@ open Option :sjs None isDefined() //│ JS (unsanitized): -//│ Option1.isDefined(Option1.None) +//│ Option.isDefined(Option.None) //│ = false case Some(x) then x @@ -39,7 +39,7 @@ Some(1) :sjs (new Some(1)) isDefined() //│ JS (unsanitized): -//│ let tmp3; tmp3 = globalThis.Object.freeze(new Option1.Some.class(1)); Option1.isDefined(tmp3) +//│ let tmp3; tmp3 = globalThis.Object.freeze(new Option.Some.class(1)); Option.isDefined(tmp3) //│ = true new Some(1) isDefined() diff --git a/hkmc2/shared/src/test/mlscript/codegen/OpenWildcard.mls b/hkmc2/shared/src/test/mlscript/codegen/OpenWildcard.mls index adcac476c6..59ec70080c 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/OpenWildcard.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/OpenWildcard.mls @@ -15,7 +15,7 @@ open Option :sjs None isDefined() //│ JS (unsanitized): -//│ Option1.isDefined(Option1.None) +//│ Option.isDefined(Option.None) //│ = false Some(1) isDefined() @@ -52,13 +52,13 @@ none() :sjs val Option = "Oops" //│ JS (unsanitized): -//│ let Option2; Option2 = "Oops"; +//│ let Option1; Option1 = "Oops"; //│ Option = "Oops" :sjs Some(123) //│ JS (unsanitized): -//│ Option1.Some(123) +//│ Option.Some(123) //│ = Some(123) module Option with @@ -72,13 +72,13 @@ open Option :sjs Some //│ JS (unsanitized): -//│ Option1.Some +//│ Option.Some //│ = fun Some { class: class Some } :sjs None //│ JS (unsanitized): -//│ Option4.None +//│ Option3.None //│ = 123 diff --git a/hkmc2/shared/src/test/mlscript/lifter/Imports.mls b/hkmc2/shared/src/test/mlscript/lifter/Imports.mls index 30f7c73d70..d5bc28e321 100644 --- a/hkmc2/shared/src/test/mlscript/lifter/Imports.mls +++ b/hkmc2/shared/src/test/mlscript/lifter/Imports.mls @@ -16,7 +16,7 @@ module A with //│ runtime.Unit; //│ } //│ static f(x) { -//│ if (x instanceof Option1.Some.class) { +//│ if (x instanceof Option.Some.class) { //│ return true //│ } else { //│ return false From c149a11f28d4ac6d54232b71447f90306da7cabb Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:44:55 +0800 Subject: [PATCH 158/268] remove argument names from class shape --- .../main/scala/hkmc2/codegen/Instrumentation.scala | 14 ++++---------- hkmc2/shared/src/test/mlscript-compile/Shape.mls | 12 +++++------- .../shared/src/test/mlscript-compile/ShapeSet.mls | 11 +++++------ .../shared/src/test/mlscript/staging/Functions.mls | 2 +- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 452723575b..e22a4be303 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -123,14 +123,9 @@ class InstrumentationImpl(using State): def shapeArr(ps: Ls[ShapeSet])(k: ShapeSet => Block): Block = tuple(ps, "test"): tup => shapeSetCall("mkArr", Ls(tup))(s => k(ShapeSet(s))) - def shapeClass(cls: Path, params: Ls[(Symbol, ShapeSet)])(k: ShapeSet => Block): Block = - params.map((n, s) => - (k: Path => Block) => - transformSymbol(n): n => - tuple(Ls(n, s))(k) - ).collectApply: ls => - tuple(ls): params => - shapeSetCall("mkClass", Ls(cls, params))(s => k(ShapeSet(s))) + def shapeClass(cls: Path, params: Ls[ShapeSet])(k: ShapeSet => Block): Block = + tuple(params): params => + shapeSetCall("mkClass", Ls(cls, params))(s => k(ShapeSet(s))) def fnConcat(p1: Path, p2: Path)(k: Path => Block): Block = blockCall("concat", Ls(p1, p2))(k) @@ -204,8 +199,7 @@ class InstrumentationImpl(using State): // case _ => ??? transformSymbol(TempSymbol(N, "TODO")): sym => // TODO: add back class names - val fieldName = new TempSymbol(N, "TODO") - shapeClass(sym, xs.map(x => (fieldName, x.shapes))): sp => + shapeClass(sym, xs.map(_.shapes)): sp => // reuse instrumentation logic, shape of cls is discarded // possible to skip this? this uses ruleVar, which is not in formalization transformPath(cls): cls => diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index a82d5ff13b..b0654866fe 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -10,16 +10,14 @@ class Shape with constructor Dyn() Lit(val l: Literal) - Arr(val shapes: Array[Shape]) // is length parameter needed? - Class(val sym: Symbol, val params: Array[[Symbol, Shape]]) - Bot() // temp stub for ShapeSet + Arr(val shapes: Array[Shape]) + Class(val sym: Symbol, val params: Array[Shape]) fun show(s: Shape) = if s is Dyn then "Dyn" Lit(lit) then "Lit(" + Block.showLiteral(lit) + ")" Arr(shapes) then "Arr(" + shapes.map(show).join(", ") + ")" - Class(sym, params) then "Class(" + sym.name + ", [" + params.map(p => p.0.name + ":" + show(p.1)).join(", ") + "])" - Bot() then "Bot()" + Class(sym, params) then "Class(" + sym.name + ", [" + params.map(show).join(", ") + "])" fun isPrimitiveType(sym: Str) = if sym is @@ -60,7 +58,7 @@ fun mrg(s1: Array[Shape]) = fun sel(s1: Shape, s2: Shape): Array[Shape] = if [s1, s2] is [Class(c, params), Lit(n)] and n is Str - then if params.find(_.0.name == n) + then if () // TODO: get parameter from context == () then [] is param then [param.1] [Dyn, Lit(n)] and n is Str @@ -86,7 +84,7 @@ open Block { Case } fun silh(p: Case): Shape = if p is Block.Lit(l) then Lit(l) - Block.Cls(sym, path) then Class(sym, Array(1).fill(["TODO", Dyn])) + Block.Cls(sym, path) then Class(sym, Array(1).fill(Dyn)) // TODO: find length of argument Block.Tup(n) then Arr(Array(n).fill(Dyn)) fun filter(s: Shape, p: Case): Array[Shape] = diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls index 2d85496c8c..a2012e80ea 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -33,9 +33,9 @@ fun liftMany(arr: Array[Shape]) = ShapeSet(new Map(arr.map(s => [hash(s), s]))) // combining ShapeSet -fun union(s1: ShapeSet, s2: ShapeSet) = new Map([...s1.underlying, ...s2.underlying]) +fun union(s1: ShapeSet, s2: ShapeSet) = ShapeSet(new Map([...s1.underlying, ...s2.underlying])) -fun flat(arr: Array[ShapeSet]) = new Map(arr.map(_.underlying).flat()) +fun flat(arr: Array[ShapeSet]) = ShapeSet(new Map(arr.map(_.underlying.entries().toArray()).flat())) // Cartesian product: https://stackoverflow.com/a/43053803 fun prod(xs) = @@ -61,11 +61,10 @@ fun mkArr(shapes: Array[ShapeSet]) = .map(x => Arr(x)) |> liftMany -fun mkClass(sym: Symbol, params: Array[[Symbol, ShapeSet]]) = - params - .map(p => p.1.underlying.values().map(s => [p.0, s]).toArray()) +fun mkClass(sym: Symbol, params: Array[ShapeSet]) = + params.map((s, _, _) => s.underlying.values().toArray()) |> prod - .map(Class(sym, _)) + .map((s, _, _) => Class(sym, s)) |> liftMany // helper functions diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 8e4338e818..5313779c8b 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -34,7 +34,7 @@ staged module B with //│ > Assign(Symbol("x"), Lit(undefined), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false))) //│ > Arr(Lit(1), Lit(2)) //│ > Return(Tuple([Lit(1), Lit(2)]), false) -//│ > Class(TODO, [TODO:Lit(1)]) +//│ > Class(TODO, [Lit(1)]) //│ > Return(Instantiate(Ref(Symbol("A")), [Lit(1)]), false) //│ > Lit(1) //│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) From 1f5c8d7125c3735f3271e3551daac4bf75c0db53 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 24 Nov 2025 20:12:00 +0800 Subject: [PATCH 159/268] move functions --- .../src/test/mlscript-compile/Block.mls | 16 ++++++++++++++++ .../src/test/mlscript-compile/Shape.mls | 19 ++++--------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index d0d3e36a50..56e17e92da 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -17,6 +17,22 @@ type Ident = Symbol type Literal = null | undefined | Str | Int | Num | Bool +fun isPrimitiveType(sym: Str) = + if sym is + "Str" then true + "Int" then true + "Num" then true + "Bool" then true + else false + +fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = + if [sym.name, l] is + ["Str", l] and l is Str then true + ["Int", i] and i is Int then true + ["Num", n] and n is Num then true + ["Bool", b] and b is Bool then true + else false + type ParamList = Array[Symbol] // Classes defined in Block.scala diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index b0654866fe..12880b68fe 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -1,6 +1,8 @@ import "./Block.mls" type Literal = null | undefined | Str | Int | Num | Bool + +open Block { ClassSymbol, showSymbol, isPrimitiveType, isPrimitiveTypeOf } type Symbol = Block.Symbol type Shape = Shape.Shape @@ -19,21 +21,8 @@ fun show(s: Shape) = if s is Arr(shapes) then "Arr(" + shapes.map(show).join(", ") + ")" Class(sym, params) then "Class(" + sym.name + ", [" + params.map(show).join(", ") + "])" -fun isPrimitiveType(sym: Str) = - if sym is - "Str" then true - "Int" then true - "Num" then true - "Bool" then true - else false - -fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = - if [sym.name, l] is - ["Str", l] and l is Str then true - ["Int", i] and i is Int then true - ["Num", n] and n is Num then true - ["Bool", b] and b is Bool then true - else false + + fun zipMrg[A](a: Array[A], b: Array[A]): Array[A] = a.map((a, i, _) => mrg2(a, b.at(i))) From a6b01621796ade035314e29666e6f684bc2cd071 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 24 Nov 2025 20:57:53 +0800 Subject: [PATCH 160/268] add ClassSymbol --- .../scala/hkmc2/codegen/Instrumentation.scala | 28 +++++++++--- .../src/test/mlscript-compile/Block.mls | 19 ++++++-- .../src/test/mlscript-compile/Shape.mls | 30 +++++++------ .../src/test/mlscript-compile/ShapeSet.mls | 4 +- .../src/test/mlscript/staging/Functions.mls | 43 +++++++++++-------- 5 files changed, 79 insertions(+), 45 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index e22a4be303..7a71e6ca68 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -143,7 +143,19 @@ class InstrumentationImpl(using State): // transformation helpers - def transformSymbol(sym: Symbol)(k: Path => Block) = blockCtor("Symbol", Ls(toValue(sym.nme)))(k) + def transformSymbol[S <: Symbol](sym: S)(k: Path => Block): Block = + sym match + case clsSym: ClassSymbol => + clsSym.defn.get.paramsOpt match + case S(ps) => + ps.params.map(p => transformSymbol(p.sym)).collectApply: params => + tuple(params): params => + optionSome(params): paramsOpt => + blockCtor("ClassSymbol", Ls(toValue(sym.nme), paramsOpt))(k) + case N => + optionNone(): none => + blockCtor("ClassSymbol", Ls(toValue(sym.nme), none))(k) + case _ => blockCtor("Symbol", Ls(toValue(sym.nme)), "sym")(k) def transformOption[A](xOpt: Opt[A], f: A => (Path => Block) => Block)(k: Path => Block): Block = xOpt match @@ -159,7 +171,8 @@ class InstrumentationImpl(using State): // not in formalization def ruleVar(r: Value.Ref)(k: StagedPath => Block): Block = - blockCtor("Symbol", Ls(toValue(r.l.nme))): sym => + val Value.Ref(l, disamb) = r + transformSymbol(disamb.getOrElse(l)): sym => blockCtor("ValueRef", Ls(sym)): cde => // variable defined outside of scope, may be a reference to a class shapeDyn(): sp => @@ -194,11 +207,12 @@ class InstrumentationImpl(using State): assert(!mut, "mutable instantiation not supported") transformArgs(args): xs => tuple(xs.map(_.shapes)): shapes => - // val sym = cls match - // case Select(Value.Ref(l, _), _) => l - // case _ => ??? - transformSymbol(TempSymbol(N, "TODO")): sym => - // TODO: add back class names + val sym = cls match + // TODO: if class is staged, we can just use Symbol without storing the arguments + case Value.Ref(l, S(disamb)) => transformSymbol(disamb) + case s: Select if s.symbol.isDefined => transformSymbol(s.symbol.get) + case _ => transformSymbol(TempSymbol(N, "TODO")) + sym: sym => shapeClass(sym, xs.map(_.shapes)): sp => // reuse instrumentation logic, shape of cls is discarded // possible to skip this? this uses ruleVar, which is not in formalization diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 56e17e92da..a0756ec9d2 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -14,11 +14,13 @@ type Opt[A] = Option[A] class Symbol(val name: Str) type Ident = Symbol +// this is so that we're able to retrieve information about the class from the symbol +class ClassSymbol(val name: Str, val args: Opt[Array[Symbol]]) extends Symbol(name) type Literal = null | undefined | Str | Int | Num | Bool -fun isPrimitiveType(sym: Str) = - if sym is +fun isPrimitiveType(sym: Symbol) = + if sym.name is "Str" then true "Int" then true "Num" then true @@ -89,7 +91,16 @@ fun showLiteral(l: Literal) = null then "null" else l.toString() -fun showSymbol(s: Symbol) = "Symbol(" + "\"" + s.name + "\"" + ")" +fun showSymbol(s: Symbol) = + // console.log("printing " + s) + if s is + ClassSymbol(name, args) then + "ClassSymbol(" + "\"" + name + "\"" + + if args + is Some(args) then ":[" + args.map(showSymbol).join(", ") + "]" + is None then "" + + ")" + _ then "Symbol(" + "\"" + s.name + "\"" + ")" fun showIdent(i: Ident) = showSymbol(i) @@ -141,7 +152,7 @@ fun showDefn(d: Defn): Str = "ClsLikeDefn(" + showSymbol(sym) + ", " + if paramsOpt is Some(params) then "(" + showParamList(params) + ")" - None then "([])" + None then "()" + ", " + "TODO" + ")" diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index 12880b68fe..9805553afc 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -1,9 +1,10 @@ import "./Block.mls" +import "./Option.mls" type Literal = null | undefined | Str | Int | Num | Bool open Block { ClassSymbol, showSymbol, isPrimitiveType, isPrimitiveTypeOf } -type Symbol = Block.Symbol +open Option type Shape = Shape.Shape module Shape with... @@ -13,16 +14,14 @@ class Shape with Dyn() Lit(val l: Literal) Arr(val shapes: Array[Shape]) - Class(val sym: Symbol, val params: Array[Shape]) - -fun show(s: Shape) = if s is - Dyn then "Dyn" - Lit(lit) then "Lit(" + Block.showLiteral(lit) + ")" - Arr(shapes) then "Arr(" + shapes.map(show).join(", ") + ")" - Class(sym, params) then "Class(" + sym.name + ", [" + params.map(show).join(", ") + "])" - - + Class(val sym: ClassSymbol, val params: Array[Shape]) +fun show(s: Shape) = + if s is + Dyn then "Dyn" + Lit(lit) then "Lit(" + Block.showLiteral(lit) + ")" + Arr(shapes) then "Arr(" + shapes.map(show).join(", ") + ")" + Class(sym, params) then "Class(" + showSymbol(sym) + ", [" + params.map(show).join(", ") + "])" fun zipMrg[A](a: Array[A], b: Array[A]): Array[A] = a.map((a, i, _) => mrg2(a, b.at(i))) @@ -46,10 +45,11 @@ fun mrg(s1: Array[Shape]) = fun sel(s1: Shape, s2: Shape): Array[Shape] = if [s1, s2] is - [Class(c, params), Lit(n)] and n is Str - then if () // TODO: get parameter from context + [Class(sym, params), Lit(n)] and n is Str + and sym.args is Some(args) + and args.find(_ == n) == () then [] - is param then [param.1] + is i then [params.(i)] [Dyn, Lit(n)] and n is Str then [Dyn()] [Arr(shapes), Lit(n)] and n is Int @@ -73,7 +73,9 @@ open Block { Case } fun silh(p: Case): Shape = if p is Block.Lit(l) then Lit(l) - Block.Cls(sym, path) then Class(sym, Array(1).fill(Dyn)) // TODO: find length of argument + Block.Cls(sym, path) then + val size = if sym.args is Some(i) then i else 0 + Class(sym, Array(size).fill(Dyn)) Block.Tup(n) then Arr(Array(n).fill(Dyn)) fun filter(s: Shape, p: Case): Array[Shape] = diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls index a2012e80ea..1fef324ee2 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -3,7 +3,7 @@ import "./Block.mls" import "./Shape.mls" open Predef -open Block { Symbol } +open Block { ClassSymbol } open Shape { show } type ShapeSet = ShapeSet.ShapeSet @@ -61,7 +61,7 @@ fun mkArr(shapes: Array[ShapeSet]) = .map(x => Arr(x)) |> liftMany -fun mkClass(sym: Symbol, params: Array[ShapeSet]) = +fun mkClass(sym: ClassSymbol, params: Array[ShapeSet]) = params.map((s, _, _) => s.underlying.values().toArray()) |> prod .map((s, _, _) => Class(sym, s)) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 5313779c8b..a60188442e 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -1,10 +1,7 @@ :js :staging -class A(a) -staged module B with - class Class(a, b) - class NoArg +staged module Expressions with fun lit() = 1 fun assign() = let x = 42 @@ -14,18 +11,15 @@ staged module B with val x = 1 x fun tup() = [1, 2] - fun inst() = new A(1) fun dynsel() = [1].(0) fun match() = if 9 is - 8 then 1 - 9 then 2 - Int then 3 - Bool then 4 - // TODO: Case.Tup - else 0 -//│ > Define(ClsLikeDefn(Symbol("NoArg"), ([]), TODO), End) -//│ > Define(ClsLikeDefn(Symbol("Class"), ([Symbol("a"), Symbol("b")]), TODO), End) + 8 then 1 + 9 then 2 + Int then 3 + Bool then 4 + // [1, 2] then 5 // TODO: Case.Tup, needs handling for Label, Break + else 0 //│ > Lit(1) //│ > Return(Lit(1), false) //│ > Lit(42) @@ -34,12 +28,25 @@ staged module B with //│ > Assign(Symbol("x"), Lit(undefined), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false))) //│ > Arr(Lit(1), Lit(2)) //│ > Return(Tuple([Lit(1), Lit(2)]), false) -//│ > Class(TODO, [Lit(1)]) -//│ > Return(Instantiate(Ref(Symbol("A")), [Lit(1)]), false) //│ > Lit(1) //│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) //│ > Dyn -//│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Lit(8) -> End, Lit(9) -> Return(Lit(2), false), Cls(Symbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false), Cls(Symbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> End], Return(Lit(0), false), End)) +//│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Lit(8) -> End, Lit(9) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false), Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> End], Return(Lit(0), false), End)) + +:js +:staging +class Outside(a) +staged module ClassInstrumentation with + class Class(a, b) + class NoArg + fun inst1() = new Outside(1) + fun inst2() = new NoArg +//│ > Define(ClsLikeDefn(Symbol("NoArg"), (), TODO), End) +//│ > Define(ClsLikeDefn(Symbol("Class"), ([Symbol("a"), Symbol("b")]), TODO), End) +//│ > Class(ClassSymbol("Outside":[Symbol("a")]), [Lit(1)]) +//│ > Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) +//│ > Class(ClassSymbol("NoArg"), []) +//│ > Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), Symbol("NoArg")), []), false) // collision with class name? :js @@ -48,7 +55,7 @@ staged module B with class A() staged module A with fun f() = 1 -//│ ═══[RUNTIME ERROR] TypeError: A3.f_gen is not a function +//│ ═══[RUNTIME ERROR] TypeError: A1.f_gen is not a function // unable to reference the class when calling the instrumented function for debugging :js @@ -57,4 +64,4 @@ staged module A with module A with staged module B with fun f() = 1 -//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing +//│ /!!!\ Uncaught error: java.lang.AssertionError: assertion failed: nested module not supported From c9f3c6a7a45ec1f89334af4d4605ad558a5622de Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 24 Nov 2025 21:06:27 +0800 Subject: [PATCH 161/268] formatting --- .../scala/hkmc2/codegen/Instrumentation.scala | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 7a71e6ca68..fc98b9a5de 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -103,7 +103,7 @@ class InstrumentationImpl(using State): def end: Block = Return(p, false) object StagedPath: - def mk(shapeSet: ShapeSet, code: Path, symName: Str = "tmp")(k: StagedPath => Block): Block = + def apply(shapeSet: ShapeSet, code: Path, symName: Str = "tmp")(k: StagedPath => Block): Block = tuple(Ls(shapeSet.p, code), symName)(p => k(StagedPath(p))) // linking functions defined in MLscipt @@ -167,7 +167,7 @@ class InstrumentationImpl(using State): def ruleLit(l: Value.Lit)(k: StagedPath => Block): Block = shapeLit(l): sp => blockCtor("ValueLit", Ls(l)): cde => - StagedPath.mk(sp, cde, "lit")(k) + StagedPath(sp, cde, "lit")(k) // not in formalization def ruleVar(r: Value.Ref)(k: StagedPath => Block): Block = @@ -176,7 +176,7 @@ class InstrumentationImpl(using State): blockCtor("ValueRef", Ls(sym)): cde => // variable defined outside of scope, may be a reference to a class shapeDyn(): sp => - StagedPath.mk(sp, cde, "var")(k) + StagedPath(sp, cde, "var")(k) def ruleTup(t: Tuple)(using Context)(k: StagedPath => Block): Block = assert(!t.mut, "mutable tuple not supported") @@ -184,7 +184,7 @@ class InstrumentationImpl(using State): shapeArr(xs.map(_.shapes)): sp => tuple(xs.map(_.code)): codes => blockCtor("Tuple", Ls(codes)): cde => - StagedPath.mk(sp, cde, "tup")(k) + StagedPath(sp, cde, "tup")(k) def ruleSel(s: Select)(using Context)(k: StagedPath => Block): Block = val Select(p, i @ Tree.Ident(name)) = s @@ -193,14 +193,14 @@ class InstrumentationImpl(using State): fnSel(x.shapes, n): sp => blockCtor("Symbol", Ls(toValue(name))): name => blockCtor("Select", Ls(x.code, name)): cde => - StagedPath.mk(sp, cde, "sel")(k) + StagedPath(sp, cde, "sel")(k) def ruleDynSel(d: DynSelect)(using Context)(k: StagedPath => Block): Block = transformPath(d.qual): x => transformPath(d.fld): y => fnSel(x.shapes, y.shapes): sp => blockCtor("DynSelect", Ls(x.code, y.code, toValue(d.arrayIdx))): cde => - StagedPath.mk(sp, cde, "dynsel")(k) + StagedPath(sp, cde, "dynsel")(k) def ruleInst(i: Instantiate)(using Context)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i @@ -219,12 +219,12 @@ class InstrumentationImpl(using State): transformPath(cls): cls => tuple(xs.map(_.code)): codes => blockCtor("Instantiate", Ls(cls.code, codes)): cde => - StagedPath.mk(sp, cde, "inst")(k) + StagedPath(sp, cde, "inst")(k) def ruleReturn(r: Return)(using Context)(k: (StagedPath, Context) => Block): Block = transformResult(r.res): x => blockCtor("Return", Ls(x.code, toValue(false))): cde => - StagedPath.mk(x.shapes, cde, "return")(k(_, summon)) + StagedPath(x.shapes, cde, "return")(k(_, summon)) def ruleMatch(m: Match)(using Context)(k: (StagedPath, Context) => Block): Block = val Match(p, ks, dflt, rest) = m @@ -233,7 +233,7 @@ class InstrumentationImpl(using State): transformBlock(rest)(using ctx1): (z, ctx2) => fnMrg(stagedMatch.shapes, z.shapes): sp => fnConcat(stagedMatch.code, z.code): cde => - StagedPath.mk(sp, cde)(k(_, ctx2)) + StagedPath(sp, cde)(k(_, ctx2)) def ruleAssign(a: Assign)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Assign(x, r, b) = a @@ -245,49 +245,49 @@ class InstrumentationImpl(using State): ctx.get(x.asPath) match case S(x1) => fnUnion(y.shapes, x1.shapes): sp => - StagedPath.mk(sp, xStaged): x2 => + StagedPath(sp, xStaged): x2 => (Assign(x, x2.p, _)): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => - StagedPath.mk(z.shapes, cde, "assign")(k(_, ctx)) + StagedPath(z.shapes, cde, "assign")(k(_, ctx)) case N => - StagedPath.mk(y.shapes, xStaged): x2 => + StagedPath(y.shapes, xStaged): x2 => // propagate shape information for future references to x (Assign(x, y.p, _)): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => - StagedPath.mk(z.shapes, cde, "assign")(k(_, ctx)) + StagedPath(z.shapes, cde, "assign")(k(_, ctx)) def ruleLet(x: BlockMemberSymbol, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = shapeBot(): bot => transformSymbol(x): xSym => - StagedPath.mk(bot, xSym): y => + StagedPath(bot, xSym): y => (Assign(x, y.p, _)): given Context = ctx.clone() += x.asPath -> y transformBlock(b): (z, ctx) => blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => blockCtor("Assign", Ls(xSym, undefined, z.code)): cde => - StagedPath.mk(z.shapes, cde, "_let")(k(_, summon)) + StagedPath(z.shapes, cde, "_let")(k(_, summon)) def ruleEnd()(k: StagedPath => Block): Block = shapeBot(): sp => blockCtor("End", Ls()): cde => - StagedPath.mk(sp, cde, "end")(k) + StagedPath(sp, cde, "end")(k) def ruleBlk(b: Block)(using Context)(k: Path => Block): Block = transformBlock(b)(k apply _.code) def ruleCls(cls: ClsLikeDefn, rest: Block)(using Context)(k: Path => Block): Block = + assert(cls.companion.isEmpty, "nested module not supported") (Define(cls, _)): transformBlock(rest): p => transformSymbol(cls.sym): c => def stageParamList(ps: ParamList)(k: Path => Block) = ps.params.map(p => transformSymbol(p.sym)).collectApply(tuple(_)(k)) transformOption(cls.paramsOpt, stageParamList): paramsOpt => - assert(cls.companion.isEmpty, "nested module not supported") - optionNone(): none => + optionNone(): none => // TODO: companion object blockCtor("ClsLikeDefn", Ls(c, paramsOpt, none)): cls => blockCtor("Define", Ls(cls, p.code))(k) @@ -305,28 +305,28 @@ class InstrumentationImpl(using State): ruleWildCard(x, p, dflt): (dflt, ctx) => optionSome(dflt.code): dflt => blockCtor("Match", Ls(x.code, arms, dflt, e)): m => - StagedPath.mk(sp, m, "branches")(k(_, ctx)) + StagedPath(sp, m, "branches")(k(_, ctx)) case N => optionNone(): none => blockCtor("Match", Ls(x.code, arms, none, e)): m => - StagedPath.mk(sp, m, "branches")(k(_, ctx)) + StagedPath(sp, m, "branches")(k(_, ctx)) def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = transformCase(cse): cse => fnFilter(x.shapes, cse): sp => - StagedPath.mk(sp, x.code): x0 => + StagedPath(sp, x.code): x0 => call(x0.shapes.p.selSN("isEmpty"), Ls()): scrut => ruleEnd(): e => tuple(Ls(cse, e.code)): armStaged => // returns Case -> Block, instead of End as in formalization - StagedPath.mk(e.shapes, armStaged): badArm => + StagedPath(e.shapes, armStaged): badArm => val arm = Case.Lit(Tree.BoolLit(true)) -> k(badArm, ctx) (Match(scrut, Ls(arm), N, _)): given Context = ctx.clone() += p -> x0 transformBlock(b): (y1, ctx) => // TODO: use Arm type instead of Tup tuple(Ls(cse, y1.code)): cde => - StagedPath.mk(y1.shapes, cde, "branch")(k(_, ctx.clone() -= p)) + StagedPath(y1.shapes, cde, "branch")(k(_, ctx.clone() -= p)) // not in formalization // this partially applies rules from filter to account for difference in Block.Case and Match pattern in the formalization @@ -365,7 +365,7 @@ class InstrumentationImpl(using State): optionNone(): opt => transformPath(value): value => blockCtor("Arg", Ls(opt, value.code)): cde => - StagedPath.mk(value.shapes, cde)(k) + StagedPath(value.shapes, cde)(k) // provides list of shapes and list of codes to continuation def transformArgs(args: Ls[Arg])(using Context)(k: Ls[StagedPath] => Block): Block = From db7395d51dbc3990c4d8696dcfc0b1393d94aede Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 24 Nov 2025 23:24:41 +0800 Subject: [PATCH 162/268] clean up --- .../scala/hkmc2/codegen/Instrumentation.scala | 44 ++++++++----------- .../src/test/mlscript-compile/ShapeSet.mls | 4 +- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index fc98b9a5de..6b0d15f74c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -146,15 +146,8 @@ class InstrumentationImpl(using State): def transformSymbol[S <: Symbol](sym: S)(k: Path => Block): Block = sym match case clsSym: ClassSymbol => - clsSym.defn.get.paramsOpt match - case S(ps) => - ps.params.map(p => transformSymbol(p.sym)).collectApply: params => - tuple(params): params => - optionSome(params): paramsOpt => - blockCtor("ClassSymbol", Ls(toValue(sym.nme), paramsOpt))(k) - case N => - optionNone(): none => - blockCtor("ClassSymbol", Ls(toValue(sym.nme), none))(k) + stageParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => + blockCtor("ClassSymbol", Ls(toValue(sym.nme), paramsOpt))(k) case _ => blockCtor("Symbol", Ls(toValue(sym.nme)), "sym")(k) def transformOption[A](xOpt: Opt[A], f: A => (Path => Block) => Block)(k: Path => Block): Block = @@ -284,10 +277,8 @@ class InstrumentationImpl(using State): (Define(cls, _)): transformBlock(rest): p => transformSymbol(cls.sym): c => - def stageParamList(ps: ParamList)(k: Path => Block) = - ps.params.map(p => transformSymbol(p.sym)).collectApply(tuple(_)(k)) - transformOption(cls.paramsOpt, stageParamList): paramsOpt => - optionNone(): none => // TODO: companion object + stageParamsOpt(cls.paramsOpt): paramsOpt => + optionNone(): none => // TODO: handle companion object blockCtor("ClsLikeDefn", Ls(c, paramsOpt, none)): cls => blockCtor("Define", Ls(cls, p.code))(k) @@ -299,17 +290,14 @@ class InstrumentationImpl(using State): fnFlat(arms.map(_.shapes)): sp => tuple(arms.map(_.code)): arms => blockCtor("End", Ls()): e => - // unable to use transformOption here because ctx is changed here - dflt match - case S(dflt) => - ruleWildCard(x, p, dflt): (dflt, ctx) => - optionSome(dflt.code): dflt => - blockCtor("Match", Ls(x.code, arms, dflt, e)): m => - StagedPath(sp, m, "branches")(k(_, ctx)) - case N => - optionNone(): none => - blockCtor("Match", Ls(x.code, arms, none, e)): m => - StagedPath(sp, m, "branches")(k(_, ctx)) + // TODO: use transformOption here + def dfltStaged(k: (Path, Context) => Block) = dflt match + case S(dflt) => ruleWildCard(x, p, dflt): (dflt, ctx) => + optionSome(dflt.code)(k(_, ctx)) + case N => optionNone()(k(_, ctx)) + dfltStaged: (dflt, ctx) => + blockCtor("Match", Ls(x.code, arms, dflt, e)): m => + StagedPath(sp, m, "branches")(k(_, ctx)) def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = transformCase(cse): cse => @@ -371,6 +359,12 @@ class InstrumentationImpl(using State): def transformArgs(args: Ls[Arg])(using Context)(k: Ls[StagedPath] => Block): Block = args.map(transformArg).collectApply(k) + def stageParamList(ps: ParamList)(k: Path => Block) = + ps.params.map(p => transformSymbol(p.sym)).collectApply(tuple(_)(k)) + + def stageParamsOpt(pOpt: Opt[ParamList])(k: Path => Block) = + transformOption(pOpt, stageParamList)(k) + def transformCase(cse: Case)(using Context)(k: Path => Block): Block = cse match case Case.Lit(lit) => blockCtor("Lit", Ls(Value.Lit(lit)))(k) @@ -442,7 +436,7 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): val newCtor = impl.transformBlock(companion.ctor)(using new HashMap())(_ => End()) val newCompanion = companion.copy(methods = companion.methods ++ stagedMethods, ctor = newCtor) val newModule = c.copy(sym = sym, companion = S(newCompanion)) - // debug is printed without calling the instrumented function + // debug is printed after definition val debugBlock = debugPrintCode.foldRight(rest)(impl.concat) Define(newModule, debugBlock) case _ => d diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls index 1fef324ee2..ed97d00cb1 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -62,9 +62,9 @@ fun mkArr(shapes: Array[ShapeSet]) = |> liftMany fun mkClass(sym: ClassSymbol, params: Array[ShapeSet]) = - params.map((s, _, _) => s.underlying.values().toArray()) + params.map(_.underlying.values().toArray()) |> prod - .map((s, _, _) => Class(sym, s)) + .map(Class(sym, _)) |> liftMany // helper functions From af3f436620fb25fb72267b0990f283a764626102 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 24 Nov 2025 23:32:27 +0800 Subject: [PATCH 163/268] Revert "move functions" This reverts commit 1f5c8d7125c3735f3271e3551daac4bf75c0db53. --- .../src/test/mlscript-compile/Block.mls | 16 -------------- .../src/test/mlscript-compile/Shape.mls | 21 ++++++++++++++++--- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index a0756ec9d2..ea54c8b3f6 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -19,22 +19,6 @@ class ClassSymbol(val name: Str, val args: Opt[Array[Symbol]]) extends Symbol(na type Literal = null | undefined | Str | Int | Num | Bool -fun isPrimitiveType(sym: Symbol) = - if sym.name is - "Str" then true - "Int" then true - "Num" then true - "Bool" then true - else false - -fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = - if [sym.name, l] is - ["Str", l] and l is Str then true - ["Int", i] and i is Int then true - ["Num", n] and n is Num then true - ["Bool", b] and b is Bool then true - else false - type ParamList = Array[Symbol] // Classes defined in Block.scala diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index 9805553afc..223940c38c 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -1,12 +1,27 @@ import "./Block.mls" import "./Option.mls" -type Literal = null | undefined | Str | Int | Num | Bool - -open Block { ClassSymbol, showSymbol, isPrimitiveType, isPrimitiveTypeOf } +open Block { Literal, Symbol, ClassSymbol, showSymbol } open Option + type Shape = Shape.Shape +fun isPrimitiveType(sym: Symbol) = + if sym.name is + "Str" then true + "Int" then true + "Num" then true + "Bool" then true + else false + +fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = + if [sym.name, l] is + ["Str", l] and l is Str then true + ["Int", i] and i is Int then true + ["Num", n] and n is Num then true + ["Bool", b] and b is Bool then true + else false + module Shape with... class Shape with From 89f414ccc088878a6a35c81e465e440092d64c47 Mon Sep 17 00:00:00 2001 From: TYeung Date: Tue, 25 Nov 2025 18:03:47 +0800 Subject: [PATCH 164/268] update diff output --- .../src/test/mlscript/staging/Functions.mls | 95 ++++++++++++++++--- 1 file changed, 80 insertions(+), 15 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index cd00dea636..adbdc935e1 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -1,24 +1,88 @@ :js :staging -// :ssjs +:ssjs class B() staged module A with - fun f() = 1 - fun g() = - let x = 42 - let y = x - y - fun h() = - val x = 1 - x + // fun f() = 1 + // fun g() = + // let x = 42 + // let y = x + // y + // fun h() = + // val x = 1 + // x fun i() = [1, 2] - fun j() = new B() -//│ > Return(Lit(1), false) -//│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) -//│ > Define(ValDefn(Symbol("x"), Lit(1)), Return(Ref(Symbol("x")), false)) -//│ > Return(Tuple([Lit(1), Lit(2)]), false) -//│ > Return(Instantiate(Select(Ref(Symbol("B")), Symbol("class")), []), false) + // fun j() = new B() +//│ JS: +//│ B1 = function B(...args) { +//│ return globalThis.Object.freeze(new B.class(...args)); +//│ }; +//│ globalThis.Object.freeze(class B { +//│ static { +//│ B1.class = this +//│ } +//│ constructor() {} +//│ toString() { return runtime.render(this); } +//│ static [definitionMetadata] = ["class", "B", []]; +//│ }); +//│ globalThis.Object.freeze(class A { +//│ static { +//│ A1 = this +//│ } +//│ constructor() { +//│ runtime.Unit; +//│ } +//│ static i(...args) { +//│ runtime.checkArgs("i", 0, true, args.length); +//│ return globalThis.Object.freeze([ +//│ 1, +//│ 2 +//│ ]) +//│ } +//│ static i_gen(...args) { +//│ runtime.checkArgs("i_gen", 0, true, args.length); +//│ let tmp2, tmp3, lit, tmp4, tmp5, lit1, tmp6, tmp7, tmp8, tmp9, tup, tmp10, ret; +//│ tmp2 = globalThis.Object.freeze(new Shape.Lit(1)); +//│ tmp3 = globalThis.Object.freeze(new Block.ValueLit(1)); +//│ lit = globalThis.Object.freeze([ +//│ tmp2, +//│ tmp3 +//│ ]); +//│ tmp4 = globalThis.Object.freeze(new Shape.Lit(2)); +//│ tmp5 = globalThis.Object.freeze(new Block.ValueLit(2)); +//│ lit1 = globalThis.Object.freeze([ +//│ tmp4, +//│ tmp5 +//│ ]); +//│ tmp6 = globalThis.Object.freeze([ +//│ lit[0], +//│ lit1[0] +//│ ]); +//│ tmp7 = globalThis.Object.freeze(new Shape.Arr(tmp6)); +//│ tmp8 = globalThis.Object.freeze([ +//│ lit[1], +//│ lit1[1] +//│ ]); +//│ tmp9 = globalThis.Object.freeze(new Block.Tuple(tmp8)); +//│ tup = globalThis.Object.freeze([ +//│ tmp7, +//│ tmp9 +//│ ]); +//│ tmp10 = globalThis.Object.freeze(new Block.Return(tup[1])); +//│ ret = globalThis.Object.freeze([ +//│ tup[0], +//│ tmp10 +//│ ]); +//│ return ret +//│ } +//│ toString() { return runtime.render(this); } +//│ static [definitionMetadata] = ["class", "A"]; +//│ }); +//│ tmp = runtime.checkCall(A1.i_gen()); +//│ tmp1 = runtime.checkCall(Block.printCode(tmp[1])); +//│ block$res = undefined; +//│ > (,) // collision with class name? :js @@ -28,3 +92,4 @@ class A() staged module A with fun f() = 1 //│ ═══[RUNTIME ERROR] TypeError: A3.f_gen is not a function + From 6db62ea9eb7b0bc84dc75add1a2928e235becb99 Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 14:16:17 +0800 Subject: [PATCH 165/268] pass staged annotation in lowering --- hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala | 7 +++++-- hkmc2/shared/src/test/mlscript/staging/Syntax.mls | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index d4922ec4c2..23c1d0301a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -211,14 +211,17 @@ class Lowering()(using Config, TL, Raise, State, Ctx): mod.classCompanion match case S(comp) => comp.defn.getOrElse(wat("Module companion without definition", mod.companion)) case N => - ClassDef.Plain(mod.owner, syntax.Cls, new ClassSymbol(Tree.DummyTypeDef(syntax.Cls), mod.sym.id), + val clsSymb = new ClassSymbol(Tree.DummyTypeDef(syntax.Cls), mod.sym.id) + val newDefn = ClassDef.Plain(mod.owner, syntax.Cls, clsSymb, mod.bsym, Nil, N, ObjBody(Blk(Nil, UnitVal())), S(mod.sym), - Nil, + mod.annotations, ) + clsSymb.defn = S(newDefn) + newDefn case _ => _defn reportAnnotations(defn, defn.extraAnnotations) val bufferableAnnots = defn.annotations.flatMap: diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index 163193d6df..e5c4b86216 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -22,4 +22,4 @@ staged fun f() = 0 :slot staged module A //│ Pretty Lowered: -//│ define class A in set block$res1 = undefined in end +//│ define staged class A in set block$res1 = undefined in end From c1f00e8b86832f9749c5022a72999825d35b521d Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 26 Nov 2025 15:26:51 +0800 Subject: [PATCH 166/268] Revert "patch in instrumentation" This reverts commit 3c4faec660df12baae4a93f8abdb958c1034007e. --- .../main/scala/hkmc2/codegen/Instrumentation.scala | 2 +- hkmc2/shared/src/test/mlscript/staging/Functions.mls | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 6b0d15f74c..b51c61ed37 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -427,7 +427,7 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): case d @ Define(defn, rest) => defn match // find modules with staged annotation - case c: ClsLikeDefn if c.companion.isDefined => + case c: ClsLikeDefn if c.companion.exists(_.isym.defn.exists(_.hasStagedModifier.isDefined)) => val sym = c.sym.subst val companion = c.companion.get val (stagedMethods, debugPrintCode) = companion.methods diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index a60188442e..cd244ddb9f 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -48,7 +48,7 @@ staged module ClassInstrumentation with //│ > Class(ClassSymbol("NoArg"), []) //│ > Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), Symbol("NoArg")), []), false) -// collision with class name? +// debug printing fails, collision with class name? :js :staging :fixme @@ -57,11 +57,17 @@ staged module A with fun f() = 1 //│ ═══[RUNTIME ERROR] TypeError: A1.f_gen is not a function -// unable to reference the class when calling the instrumented function for debugging +// debug printing fails, unable to reference the class when calling the instrumented function :js :staging :fixme module A with staged module B with fun f() = 1 -//│ /!!!\ Uncaught error: java.lang.AssertionError: assertion failed: nested module not supported +//│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' +//│ ╟── which references the symbol introduced here +//│ ║ l.65: staged module B with +//│ ║ ^^^^^^ +//│ ║ l.66: fun f() = 1 +//│ ╙── ^^^^^^^^^^^^^^^ +//│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From 143ce9bf38b550f9f139c6ad17d42510355eb47f Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 25 Nov 2025 00:28:50 +0800 Subject: [PATCH 167/268] rename functions --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index b51c61ed37..267b264025 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -146,7 +146,7 @@ class InstrumentationImpl(using State): def transformSymbol[S <: Symbol](sym: S)(k: Path => Block): Block = sym match case clsSym: ClassSymbol => - stageParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => + transformParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => blockCtor("ClassSymbol", Ls(toValue(sym.nme), paramsOpt))(k) case _ => blockCtor("Symbol", Ls(toValue(sym.nme)), "sym")(k) @@ -277,7 +277,7 @@ class InstrumentationImpl(using State): (Define(cls, _)): transformBlock(rest): p => transformSymbol(cls.sym): c => - stageParamsOpt(cls.paramsOpt): paramsOpt => + transformParamsOpt(cls.paramsOpt): paramsOpt => optionNone(): none => // TODO: handle companion object blockCtor("ClsLikeDefn", Ls(c, paramsOpt, none)): cls => blockCtor("Define", Ls(cls, p.code))(k) @@ -359,11 +359,11 @@ class InstrumentationImpl(using State): def transformArgs(args: Ls[Arg])(using Context)(k: Ls[StagedPath] => Block): Block = args.map(transformArg).collectApply(k) - def stageParamList(ps: ParamList)(k: Path => Block) = + def transformParamList(ps: ParamList)(k: Path => Block) = ps.params.map(p => transformSymbol(p.sym)).collectApply(tuple(_)(k)) - def stageParamsOpt(pOpt: Opt[ParamList])(k: Path => Block) = - transformOption(pOpt, stageParamList)(k) + def transformParamsOpt(pOpt: Opt[ParamList])(k: Path => Block) = + transformOption(pOpt, transformParamList)(k) def transformCase(cse: Case)(using Context)(k: Path => Block): Block = cse match From fcbe8c91dc9e35930169a55da4aa9e744133336e Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 25 Nov 2025 00:30:38 +0800 Subject: [PATCH 168/268] add debug information to rules --- .../scala/hkmc2/codegen/Instrumentation.scala | 97 +++++++++---------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 267b264025..556ff88f69 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -157,78 +157,77 @@ class InstrumentationImpl(using State): // instrumentation rules - def ruleLit(l: Value.Lit)(k: StagedPath => Block): Block = + def ruleLit(l: Value.Lit, symName: String = "lit")(k: StagedPath => Block): Block = shapeLit(l): sp => blockCtor("ValueLit", Ls(l)): cde => - StagedPath(sp, cde, "lit")(k) + StagedPath(sp, cde, symName)(k) // not in formalization - def ruleVar(r: Value.Ref)(k: StagedPath => Block): Block = + def ruleVar(r: Value.Ref, symName: String = "var")(k: StagedPath => Block): Block = val Value.Ref(l, disamb) = r transformSymbol(disamb.getOrElse(l)): sym => blockCtor("ValueRef", Ls(sym)): cde => // variable defined outside of scope, may be a reference to a class shapeDyn(): sp => - StagedPath(sp, cde, "var")(k) + StagedPath(sp, cde, symName)(k) - def ruleTup(t: Tuple)(using Context)(k: StagedPath => Block): Block = + def ruleTup(t: Tuple, symName: String = "tup")(using Context)(k: StagedPath => Block): Block = assert(!t.mut, "mutable tuple not supported") transformArgs(t.elems): xs => shapeArr(xs.map(_.shapes)): sp => tuple(xs.map(_.code)): codes => blockCtor("Tuple", Ls(codes)): cde => - StagedPath(sp, cde, "tup")(k) + StagedPath(sp, cde, symName)(k) - def ruleSel(s: Select)(using Context)(k: StagedPath => Block): Block = + def ruleSel(s: Select, symName: String = "sel")(using Context)(k: StagedPath => Block): Block = val Select(p, i @ Tree.Ident(name)) = s transformPath(p): x => shapeLit(toValue(name)): n => fnSel(x.shapes, n): sp => blockCtor("Symbol", Ls(toValue(name))): name => blockCtor("Select", Ls(x.code, name)): cde => - StagedPath(sp, cde, "sel")(k) + StagedPath(sp, cde, symName)(k) - def ruleDynSel(d: DynSelect)(using Context)(k: StagedPath => Block): Block = + def ruleDynSel(d: DynSelect, symName: String = "dynsel")(using Context)(k: StagedPath => Block): Block = transformPath(d.qual): x => transformPath(d.fld): y => fnSel(x.shapes, y.shapes): sp => blockCtor("DynSelect", Ls(x.code, y.code, toValue(d.arrayIdx))): cde => - StagedPath(sp, cde, "dynsel")(k) + StagedPath(sp, cde, symName)(k) - def ruleInst(i: Instantiate)(using Context)(k: StagedPath => Block): Block = + def ruleInst(i: Instantiate, symName: String = "inst")(using Context)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i assert(!mut, "mutable instantiation not supported") transformArgs(args): xs => - tuple(xs.map(_.shapes)): shapes => - val sym = cls match - // TODO: if class is staged, we can just use Symbol without storing the arguments - case Value.Ref(l, S(disamb)) => transformSymbol(disamb) - case s: Select if s.symbol.isDefined => transformSymbol(s.symbol.get) - case _ => transformSymbol(TempSymbol(N, "TODO")) - sym: sym => - shapeClass(sym, xs.map(_.shapes)): sp => - // reuse instrumentation logic, shape of cls is discarded - // possible to skip this? this uses ruleVar, which is not in formalization - transformPath(cls): cls => - tuple(xs.map(_.code)): codes => - blockCtor("Instantiate", Ls(cls.code, codes)): cde => - StagedPath(sp, cde, "inst")(k) - - def ruleReturn(r: Return)(using Context)(k: (StagedPath, Context) => Block): Block = + val sym = cls match + // TODO: if class is staged, we can just use Symbol without storing the arguments + case Value.Ref(l, S(disamb)) => transformSymbol(disamb) + case s: Select if s.symbol.isDefined => transformSymbol(s.symbol.get) + case _ => transformSymbol(TempSymbol(N, "TODO")) + sym: sym => + shapeClass(sym, xs.map(_.shapes)): sp => + // reuse instrumentation logic, shape of cls is discarded + // possible to skip this? this uses ruleVar, which is not in formalization + transformPath(cls): cls => + tuple(xs.map(_.code)): codes => + blockCtor("Instantiate", Ls(cls.code, codes)): cde => + StagedPath(sp, cde, symName)(k) + + def ruleReturn(r: Return, symName: String = "return")(using Context)(k: (StagedPath, Context) => Block): Block = transformResult(r.res): x => blockCtor("Return", Ls(x.code, toValue(false))): cde => - StagedPath(x.shapes, cde, "return")(k(_, summon)) + StagedPath(x.shapes, cde, symName)(k(_, summon)) - def ruleMatch(m: Match)(using Context)(k: (StagedPath, Context) => Block): Block = + def ruleMatch(m: Match, symName: String = "match")(using Context)(k: (StagedPath, Context) => Block): Block = val Match(p, ks, dflt, rest) = m transformPath(p): x => ruleBranches(x, p, ks, dflt): (stagedMatch, ctx1) => transformBlock(rest)(using ctx1): (z, ctx2) => fnMrg(stagedMatch.shapes, z.shapes): sp => fnConcat(stagedMatch.code, z.code): cde => - StagedPath(sp, cde)(k(_, ctx2)) + StagedPath(sp, cde, symName)(k(_, ctx2)) - def ruleAssign(a: Assign)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def ruleAssign(a: Assign, symName: String = "assign")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Assign(x, r, b) = a transformResult(r): y => transformSymbol(x): xSym => @@ -243,7 +242,7 @@ class InstrumentationImpl(using State): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => - StagedPath(z.shapes, cde, "assign")(k(_, ctx)) + StagedPath(z.shapes, cde, symName)(k(_, ctx)) case N => StagedPath(y.shapes, xStaged): x2 => // propagate shape information for future references to x @@ -251,9 +250,9 @@ class InstrumentationImpl(using State): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => - StagedPath(z.shapes, cde, "assign")(k(_, ctx)) + StagedPath(z.shapes, cde, symName)(k(_, ctx)) - def ruleLet(x: BlockMemberSymbol, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def ruleLet(x: BlockMemberSymbol, b: Block, symName: String = "_let")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = shapeBot(): bot => transformSymbol(x): xSym => StagedPath(bot, xSym): y => @@ -262,12 +261,12 @@ class InstrumentationImpl(using State): transformBlock(b): (z, ctx) => blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => blockCtor("Assign", Ls(xSym, undefined, z.code)): cde => - StagedPath(z.shapes, cde, "_let")(k(_, summon)) + StagedPath(z.shapes, cde, symName)(k(_, summon)) - def ruleEnd()(k: StagedPath => Block): Block = + def ruleEnd(symName: String = "inst")(k: StagedPath => Block): Block = shapeBot(): sp => blockCtor("End", Ls()): cde => - StagedPath(sp, cde, "end")(k) + StagedPath(sp, cde, symName)(k) def ruleBlk(b: Block)(using Context)(k: Path => Block): Block = transformBlock(b)(k apply _.code) @@ -282,7 +281,7 @@ class InstrumentationImpl(using State): blockCtor("ClsLikeDefn", Ls(c, paramsOpt, none)): cls => blockCtor("Define", Ls(cls, p.code))(k) - def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block])(using Context)(k: (StagedPath, Context) => Block): Block = + def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block], symName: String = "branches")(using Context)(k: (StagedPath, Context) => Block): Block = arms.map((cse, block) => (f: StagedPath => Context => Block) => (ruleBranch(x, p, cse, block)(using _)).flip(f(_)(_))) .collectApply .pipe(_.flip(summon)): arms => @@ -297,24 +296,24 @@ class InstrumentationImpl(using State): case N => optionNone()(k(_, ctx)) dfltStaged: (dflt, ctx) => blockCtor("Match", Ls(x.code, arms, dflt, e)): m => - StagedPath(sp, m, "branches")(k(_, ctx)) + StagedPath(sp, m, symName)(k(_, ctx)) - def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block, symName: String = "branch")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = transformCase(cse): cse => fnFilter(x.shapes, cse): sp => - StagedPath(sp, x.code): x0 => - call(x0.shapes.p.selSN("isEmpty"), Ls()): scrut => - ruleEnd(): e => - tuple(Ls(cse, e.code)): armStaged => - // returns Case -> Block, instead of End as in formalization - StagedPath(e.shapes, armStaged): badArm => - val arm = Case.Lit(Tree.BoolLit(true)) -> k(badArm, ctx) - (Match(scrut, Ls(arm), N, _)): + call(sp.p.selSN("isEmpty"), Ls()): scrut => + ruleEnd(): e => + tuple(Ls(cse, e.code)): armStaged => + // returns Case -> Block, instead of End as in formalization + StagedPath(e.shapes, armStaged): badArm => + val arm = Case.Lit(Tree.BoolLit(true)) -> k(badArm, ctx) + (Match(scrut, Ls(arm), N, _)): + StagedPath(sp, x.code): x0 => given Context = ctx.clone() += p -> x0 transformBlock(b): (y1, ctx) => // TODO: use Arm type instead of Tup tuple(Ls(cse, y1.code)): cde => - StagedPath(y1.shapes, cde, "branch")(k(_, ctx.clone() -= p)) + StagedPath(y1.shapes, cde, symName)(k(_, ctx.clone() -= p)) // not in formalization // this partially applies rules from filter to account for difference in Block.Case and Match pattern in the formalization From 87b545798b0c9ccab9e428957a5e4a492bdbb4bc Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 25 Nov 2025 10:25:58 +0800 Subject: [PATCH 169/268] move paramsOpt into ClassSymbol --- .../scala/hkmc2/codegen/Instrumentation.scala | 6 ++--- .../src/test/mlscript-compile/Block.mls | 27 ++++++++----------- .../src/test/mlscript/staging/Functions.mls | 6 ++--- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 556ff88f69..33c7827081 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -275,10 +275,10 @@ class InstrumentationImpl(using State): assert(cls.companion.isEmpty, "nested module not supported") (Define(cls, _)): transformBlock(rest): p => - transformSymbol(cls.sym): c => - transformParamsOpt(cls.paramsOpt): paramsOpt => + transformParamsOpt(cls.paramsOpt): paramsOpt => + transformSymbol(cls.isym): c => optionNone(): none => // TODO: handle companion object - blockCtor("ClsLikeDefn", Ls(c, paramsOpt, none)): cls => + blockCtor("ClsLikeDefn", Ls(c, none)): cls => blockCtor("Define", Ls(cls, p.code))(k) def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block], symName: String = "branches")(using Context)(k: (StagedPath, Context) => Block): Block = diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index ea54c8b3f6..356f1da481 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -12,15 +12,15 @@ type Opt[A] = Option[A] // dependancies referenced in Block classes, referencing implementation in Term.mls -class Symbol(val name: Str) -type Ident = Symbol -// this is so that we're able to retrieve information about the class from the symbol -class ClassSymbol(val name: Str, val args: Opt[Array[Symbol]]) extends Symbol(name) - type Literal = null | undefined | Str | Int | Num | Bool type ParamList = Array[Symbol] +class Symbol(val name: Str) +type Ident = Symbol +// this is so that we're able to retrieve information about the class from the symbol +class ClassSymbol(val name: Str, val paramsOpt: Opt[ParamList]) extends Symbol(name) + // Classes defined in Block.scala class Arg(val spread: Opt[Bool], val value: Path) @@ -47,7 +47,7 @@ class Path extends Result with class Defn with constructor ValDefn(val sym: Symbol, val rhs: Path) - ClsLikeDefn(val sym: Symbol, val paramsOpt: Opt[ParamList], val companion: Opt[ClsLikeBody]) // unused + ClsLikeDefn(val sym: Symbol, val companion: Opt[ClsLikeBody]) // companion unused FunDefn(val sym: Symbol, val params: Array[ParamList], val body: Block) class ClsLikeBody(val isym: Symbol, val methods: Array[FunDefn], val publicFields: Array[[Symbol, Symbol]]) // unused @@ -78,10 +78,10 @@ fun showLiteral(l: Literal) = fun showSymbol(s: Symbol) = // console.log("printing " + s) if s is - ClassSymbol(name, args) then + ClassSymbol(name, paramsOpt) then "ClassSymbol(" + "\"" + name + "\"" + - if args - is Some(args) then ":[" + args.map(showSymbol).join(", ") + "]" + if paramsOpt + is Some(paramsOpt) then ":[" + paramsOpt.map(showSymbol).join(", ") + "]" is None then "" + ")" _ then "Symbol(" + "\"" + s.name + "\"" + ")" @@ -131,14 +131,9 @@ fun showDefn(d: Defn): Str = "FunDefn(" + showSymbol(sym) + ", " + showParamList(params) + ", " + showBlock(body) + ")" - ClsLikeDefn(sym, paramsOpt, companion) then + ClsLikeDefn(sym, companion) then // TODO: print rest of the arguments - "ClsLikeDefn(" + showSymbol(sym) + ", " + - if paramsOpt is - Some(params) then "(" + showParamList(params) + ")" - None then "()" - + ", " + - "TODO" + ")" + "ClsLikeDefn(" + showSymbol(sym) + ", " + "TODO" + ")" fun showOptBlock(ob: Opt[Block]) = if ob is Some(b) then showBlock(b) else "None" diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index cd244ddb9f..ed8152c15b 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -37,12 +37,12 @@ staged module Expressions with :staging class Outside(a) staged module ClassInstrumentation with - class Class(a, b) + class Inside(a, b) class NoArg fun inst1() = new Outside(1) fun inst2() = new NoArg -//│ > Define(ClsLikeDefn(Symbol("NoArg"), (), TODO), End) -//│ > Define(ClsLikeDefn(Symbol("Class"), ([Symbol("a"), Symbol("b")]), TODO), End) +//│ > Define(ClsLikeDefn(ClassSymbol("NoArg"), TODO), End) +//│ > Define(ClsLikeDefn(ClassSymbol("Inside":[Symbol("a"), Symbol("b")]), TODO), End) //│ > Class(ClassSymbol("Outside":[Symbol("a")]), [Lit(1)]) //│ > Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) //│ > Class(ClassSymbol("NoArg"), []) From 67a099c9dfa95d067e2ce3f0a8ad40899d751928 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 26 Nov 2025 13:36:32 +0800 Subject: [PATCH 170/268] implement pruning of bad arms from Match statement --- .../scala/hkmc2/codegen/Instrumentation.scala | 39 +++++++++---------- .../src/test/mlscript-compile/Block.mls | 5 ++- .../src/test/mlscript-compile/ShapeSet.mls | 6 +++ .../src/test/mlscript/staging/Functions.mls | 2 +- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 33c7827081..ebb6cc5034 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -129,6 +129,8 @@ class InstrumentationImpl(using State): def fnConcat(p1: Path, p2: Path)(k: Path => Block): Block = blockCall("concat", Ls(p1, p2))(k) + def fnPruneBadArms(arms: Path)(k: Path => Block): Block = + shapeSetCall("pruneBadArms", Ls(arms))(k) def fnMrg(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = shapeSetCall("mrg", Ls(s1, s2))(s => k(ShapeSet(s))) def fnSel(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = @@ -137,9 +139,6 @@ class InstrumentationImpl(using State): shapeSetCall("filter", Ls(s1, s2))(s => k(ShapeSet(s))) def fnUnion(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = shapeSetCall("union", Ls(s1, s2))(s => k(ShapeSet(s))) - def fnFlat(s: Ls[ShapeSet])(k: ShapeSet => Block): Block = - tuple(s): tup => - shapeSetCall("flat", Ls(tup))(s => k(ShapeSet(s))) // transformation helpers @@ -286,8 +285,11 @@ class InstrumentationImpl(using State): .collectApply .pipe(_.flip(summon)): arms => ctx => - fnFlat(arms.map(_.shapes)): sp => - tuple(arms.map(_.code)): arms => + tuple(arms.map(_.p)): tup => + fnPruneBadArms(tup): res => + val result = StagedPath(res) + val sp = result.shapes + val arms = result.code blockCtor("End", Ls()): e => // TODO: use transformOption here def dfltStaged(k: (Path, Context) => Block) = dflt match @@ -303,23 +305,18 @@ class InstrumentationImpl(using State): fnFilter(x.shapes, cse): sp => call(sp.p.selSN("isEmpty"), Ls()): scrut => ruleEnd(): e => - tuple(Ls(cse, e.code)): armStaged => - // returns Case -> Block, instead of End as in formalization - StagedPath(e.shapes, armStaged): badArm => - val arm = Case.Lit(Tree.BoolLit(true)) -> k(badArm, ctx) - (Match(scrut, Ls(arm), N, _)): - StagedPath(sp, x.code): x0 => - given Context = ctx.clone() += p -> x0 - transformBlock(b): (y1, ctx) => - // TODO: use Arm type instead of Tup - tuple(Ls(cse, y1.code)): cde => - StagedPath(y1.shapes, cde, symName)(k(_, ctx.clone() -= p)) - - // not in formalization - // this partially applies rules from filter to account for difference in Block.Case and Match pattern in the formalization - // to avoid defining the `_` pattern in Block.Case, we use the fact that filter(s, _) = s + val arm = Case.Lit(Tree.BoolLit(true)) -> k(e, ctx) + (Match(scrut, Ls(arm), N, _)): + StagedPath(sp, x.code): x0 => + given Context = ctx.clone() += p -> x0 + transformBlock(b): (y1, ctx) => + // TODO: use Arm type instead of Tup + tuple(Ls(cse, y1.code)): cde => + StagedPath(y1.shapes, cde, symName)(k(_, ctx.clone() -= p)) + + // this partially applies rules from filter to account for difference between Block.Case and Match pattern in the formalization + // to avoid defining the `_` pattern in Block.Case, we apply filter(s, _) = s def ruleWildCard(x: StagedPath, p: Path, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = - // when pattern = _, x0 = x call(x.shapes.p.selSN("isEmpty"), Ls()): scrut => val arm = Case.Lit(Tree.BoolLit(true)) -> ruleEnd()(p => Return(p.p, false)) (Match(scrut, Ls(arm), N, _)): diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 356f1da481..85e0ce45ad 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -29,7 +29,7 @@ class Case with constructor Lit(val lit: Literal) Cls(val cls: Symbol, val path: Path) - Tup(val len: Int) // TODO: remove inf? + Tup(val len: Int) class Result with constructor @@ -158,6 +158,7 @@ fun showBlock(b: Block): Str = End() then "End" fun show(x) = + // console.log("debug block: " + x) if x is Symbol then showSymbol(x) Path then showPath(x) @@ -166,7 +167,7 @@ fun show(x) = Defn then showDefn(x) Block then showBlock(x) else - "" + "" fun printCode(x) = print(show(x)) diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls index ed97d00cb1..7ed0f5c60e 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -78,3 +78,9 @@ fun sel(s1: ShapeSet, s2: ShapeSet) = fun mrg(s1: ShapeSet, s2: ShapeSet) = mkDyn() // TODO + +open Block { Block } + +fun pruneBadArms(arms: Array[[ShapeSet, Block]]) = + val rem = arms.filter(arm => not (arm.0.isEmpty() and arm.1 is End)) + [flat(rem.map(_.0)), rem.map(_.1)] diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index ed8152c15b..b24202260e 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -31,7 +31,7 @@ staged module Expressions with //│ > Lit(1) //│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) //│ > Dyn -//│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Lit(8) -> End, Lit(9) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false), Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> End], Return(Lit(0), false), End)) +//│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Lit(9) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End)) :js :staging From 9f148afb071cdc519c580666b7bc0d2b1fa9c4d8 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 26 Nov 2025 14:59:32 +0800 Subject: [PATCH 171/268] add debug name to transformSymbol --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index ebb6cc5034..53d689afb3 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -142,12 +142,12 @@ class InstrumentationImpl(using State): // transformation helpers - def transformSymbol[S <: Symbol](sym: S)(k: Path => Block): Block = + def transformSymbol[S <: Symbol](sym: S, symName: Str = "sym")(k: Path => Block): Block = sym match case clsSym: ClassSymbol => transformParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => - blockCtor("ClassSymbol", Ls(toValue(sym.nme), paramsOpt))(k) - case _ => blockCtor("Symbol", Ls(toValue(sym.nme)), "sym")(k) + blockCtor("ClassSymbol", Ls(toValue(sym.nme), paramsOpt), symName)(k) + case _ => blockCtor("Symbol", Ls(toValue(sym.nme)), symName)(k) def transformOption[A](xOpt: Opt[A], f: A => (Path => Block) => Block)(k: Path => Block): Block = xOpt match From cd26ae105d32f595eaa2c75c5316eab4eb4873dd Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 26 Nov 2025 15:08:24 +0800 Subject: [PATCH 172/268] remove code duplication from ruleBranch --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 53d689afb3..7d4ec0dcaf 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -305,14 +305,18 @@ class InstrumentationImpl(using State): fnFilter(x.shapes, cse): sp => call(sp.p.selSN("isEmpty"), Ls()): scrut => ruleEnd(): e => - val arm = Case.Lit(Tree.BoolLit(true)) -> k(e, ctx) - (Match(scrut, Ls(arm), N, _)): + val res = new TempSymbol(N, "tmp") + val arm = Case.Lit(Tree.BoolLit(true)) -> Assign(res, e.p, End()) + val dflt = StagedPath(sp, x.code): x0 => given Context = ctx.clone() += p -> x0 transformBlock(b): (y1, ctx) => // TODO: use Arm type instead of Tup tuple(Ls(cse, y1.code)): cde => - StagedPath(y1.shapes, cde, symName)(k(_, ctx.clone() -= p)) + StagedPath(y1.shapes, cde, symName): ret => + Assign(res, ret.p, End()) + (Match(scrut, Ls(arm), S(dflt), _)): + k(StagedPath(Value.Ref(res)), ctx.clone() -= p) // this partially applies rules from filter to account for difference between Block.Case and Match pattern in the formalization // to avoid defining the `_` pattern in Block.Case, we apply filter(s, _) = s From 2b5b30a5697024ed9581fb2ded3e981a3e050390 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 26 Nov 2025 15:09:16 +0800 Subject: [PATCH 173/268] fix typo --- hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 7d4ec0dcaf..f6ffb6fde5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -262,7 +262,7 @@ class InstrumentationImpl(using State): blockCtor("Assign", Ls(xSym, undefined, z.code)): cde => StagedPath(z.shapes, cde, symName)(k(_, summon)) - def ruleEnd(symName: String = "inst")(k: StagedPath => Block): Block = + def ruleEnd(symName: String = "end")(k: StagedPath => Block): Block = shapeBot(): sp => blockCtor("End", Ls()): cde => StagedPath(sp, cde, symName)(k) From 5d63091e0d1e91de74d0601fc8bf2ad5155f2c59 Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 18:09:30 +0800 Subject: [PATCH 174/268] update pretty printing to print actual mlscript --- .../src/test/mlscript-compile/Block.mls | 175 +++++++----------- .../src/test/mlscript/staging/PrintCode.mls | 41 +++- 2 files changed, 108 insertions(+), 108 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index ea54c8b3f6..e6e4906d4b 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -1,9 +1,6 @@ -import "./Predef.mls" import "./Option.mls" import "./StrOps.mls" -open Predef -open StrOps open Option module Block with... @@ -21,10 +18,8 @@ type Literal = null | undefined | Str | Int | Num | Bool type ParamList = Array[Symbol] -// Classes defined in Block.scala - -class Arg(val spread: Opt[Bool], val value: Path) - +class Arg(val spread: Opt[Bool], val value: Path) + class Case with constructor Lit(val lit: Literal) @@ -48,18 +43,20 @@ class Defn with constructor ValDefn(val sym: Symbol, val rhs: Path) ClsLikeDefn(val sym: Symbol, val paramsOpt: Opt[ParamList], val companion: Opt[ClsLikeBody]) // unused - FunDefn(val sym: Symbol, val params: Array[ParamList], val body: Block) + FunDefn(val sym: Symbol, val params: ParamList, val body: Block, val stage: Bool) class ClsLikeBody(val isym: Symbol, val methods: Array[FunDefn], val publicFields: Array[[Symbol, Symbol]]) // unused +class Arm(val cse: Case, val body: Block) + class Block with constructor - Match(val scrut: Path, val arms: Array[[Case, Block]], val dflt: Opt[Block], val rest: Block) + Match(val scrut: Path, val arms: Array[Arm], val dflt: Opt[Block], val rest: Block) Return(val res: Result, val implct: Bool) Assign(val lhs: Symbol, val rhs: Result, val rest: Block) Define(val defn: Defn, val rest: Block) End() - + fun concat(b1: Block, b2: Block) = if b1 is Match(scrut, arms, dflt, rest) then Match(scrut, arms, dflt, concat(rest, b2)) Return(res, implct) then b2 // discard return? @@ -67,112 +64,78 @@ fun concat(b1: Block, b2: Block) = if b1 is Define(defn, rest) then Define(defn, concat(rest, b2)) End() then b2 -fun showBool(b: Bool) = if b then "true" else "false" +fun showSymbol(s) = s.name -fun showLiteral(l: Literal) = +fun showLiteral(l) = if l is undefined then "undefined" - null then "null" - else l.toString() - -fun showSymbol(s: Symbol) = - // console.log("printing " + s) - if s is - ClassSymbol(name, args) then - "ClassSymbol(" + "\"" + name + "\"" + - if args - is Some(args) then ":[" + args.map(showSymbol).join(", ") + "]" - is None then "" - + ")" - _ then "Symbol(" + "\"" + s.name + "\"" + ")" - -fun showIdent(i: Ident) = showSymbol(i) - -fun showPath(p: Path): Str = + _ then l.toString() + +fun showPath(p) = if p is - Select(qual, name) then - "Select(" + showPath(qual) + ", " + showIdent(name) + ")" - DynSelect(qual, fld, arrayIdx) then - "DynSelect(" + showPath(qual) + ", " + showPath(fld) + ", " + showBool(arrayIdx) + ")" - ValueRef(l) then - "Ref(" + showSymbol(l) + ")" - ValueLit(lit) then - "Lit(" + showLiteral(lit) + ")" - -fun showArg(arg: Arg) = - if arg.spread is Some(true) then "..." + showPath(arg.value) - else showPath(arg.value) - -fun showArgs(args: Array[Arg]) = - "[" + args.map(showArg).join(", ") + "]" - -// Case (match arm patterns) -fun showCase(c: Case): Str = - if c is - Lit(lit) then "Lit(" + showLiteral(lit) + ")" - Cls(cls, path) then "Cls(" + showSymbol(cls) + ", " + showPath(path) + ")" - Tup(len) then "Tup(" + len + ")" + Select(qual, name) then showPath(qual) + "." + showSymbol(name) + DynSelect(qual, fld, idx) then showPath(qual) + "[" + showPath(fld) + "]" + ValueRef(s) then showSymbol(s) + ValueLit(l) then showLiteral(l) + _ then "" -fun showResult(r: Result): Str = +fun showArg(a) = + (if a.spread is Some(true) then "..." else "") + showPath(a.value) + +fun showArgs(args) = + args.map(showArg) + +fun showResult(r) = if r is + Call(f, args) then showPath(f) + "(" + showArgs(args) + ")" + Instantiate(cls, args) then "new " + showPath(cls) + "(" + showArgs(args) + ")" + Tuple(elems) then "[" + showArgs(elems) + "]" Path then showPath(r) - Call(f, args) then "Call(" + showPath(f) + ", " + showArgs(args) + ")" - Instantiate(cls, args) then "Instantiate(" + showPath(cls) + ", " + showArgs(args) + ")" - Tuple(elems) then "Tuple(" + showArgs(elems) + ")" -fun showParamList(ps: ParamList) = - "[" + ps.map(s => showSymbol(s)).join(", ") + "]" +fun showCase(c) = + if c is + Lit(l) then showLiteral(l) + Cls(cls, p) then showSymbol(cls) + "(" + showPath(p) + ")" + Tup(len) then "Tuple" + _ then "_" + +fun showArm(a) = + showCase(a.cse) + " then " + showBlock(a.body) + +fun showParamsOpt(p) = + if p is + Some(s) then showParams(s) + None then "()" + +fun showParams(p: ParamList) = + "(" + p.map(showSymbol).join(", ") + ")" -fun showDefn(d: Defn): Str = +fun showDefn(d) = if d is ValDefn(sym, rhs) then - "ValDefn(" + showSymbol(sym) + ", " + showPath(rhs) + ")" - FunDefn(sym, params, body) then - "FunDefn(" + showSymbol(sym) + ", " + - showParamList(params) + ", " + - showBlock(body) + ")" - ClsLikeDefn(sym, paramsOpt, companion) then - // TODO: print rest of the arguments - "ClsLikeDefn(" + showSymbol(sym) + ", " + - if paramsOpt is - Some(params) then "(" + showParamList(params) + ")" - None then "()" - + ", " + - "TODO" + ")" - -fun showOptBlock(ob: Opt[Block]) = - if ob is Some(b) then showBlock(b) else "None" - -fun showArm(pair: Case -> Block) = - if pair is [cse, body] then showCase(cse) + " -> " + showBlock(body) else "" - -fun showBlock(b: Block): Str = + "let " + showSymbol(sym) + " = " + showPath(rhs) + FunDefn(sym, params, body, stage) then + "fun " + showSymbol(sym) + "(" + params.map(showSymbol) + ") =" + + (if body is Return(_, _) then " " else "\n ") + showBlock(body) + ClsLikeDefn(sym, paramsOpt, _) then + "class " + showSymbol(sym) + showParamsOpt(paramsOpt) + +fun showBlock(b) = if b is + Assign(lhs, rhs, rest) then + "let " + showSymbol(lhs) + " = " + showResult(rhs) + "\n" + showBlock(rest) + Define(d, rest) then + showDefn(d) + "\n" + showBlock(rest) + Return(res, _) then + showResult(res) Match(scrut, arms, dflt, rest) then - "Match(" + - showPath(scrut) + ", " + - "[" + arms.map(showArm).join(", ") + "], " + - showOptBlock(dflt) + ", " + - showBlock(rest) + ")" - Return(res, implct) then - "Return(" + showResult(res) + ", " + showBool(implct) + ")" - Assign(lhs, rhs, rest) then - "Assign(" + showSymbol(lhs) + ", " + showResult(rhs) + ", " + showBlock(rest) + ")" - Define(defn, rest) then - "Define(" + showDefn(defn) + ", " + showBlock(rest) + ")" - End() then "End" - -fun show(x) = - if x is - Symbol then showSymbol(x) - Path then showPath(x) - Result then showResult(x) - Case then showCase(x) - Defn then showDefn(x) - Block then showBlock(x) - else - "" - -fun printCode(x) = print(show(x)) - -fun compile(p: Block) = ??? \ No newline at end of file + "if " + showPath(scrut) + " is\n" + + arms.map(showArm).join("\n") + + (if dflt is Some(db) then "\nelse " + showBlock(db) else "") + + "\n" + showBlock(rest) + End() then "" + x then x + +fun printCode(p: Block) = + let s = showBlock(p) in + console.log(s) diff --git a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls index 21e4d1e5aa..a907b98bc4 100644 --- a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls +++ b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls @@ -3,6 +3,7 @@ //│ Block = class Block { //│ Symbol: fun Symbol { class: class Symbol }, +//│ ClassSymbol: fun ClassSymbol { class: class ClassSymbol }, //│ Arg: fun Arg { class: class Arg }, //│ Case: class Case, //│ Lit: fun Lit { class: class Lit }, @@ -22,6 +23,7 @@ //│ ClsLikeDefn: fun ClsLikeDefn { class: class ClsLikeDefn }, //│ FunDefn: fun FunDefn { class: class FunDefn }, //│ ClsLikeBody: fun ClsLikeBody { class: class ClsLikeBody }, +//│ Arm: fun Arm { class: class Arm }, //│ Block: class Block, //│ Match: fun Match { class: class Match }, //│ Return: fun Return { class: class Return }, @@ -30,7 +32,42 @@ //│ End: fun End { class: class End } //│ } //│ ShapeSet = class ShapeSet { ShapeSet: fun ShapeSet { class: class ShapeSet } } +import "../../mlscript-compile/Option.mls" +open Option -Block.printCode(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x")], Block.Return(Block.ValueLit(1), false))) -//│ > FunDefn(Symbol("f"), [Symbol("x")], Return(Lit(1), false)) +Block.printCode(Block.Return(Block.ValueLit(1),false)) +//│ > 1 + +Block.printCode(Block.Define(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x")], Block.Return(Block.ValueRef(Block.Symbol("x"))), false), Block.Return(Block.ValueRef(Block.Symbol("x"))), false)) +//│ > fun f(x) = x +//│ > x + +Block.printCode( + Block.Define( + Block.ClsLikeDefn(Block.Symbol("C"), Some([Block.Symbol("x"), Block.Symbol("y")]), None), + Block.Assign( + Block.Symbol("x"), + Block.Instantiate( + Block.ValueRef(Block.Symbol("C")), [Block.Arg(Some(false), Block.ValueLit("1")), Block.Arg(Some(false), Block.ValueLit("2"))] + ), + Block.Return( + Block.Select(Block.ValueRef(Block.Symbol("x")), Block.Symbol("y")) + false + ) + ) + ) +) +//│ > class C(x, y) +//│ > let x = new C(1,2) +//│ > x.y + +Block.printCode(Block.Return(Block.Tuple([Block.Arg(None, Block.ValueLit(1)), Block.Arg(None, Block.ValueLit(2))]), false)) +//│ > [1,2] + +Block.printCode(Block.Match(Block.ValueLit(2), [Block.Arm(Block.Lit(1), Block.Return(Block.ValueLit(1), false)), Block.Arm(Block.Lit(2), Block.Return(Block.ValueLit(2), false))], Some(Block.Return(Block.ValueLit(3), false)), Block.End())) +//│ > if 2 is +//│ > 1 then 1 +//│ > 2 then 2 +//│ > else 3 +//│ > From cc24cae44e234f6f43c8c3638ad754a1a3ca3742 Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 18:14:20 +0800 Subject: [PATCH 175/268] only pass the "staged" annotation for non-companion module --- hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index 23c1d0301a..eba434ddfa 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -20,7 +20,7 @@ import semantics.Term.{Throw => _, *} import semantics.Elaborator.{State, Ctx, ctx} import syntax.{Literal, Tree} -import hkmc2.syntax.Fun +import hkmc2.syntax.{Fun, Keyword} abstract class TailOp extends (Result => Block) @@ -212,13 +212,16 @@ class Lowering()(using Config, TL, Raise, State, Ctx): case S(comp) => comp.defn.getOrElse(wat("Module companion without definition", mod.companion)) case N => val clsSymb = new ClassSymbol(Tree.DummyTypeDef(syntax.Cls), mod.sym.id) + val stagedAnnots = mod.annotations.collect { + case Annot.Modifier(Keyword.`staged`) => Annot.Modifier(Keyword.`staged`) + } val newDefn = ClassDef.Plain(mod.owner, syntax.Cls, clsSymb, mod.bsym, Nil, N, ObjBody(Blk(Nil, UnitVal())), S(mod.sym), - mod.annotations, + stagedAnnots ) clsSymb.defn = S(newDefn) newDefn From bcafb989b0dd5be7ab2aa0afd3ca003681684423 Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 19:15:41 +0800 Subject: [PATCH 176/268] reduce test cases --- hkmc2/shared/src/test/mlscript/staging/PrintCode.mls | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls index a907b98bc4..2ba27f5247 100644 --- a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls +++ b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls @@ -61,10 +61,13 @@ Block.printCode( //│ > let x = new C(1,2) //│ > x.y -Block.printCode(Block.Return(Block.Tuple([Block.Arg(None, Block.ValueLit(1)), Block.Arg(None, Block.ValueLit(2))]), false)) -//│ > [1,2] - -Block.printCode(Block.Match(Block.ValueLit(2), [Block.Arm(Block.Lit(1), Block.Return(Block.ValueLit(1), false)), Block.Arm(Block.Lit(2), Block.Return(Block.ValueLit(2), false))], Some(Block.Return(Block.ValueLit(3), false)), Block.End())) +Block.printCode( + Block.Match( + Block.ValueLit(2), + [Block.Arm(Block.Lit(1), Block.Return(Block.ValueLit(1), false)), Block.Arm(Block.Lit(2), Block.Return(Block.ValueLit(2), false))], + Some(Block.Return(Block.ValueLit(3), false)), Block.End() + ) +) //│ > if 2 is //│ > 1 then 1 //│ > 2 then 2 From b9eee38286fcc3533be7b7ef0e10902cd73a7f36 Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 19:30:10 +0800 Subject: [PATCH 177/268] fix class definition printing --- .../src/test/mlscript-compile/Block.mls | 13 +++--- .../src/test/mlscript/staging/Functions.mls | 44 +++++-------------- 2 files changed, 19 insertions(+), 38 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 8b208e99ec..6e7b48937b 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -85,7 +85,7 @@ fun showArg(a) = (if a.spread is Some(true) then "..." else "") + showPath(a.value) fun showArgs(args) = - args.map(showArg) + args.map(showArg).join(", ") fun showResult(r) = if r is @@ -97,7 +97,7 @@ fun showResult(r) = fun showCase(c) = if c is Lit(l) then showLiteral(l) - Cls(cls, p) then showSymbol(cls) + "(" + showPath(p) + ")" + Cls(cls, p) then showSymbol(cls) Tup(len) then "Tuple" _ then "_" @@ -117,10 +117,11 @@ fun showDefn(d) = ValDefn(sym, rhs) then "let " + showSymbol(sym) + " = " + showPath(rhs) FunDefn(sym, params, body) then - "fun " + showSymbol(sym) + "(" + params.map(showSymbol) + ") =" + + "fun " + showSymbol(sym) + params.map(showParams).join("") + " =" + (if body is Return(_, _) then " " else "\n ") + showBlock(body) - ClsLikeDefn(sym, paramsOpt) then - "class " + showSymbol(sym) + showParamsOpt(paramsOpt) + ClsLikeDefn(sym, _) then + if sym is + ClassSymbol(n, paramsOpt) then "class " + n + showParamsOpt(paramsOpt) fun showBlock(b) = if b is @@ -136,7 +137,7 @@ fun showBlock(b) = (if dflt is Some(db) then "\nelse " + showBlock(db) else "") + "\n" + showBlock(rest) End() then "" - x then x + _ then "" fun printCode(p: Block) = let s = showBlock(p) in diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index cdfd7583c8..71c29ef69b 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -33,9 +33,8 @@ //│ } //│ ShapeSet = class ShapeSet { ShapeSet: fun ShapeSet { class: class ShapeSet } } -:slot :js -staged module Expressions with +staged module Expressions with fun lit() = 1 fun assign() = let x = 42 @@ -54,29 +53,6 @@ staged module Expressions with Bool then 4 // [1, 2] then 5 // TODO: Case.Tup, needs handling for Label, Break else 0 -//│ Pretty Lowered: -//│ -//│ define staged class Expressions in -//│ set tmp = Expressions.lit_gen() in -//│ set tmp1 = shapeSet.printShapeSet(tmp.(0)) in -//│ set tmp2 = Block.printCode(tmp.(1)) in -//│ set tmp3 = Expressions.assign_gen() in -//│ set tmp4 = shapeSet.printShapeSet(tmp3.(0)) in -//│ set tmp5 = Block.printCode(tmp3.(1)) in -//│ set tmp6 = Expressions._var_gen() in -//│ set tmp7 = shapeSet.printShapeSet(tmp6.(0)) in -//│ set tmp8 = Block.printCode(tmp6.(1)) in -//│ set tmp9 = Expressions.tup_gen() in -//│ set tmp10 = shapeSet.printShapeSet(tmp9.(0)) in -//│ set tmp11 = Block.printCode(tmp9.(1)) in -//│ set tmp12 = Expressions.dynsel_gen() in -//│ set tmp13 = shapeSet.printShapeSet(tmp12.(0)) in -//│ set tmp14 = Block.printCode(tmp12.(1)) in -//│ set tmp15 = Expressions.match_gen() in -//│ set tmp16 = shapeSet.printShapeSet(tmp15.(0)) in -//│ set tmp17 = Block.printCode(tmp15.(1)) in -//│ set block$res2 = undefined in -//│ end //│ > Lit(1) //│ > 1 //│ > Lit(42) @@ -88,17 +64,15 @@ staged module Expressions with //│ > let x = 1 //│ > x //│ > Arr(Lit(1), Lit(2)) -//│ > [1,2] +//│ > [1, 2] //│ > Lit(1) //│ > let tmp = [1] //│ > tmp[0] //│ > Dyn //│ > let scrut = 9 //│ > if scrut is -//│ > _ then undefined -//│ > _ then undefined -//│ > _ then undefined -//│ > _ then undefined +//│ > _ then +//│ > _ then //│ > else 0 //│ > @@ -106,7 +80,7 @@ staged module Expressions with :staging class Outside(a) staged module ClassInstrumentation with - class Inside(a, b) + class Inside(a, b) // not printed correctly class NoArg fun inst1() = new Outside(1) fun inst2() = new NoArg @@ -135,4 +109,10 @@ staged module A with module A with staged module B with fun f() = 1 -//│ /!!!\ Uncaught error: java.lang.AssertionError: assertion failed: nested module not supported +//│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' +//│ ╟── which references the symbol introduced here +//│ ║ l.110: staged module B with +//│ ║ ^^^^^^ +//│ ║ l.111: fun f() = 1 +//│ ╙── ^^^^^^^^^^^^^^^ +//│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From 50f07ca1ad8a419bbe267f6eaf3924eaa8286262 Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 19:34:06 +0800 Subject: [PATCH 178/268] add match error on pretty printing --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 8 +++++--- hkmc2/shared/src/test/mlscript/staging/Functions.mls | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 6e7b48937b..d02bd793e6 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -79,7 +79,7 @@ fun showPath(p) = DynSelect(qual, fld, idx) then showPath(qual) + "[" + showPath(fld) + "]" ValueRef(s) then showSymbol(s) ValueLit(l) then showLiteral(l) - _ then "" + _ then "" fun showArg(a) = (if a.spread is Some(true) then "..." else "") + showPath(a.value) @@ -93,13 +93,14 @@ fun showResult(r) = Instantiate(cls, args) then "new " + showPath(cls) + "(" + showArgs(args) + ")" Tuple(elems) then "[" + showArgs(elems) + "]" Path then showPath(r) + _ then "" fun showCase(c) = if c is Lit(l) then showLiteral(l) Cls(cls, p) then showSymbol(cls) Tup(len) then "Tuple" - _ then "_" + _ then "" fun showArm(a) = showCase(a.cse) + " then " + showBlock(a.body) @@ -122,6 +123,7 @@ fun showDefn(d) = ClsLikeDefn(sym, _) then if sym is ClassSymbol(n, paramsOpt) then "class " + n + showParamsOpt(paramsOpt) + _ then "" fun showBlock(b) = if b is @@ -137,7 +139,7 @@ fun showBlock(b) = (if dflt is Some(db) then "\nelse " + showBlock(db) else "") + "\n" + showBlock(rest) End() then "" - _ then "" + _ then "" fun printCode(p: Block) = let s = showBlock(p) in diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 71c29ef69b..6513a03596 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -71,8 +71,8 @@ staged module Expressions with //│ > Dyn //│ > let scrut = 9 //│ > if scrut is -//│ > _ then -//│ > _ then +//│ > then +//│ > then //│ > else 0 //│ > From 678dbc9be0855e2ced8bf76cdb2774401c783824 Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 19:37:36 +0800 Subject: [PATCH 179/268] fix test cases --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 6 +++--- hkmc2/shared/src/test/mlscript/staging/PrintCode.mls | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index d02bd793e6..80955b8b57 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -85,7 +85,7 @@ fun showArg(a) = (if a.spread is Some(true) then "..." else "") + showPath(a.value) fun showArgs(args) = - args.map(showArg).join(", ") + args.map(showArg).join(",") fun showResult(r) = if r is @@ -117,8 +117,8 @@ fun showDefn(d) = if d is ValDefn(sym, rhs) then "let " + showSymbol(sym) + " = " + showPath(rhs) - FunDefn(sym, params, body) then - "fun " + showSymbol(sym) + params.map(showParams).join("") + " =" + + FunDefn(sym, p, body) then + "fun " + showSymbol(sym) + showParams(p) + " =" + (if body is Return(_, _) then " " else "\n ") + showBlock(body) ClsLikeDefn(sym, _) then if sym is diff --git a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls index 2ba27f5247..d1cf0c3721 100644 --- a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls +++ b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls @@ -44,7 +44,7 @@ Block.printCode(Block.Define(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x") Block.printCode( Block.Define( - Block.ClsLikeDefn(Block.Symbol("C"), Some([Block.Symbol("x"), Block.Symbol("y")]), None), + Block.ClsLikeDefn(Block.ClassSymbol("C", Some([Block.Symbol("x"), Block.Symbol("y")])), None), Block.Assign( Block.Symbol("x"), Block.Instantiate( @@ -73,4 +73,3 @@ Block.printCode( //│ > 2 then 2 //│ > else 3 //│ > - From 71a8918d6b2be212b9961d992148ca7a67e41615 Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 19:43:51 +0800 Subject: [PATCH 180/268] some unimportant change --- hkmc2/shared/src/test/mlscript/staging/Functions.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 6513a03596..495ddb8e37 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -64,7 +64,7 @@ staged module Expressions with //│ > let x = 1 //│ > x //│ > Arr(Lit(1), Lit(2)) -//│ > [1, 2] +//│ > [1,2] //│ > Lit(1) //│ > let tmp = [1] //│ > tmp[0] From 7151735a72a4b7dd86217743fe2c96191e912d9b Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 19:52:21 +0800 Subject: [PATCH 181/268] some more unimportant change --- hkmc2/shared/src/test/mlscript/staging/Functions.mls | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index cdfd7583c8..d6c2be7340 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -97,8 +97,6 @@ staged module Expressions with //│ > if scrut is //│ > _ then undefined //│ > _ then undefined -//│ > _ then undefined -//│ > _ then undefined //│ > else 0 //│ > @@ -112,7 +110,7 @@ staged module ClassInstrumentation with fun inst2() = new NoArg //│ > class NoArg() //│ > -//│ > class Inside(a, b) +//│ > class Inside() //│ > //│ > Class(Outside, [Lit(1)]) //│ > new Outside(1) @@ -135,4 +133,10 @@ staged module A with module A with staged module B with fun f() = 1 -//│ /!!!\ Uncaught error: java.lang.AssertionError: assertion failed: nested module not supported +//│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' +//│ ╟── which references the symbol introduced here +//│ ║ l.134: staged module B with +//│ ║ ^^^^^^ +//│ ║ l.135: fun f() = 1 +//│ ╙── ^^^^^^^^^^^^^^^ +//│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From f582fa5119763e1d66484b6959d9581de63b58a7 Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 20:00:56 +0800 Subject: [PATCH 182/268] printed correctly now --- hkmc2/shared/src/test/mlscript/staging/Functions.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 495ddb8e37..1427e1e99c 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -80,7 +80,7 @@ staged module Expressions with :staging class Outside(a) staged module ClassInstrumentation with - class Inside(a, b) // not printed correctly + class Inside(a, b) class NoArg fun inst1() = new Outside(1) fun inst2() = new NoArg From 0a6087fc861e8ba162e06ce42f3b926e11ba57cd Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 23:18:05 +0800 Subject: [PATCH 183/268] Revert "printed correctly now" This reverts commit f582fa5119763e1d66484b6959d9581de63b58a7. --- hkmc2/shared/src/test/mlscript/staging/Functions.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 1427e1e99c..495ddb8e37 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -80,7 +80,7 @@ staged module Expressions with :staging class Outside(a) staged module ClassInstrumentation with - class Inside(a, b) + class Inside(a, b) // not printed correctly class NoArg fun inst1() = new Outside(1) fun inst2() = new NoArg From cd7f7bc939bc03d5b6ec3f5249fbaee88bb9a5c1 Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 23:18:36 +0800 Subject: [PATCH 184/268] Revert "Merge branch 'instrument-with-pretty-print' into instrument" This reverts commit 2548c78417bb38a3be76ecc43579a0365cb6fb60, reversing changes made to 7151735a72a4b7dd86217743fe2c96191e912d9b. --- .../src/test/mlscript-compile/Block.mls | 21 +++++----- .../src/test/mlscript/staging/Functions.mls | 38 +++++++++++++++---- .../src/test/mlscript/staging/PrintCode.mls | 14 +++---- 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 80955b8b57..8b208e99ec 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -79,13 +79,13 @@ fun showPath(p) = DynSelect(qual, fld, idx) then showPath(qual) + "[" + showPath(fld) + "]" ValueRef(s) then showSymbol(s) ValueLit(l) then showLiteral(l) - _ then "" + _ then "" fun showArg(a) = (if a.spread is Some(true) then "..." else "") + showPath(a.value) fun showArgs(args) = - args.map(showArg).join(",") + args.map(showArg) fun showResult(r) = if r is @@ -93,14 +93,13 @@ fun showResult(r) = Instantiate(cls, args) then "new " + showPath(cls) + "(" + showArgs(args) + ")" Tuple(elems) then "[" + showArgs(elems) + "]" Path then showPath(r) - _ then "" fun showCase(c) = if c is Lit(l) then showLiteral(l) - Cls(cls, p) then showSymbol(cls) + Cls(cls, p) then showSymbol(cls) + "(" + showPath(p) + ")" Tup(len) then "Tuple" - _ then "" + _ then "_" fun showArm(a) = showCase(a.cse) + " then " + showBlock(a.body) @@ -117,13 +116,11 @@ fun showDefn(d) = if d is ValDefn(sym, rhs) then "let " + showSymbol(sym) + " = " + showPath(rhs) - FunDefn(sym, p, body) then - "fun " + showSymbol(sym) + showParams(p) + " =" + + FunDefn(sym, params, body) then + "fun " + showSymbol(sym) + "(" + params.map(showSymbol) + ") =" + (if body is Return(_, _) then " " else "\n ") + showBlock(body) - ClsLikeDefn(sym, _) then - if sym is - ClassSymbol(n, paramsOpt) then "class " + n + showParamsOpt(paramsOpt) - _ then "" + ClsLikeDefn(sym, paramsOpt) then + "class " + showSymbol(sym) + showParamsOpt(paramsOpt) fun showBlock(b) = if b is @@ -139,7 +136,7 @@ fun showBlock(b) = (if dflt is Some(db) then "\nelse " + showBlock(db) else "") + "\n" + showBlock(rest) End() then "" - _ then "" + x then x fun printCode(p: Block) = let s = showBlock(p) in diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 495ddb8e37..d6c2be7340 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -33,8 +33,9 @@ //│ } //│ ShapeSet = class ShapeSet { ShapeSet: fun ShapeSet { class: class ShapeSet } } +:slot :js -staged module Expressions with +staged module Expressions with fun lit() = 1 fun assign() = let x = 42 @@ -53,6 +54,29 @@ staged module Expressions with Bool then 4 // [1, 2] then 5 // TODO: Case.Tup, needs handling for Label, Break else 0 +//│ Pretty Lowered: +//│ +//│ define staged class Expressions in +//│ set tmp = Expressions.lit_gen() in +//│ set tmp1 = shapeSet.printShapeSet(tmp.(0)) in +//│ set tmp2 = Block.printCode(tmp.(1)) in +//│ set tmp3 = Expressions.assign_gen() in +//│ set tmp4 = shapeSet.printShapeSet(tmp3.(0)) in +//│ set tmp5 = Block.printCode(tmp3.(1)) in +//│ set tmp6 = Expressions._var_gen() in +//│ set tmp7 = shapeSet.printShapeSet(tmp6.(0)) in +//│ set tmp8 = Block.printCode(tmp6.(1)) in +//│ set tmp9 = Expressions.tup_gen() in +//│ set tmp10 = shapeSet.printShapeSet(tmp9.(0)) in +//│ set tmp11 = Block.printCode(tmp9.(1)) in +//│ set tmp12 = Expressions.dynsel_gen() in +//│ set tmp13 = shapeSet.printShapeSet(tmp12.(0)) in +//│ set tmp14 = Block.printCode(tmp12.(1)) in +//│ set tmp15 = Expressions.match_gen() in +//│ set tmp16 = shapeSet.printShapeSet(tmp15.(0)) in +//│ set tmp17 = Block.printCode(tmp15.(1)) in +//│ set block$res2 = undefined in +//│ end //│ > Lit(1) //│ > 1 //│ > Lit(42) @@ -71,8 +95,8 @@ staged module Expressions with //│ > Dyn //│ > let scrut = 9 //│ > if scrut is -//│ > then -//│ > then +//│ > _ then undefined +//│ > _ then undefined //│ > else 0 //│ > @@ -80,13 +104,13 @@ staged module Expressions with :staging class Outside(a) staged module ClassInstrumentation with - class Inside(a, b) // not printed correctly + class Inside(a, b) class NoArg fun inst1() = new Outside(1) fun inst2() = new NoArg //│ > class NoArg() //│ > -//│ > class Inside(a, b) +//│ > class Inside() //│ > //│ > Class(Outside, [Lit(1)]) //│ > new Outside(1) @@ -111,8 +135,8 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.110: staged module B with +//│ ║ l.134: staged module B with //│ ║ ^^^^^^ -//│ ║ l.111: fun f() = 1 +//│ ║ l.135: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ ═══[RUNTIME ERROR] ReferenceError: B is not defined diff --git a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls index d1cf0c3721..a907b98bc4 100644 --- a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls +++ b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls @@ -44,7 +44,7 @@ Block.printCode(Block.Define(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x") Block.printCode( Block.Define( - Block.ClsLikeDefn(Block.ClassSymbol("C", Some([Block.Symbol("x"), Block.Symbol("y")])), None), + Block.ClsLikeDefn(Block.Symbol("C"), Some([Block.Symbol("x"), Block.Symbol("y")]), None), Block.Assign( Block.Symbol("x"), Block.Instantiate( @@ -61,15 +61,13 @@ Block.printCode( //│ > let x = new C(1,2) //│ > x.y -Block.printCode( - Block.Match( - Block.ValueLit(2), - [Block.Arm(Block.Lit(1), Block.Return(Block.ValueLit(1), false)), Block.Arm(Block.Lit(2), Block.Return(Block.ValueLit(2), false))], - Some(Block.Return(Block.ValueLit(3), false)), Block.End() - ) -) +Block.printCode(Block.Return(Block.Tuple([Block.Arg(None, Block.ValueLit(1)), Block.Arg(None, Block.ValueLit(2))]), false)) +//│ > [1,2] + +Block.printCode(Block.Match(Block.ValueLit(2), [Block.Arm(Block.Lit(1), Block.Return(Block.ValueLit(1), false)), Block.Arm(Block.Lit(2), Block.Return(Block.ValueLit(2), false))], Some(Block.Return(Block.ValueLit(3), false)), Block.End())) //│ > if 2 is //│ > 1 then 1 //│ > 2 then 2 //│ > else 3 //│ > + From 34d0914f3f111c508570ff9003facb13444bf2a3 Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 23:26:59 +0800 Subject: [PATCH 185/268] Revert "some more unimportant change" This reverts commit 7151735a72a4b7dd86217743fe2c96191e912d9b. --- hkmc2/shared/src/test/mlscript/staging/Functions.mls | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index d6c2be7340..cdfd7583c8 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -97,6 +97,8 @@ staged module Expressions with //│ > if scrut is //│ > _ then undefined //│ > _ then undefined +//│ > _ then undefined +//│ > _ then undefined //│ > else 0 //│ > @@ -110,7 +112,7 @@ staged module ClassInstrumentation with fun inst2() = new NoArg //│ > class NoArg() //│ > -//│ > class Inside() +//│ > class Inside(a, b) //│ > //│ > Class(Outside, [Lit(1)]) //│ > new Outside(1) @@ -133,10 +135,4 @@ staged module A with module A with staged module B with fun f() = 1 -//│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' -//│ ╟── which references the symbol introduced here -//│ ║ l.134: staged module B with -//│ ║ ^^^^^^ -//│ ║ l.135: fun f() = 1 -//│ ╙── ^^^^^^^^^^^^^^^ -//│ ═══[RUNTIME ERROR] ReferenceError: B is not defined +//│ /!!!\ Uncaught error: java.lang.AssertionError: assertion failed: nested module not supported From a3925e5da38dfbb0b92d9a0ddf59aee45ccabedf Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 23:27:50 +0800 Subject: [PATCH 186/268] Revert "Merge remote-tracking branch 'origin/instrument' into instrument" This reverts commit 2b1d1576279f2d8aca058036f8671f6d92deb161, reversing changes made to cc24cae44e234f6f43c8c3638ad754a1a3ca3742. --- .../scala/hkmc2/codegen/Instrumentation.scala | 148 +++++++++--------- .../src/test/mlscript-compile/Block.mls | 20 ++- .../src/test/mlscript-compile/ShapeSet.mls | 6 - .../src/test/mlscript/staging/Functions.mls | 8 +- 4 files changed, 87 insertions(+), 95 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index f6ffb6fde5..6b0d15f74c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -129,8 +129,6 @@ class InstrumentationImpl(using State): def fnConcat(p1: Path, p2: Path)(k: Path => Block): Block = blockCall("concat", Ls(p1, p2))(k) - def fnPruneBadArms(arms: Path)(k: Path => Block): Block = - shapeSetCall("pruneBadArms", Ls(arms))(k) def fnMrg(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = shapeSetCall("mrg", Ls(s1, s2))(s => k(ShapeSet(s))) def fnSel(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = @@ -139,15 +137,18 @@ class InstrumentationImpl(using State): shapeSetCall("filter", Ls(s1, s2))(s => k(ShapeSet(s))) def fnUnion(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = shapeSetCall("union", Ls(s1, s2))(s => k(ShapeSet(s))) + def fnFlat(s: Ls[ShapeSet])(k: ShapeSet => Block): Block = + tuple(s): tup => + shapeSetCall("flat", Ls(tup))(s => k(ShapeSet(s))) // transformation helpers - def transformSymbol[S <: Symbol](sym: S, symName: Str = "sym")(k: Path => Block): Block = + def transformSymbol[S <: Symbol](sym: S)(k: Path => Block): Block = sym match case clsSym: ClassSymbol => - transformParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => - blockCtor("ClassSymbol", Ls(toValue(sym.nme), paramsOpt), symName)(k) - case _ => blockCtor("Symbol", Ls(toValue(sym.nme)), symName)(k) + stageParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => + blockCtor("ClassSymbol", Ls(toValue(sym.nme), paramsOpt))(k) + case _ => blockCtor("Symbol", Ls(toValue(sym.nme)), "sym")(k) def transformOption[A](xOpt: Opt[A], f: A => (Path => Block) => Block)(k: Path => Block): Block = xOpt match @@ -156,77 +157,78 @@ class InstrumentationImpl(using State): // instrumentation rules - def ruleLit(l: Value.Lit, symName: String = "lit")(k: StagedPath => Block): Block = + def ruleLit(l: Value.Lit)(k: StagedPath => Block): Block = shapeLit(l): sp => blockCtor("ValueLit", Ls(l)): cde => - StagedPath(sp, cde, symName)(k) + StagedPath(sp, cde, "lit")(k) // not in formalization - def ruleVar(r: Value.Ref, symName: String = "var")(k: StagedPath => Block): Block = + def ruleVar(r: Value.Ref)(k: StagedPath => Block): Block = val Value.Ref(l, disamb) = r transformSymbol(disamb.getOrElse(l)): sym => blockCtor("ValueRef", Ls(sym)): cde => // variable defined outside of scope, may be a reference to a class shapeDyn(): sp => - StagedPath(sp, cde, symName)(k) + StagedPath(sp, cde, "var")(k) - def ruleTup(t: Tuple, symName: String = "tup")(using Context)(k: StagedPath => Block): Block = + def ruleTup(t: Tuple)(using Context)(k: StagedPath => Block): Block = assert(!t.mut, "mutable tuple not supported") transformArgs(t.elems): xs => shapeArr(xs.map(_.shapes)): sp => tuple(xs.map(_.code)): codes => blockCtor("Tuple", Ls(codes)): cde => - StagedPath(sp, cde, symName)(k) + StagedPath(sp, cde, "tup")(k) - def ruleSel(s: Select, symName: String = "sel")(using Context)(k: StagedPath => Block): Block = + def ruleSel(s: Select)(using Context)(k: StagedPath => Block): Block = val Select(p, i @ Tree.Ident(name)) = s transformPath(p): x => shapeLit(toValue(name)): n => fnSel(x.shapes, n): sp => blockCtor("Symbol", Ls(toValue(name))): name => blockCtor("Select", Ls(x.code, name)): cde => - StagedPath(sp, cde, symName)(k) + StagedPath(sp, cde, "sel")(k) - def ruleDynSel(d: DynSelect, symName: String = "dynsel")(using Context)(k: StagedPath => Block): Block = + def ruleDynSel(d: DynSelect)(using Context)(k: StagedPath => Block): Block = transformPath(d.qual): x => transformPath(d.fld): y => fnSel(x.shapes, y.shapes): sp => blockCtor("DynSelect", Ls(x.code, y.code, toValue(d.arrayIdx))): cde => - StagedPath(sp, cde, symName)(k) + StagedPath(sp, cde, "dynsel")(k) - def ruleInst(i: Instantiate, symName: String = "inst")(using Context)(k: StagedPath => Block): Block = + def ruleInst(i: Instantiate)(using Context)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i assert(!mut, "mutable instantiation not supported") transformArgs(args): xs => - val sym = cls match - // TODO: if class is staged, we can just use Symbol without storing the arguments - case Value.Ref(l, S(disamb)) => transformSymbol(disamb) - case s: Select if s.symbol.isDefined => transformSymbol(s.symbol.get) - case _ => transformSymbol(TempSymbol(N, "TODO")) - sym: sym => - shapeClass(sym, xs.map(_.shapes)): sp => - // reuse instrumentation logic, shape of cls is discarded - // possible to skip this? this uses ruleVar, which is not in formalization - transformPath(cls): cls => - tuple(xs.map(_.code)): codes => - blockCtor("Instantiate", Ls(cls.code, codes)): cde => - StagedPath(sp, cde, symName)(k) - - def ruleReturn(r: Return, symName: String = "return")(using Context)(k: (StagedPath, Context) => Block): Block = + tuple(xs.map(_.shapes)): shapes => + val sym = cls match + // TODO: if class is staged, we can just use Symbol without storing the arguments + case Value.Ref(l, S(disamb)) => transformSymbol(disamb) + case s: Select if s.symbol.isDefined => transformSymbol(s.symbol.get) + case _ => transformSymbol(TempSymbol(N, "TODO")) + sym: sym => + shapeClass(sym, xs.map(_.shapes)): sp => + // reuse instrumentation logic, shape of cls is discarded + // possible to skip this? this uses ruleVar, which is not in formalization + transformPath(cls): cls => + tuple(xs.map(_.code)): codes => + blockCtor("Instantiate", Ls(cls.code, codes)): cde => + StagedPath(sp, cde, "inst")(k) + + def ruleReturn(r: Return)(using Context)(k: (StagedPath, Context) => Block): Block = transformResult(r.res): x => blockCtor("Return", Ls(x.code, toValue(false))): cde => - StagedPath(x.shapes, cde, symName)(k(_, summon)) + StagedPath(x.shapes, cde, "return")(k(_, summon)) - def ruleMatch(m: Match, symName: String = "match")(using Context)(k: (StagedPath, Context) => Block): Block = + def ruleMatch(m: Match)(using Context)(k: (StagedPath, Context) => Block): Block = val Match(p, ks, dflt, rest) = m transformPath(p): x => ruleBranches(x, p, ks, dflt): (stagedMatch, ctx1) => transformBlock(rest)(using ctx1): (z, ctx2) => fnMrg(stagedMatch.shapes, z.shapes): sp => fnConcat(stagedMatch.code, z.code): cde => - StagedPath(sp, cde, symName)(k(_, ctx2)) + StagedPath(sp, cde)(k(_, ctx2)) - def ruleAssign(a: Assign, symName: String = "assign")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def ruleAssign(a: Assign)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Assign(x, r, b) = a transformResult(r): y => transformSymbol(x): xSym => @@ -241,7 +243,7 @@ class InstrumentationImpl(using State): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => - StagedPath(z.shapes, cde, symName)(k(_, ctx)) + StagedPath(z.shapes, cde, "assign")(k(_, ctx)) case N => StagedPath(y.shapes, xStaged): x2 => // propagate shape information for future references to x @@ -249,9 +251,9 @@ class InstrumentationImpl(using State): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => - StagedPath(z.shapes, cde, symName)(k(_, ctx)) + StagedPath(z.shapes, cde, "assign")(k(_, ctx)) - def ruleLet(x: BlockMemberSymbol, b: Block, symName: String = "_let")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def ruleLet(x: BlockMemberSymbol, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = shapeBot(): bot => transformSymbol(x): xSym => StagedPath(bot, xSym): y => @@ -260,12 +262,12 @@ class InstrumentationImpl(using State): transformBlock(b): (z, ctx) => blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => blockCtor("Assign", Ls(xSym, undefined, z.code)): cde => - StagedPath(z.shapes, cde, symName)(k(_, summon)) + StagedPath(z.shapes, cde, "_let")(k(_, summon)) - def ruleEnd(symName: String = "end")(k: StagedPath => Block): Block = + def ruleEnd()(k: StagedPath => Block): Block = shapeBot(): sp => blockCtor("End", Ls()): cde => - StagedPath(sp, cde, symName)(k) + StagedPath(sp, cde, "end")(k) def ruleBlk(b: Block)(using Context)(k: Path => Block): Block = transformBlock(b)(k apply _.code) @@ -274,22 +276,19 @@ class InstrumentationImpl(using State): assert(cls.companion.isEmpty, "nested module not supported") (Define(cls, _)): transformBlock(rest): p => - transformParamsOpt(cls.paramsOpt): paramsOpt => - transformSymbol(cls.isym): c => + transformSymbol(cls.sym): c => + stageParamsOpt(cls.paramsOpt): paramsOpt => optionNone(): none => // TODO: handle companion object - blockCtor("ClsLikeDefn", Ls(c, none)): cls => + blockCtor("ClsLikeDefn", Ls(c, paramsOpt, none)): cls => blockCtor("Define", Ls(cls, p.code))(k) - def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block], symName: String = "branches")(using Context)(k: (StagedPath, Context) => Block): Block = + def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block])(using Context)(k: (StagedPath, Context) => Block): Block = arms.map((cse, block) => (f: StagedPath => Context => Block) => (ruleBranch(x, p, cse, block)(using _)).flip(f(_)(_))) .collectApply .pipe(_.flip(summon)): arms => ctx => - tuple(arms.map(_.p)): tup => - fnPruneBadArms(tup): res => - val result = StagedPath(res) - val sp = result.shapes - val arms = result.code + fnFlat(arms.map(_.shapes)): sp => + tuple(arms.map(_.code)): arms => blockCtor("End", Ls()): e => // TODO: use transformOption here def dfltStaged(k: (Path, Context) => Block) = dflt match @@ -298,29 +297,30 @@ class InstrumentationImpl(using State): case N => optionNone()(k(_, ctx)) dfltStaged: (dflt, ctx) => blockCtor("Match", Ls(x.code, arms, dflt, e)): m => - StagedPath(sp, m, symName)(k(_, ctx)) + StagedPath(sp, m, "branches")(k(_, ctx)) - def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block, symName: String = "branch")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = transformCase(cse): cse => fnFilter(x.shapes, cse): sp => - call(sp.p.selSN("isEmpty"), Ls()): scrut => - ruleEnd(): e => - val res = new TempSymbol(N, "tmp") - val arm = Case.Lit(Tree.BoolLit(true)) -> Assign(res, e.p, End()) - val dflt = - StagedPath(sp, x.code): x0 => - given Context = ctx.clone() += p -> x0 - transformBlock(b): (y1, ctx) => - // TODO: use Arm type instead of Tup - tuple(Ls(cse, y1.code)): cde => - StagedPath(y1.shapes, cde, symName): ret => - Assign(res, ret.p, End()) - (Match(scrut, Ls(arm), S(dflt), _)): - k(StagedPath(Value.Ref(res)), ctx.clone() -= p) - - // this partially applies rules from filter to account for difference between Block.Case and Match pattern in the formalization - // to avoid defining the `_` pattern in Block.Case, we apply filter(s, _) = s + StagedPath(sp, x.code): x0 => + call(x0.shapes.p.selSN("isEmpty"), Ls()): scrut => + ruleEnd(): e => + tuple(Ls(cse, e.code)): armStaged => + // returns Case -> Block, instead of End as in formalization + StagedPath(e.shapes, armStaged): badArm => + val arm = Case.Lit(Tree.BoolLit(true)) -> k(badArm, ctx) + (Match(scrut, Ls(arm), N, _)): + given Context = ctx.clone() += p -> x0 + transformBlock(b): (y1, ctx) => + // TODO: use Arm type instead of Tup + tuple(Ls(cse, y1.code)): cde => + StagedPath(y1.shapes, cde, "branch")(k(_, ctx.clone() -= p)) + + // not in formalization + // this partially applies rules from filter to account for difference in Block.Case and Match pattern in the formalization + // to avoid defining the `_` pattern in Block.Case, we use the fact that filter(s, _) = s def ruleWildCard(x: StagedPath, p: Path, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + // when pattern = _, x0 = x call(x.shapes.p.selSN("isEmpty"), Ls()): scrut => val arm = Case.Lit(Tree.BoolLit(true)) -> ruleEnd()(p => Return(p.p, false)) (Match(scrut, Ls(arm), N, _)): @@ -359,11 +359,11 @@ class InstrumentationImpl(using State): def transformArgs(args: Ls[Arg])(using Context)(k: Ls[StagedPath] => Block): Block = args.map(transformArg).collectApply(k) - def transformParamList(ps: ParamList)(k: Path => Block) = + def stageParamList(ps: ParamList)(k: Path => Block) = ps.params.map(p => transformSymbol(p.sym)).collectApply(tuple(_)(k)) - def transformParamsOpt(pOpt: Opt[ParamList])(k: Path => Block) = - transformOption(pOpt, transformParamList)(k) + def stageParamsOpt(pOpt: Opt[ParamList])(k: Path => Block) = + transformOption(pOpt, stageParamList)(k) def transformCase(cse: Case)(using Context)(k: Path => Block): Block = cse match @@ -427,7 +427,7 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): case d @ Define(defn, rest) => defn match // find modules with staged annotation - case c: ClsLikeDefn if c.companion.exists(_.isym.defn.exists(_.hasStagedModifier.isDefined)) => + case c: ClsLikeDefn if c.companion.isDefined => val sym = c.sym.subst val companion = c.companion.get val (stagedMethods, debugPrintCode) = companion.methods diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 8b208e99ec..e6e4906d4b 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -9,16 +9,14 @@ type Opt[A] = Option[A] // dependancies referenced in Block classes, referencing implementation in Term.mls -type Literal = null | undefined | Str | Int | Num | Bool - -type ParamList = Array[Symbol] - class Symbol(val name: Str) type Ident = Symbol // this is so that we're able to retrieve information about the class from the symbol -class ClassSymbol(val name: Str, val paramsOpt: Opt[ParamList]) extends Symbol(name) +class ClassSymbol(val name: Str, val args: Opt[Array[Symbol]]) extends Symbol(name) -// Classes defined in Block.scala +type Literal = null | undefined | Str | Int | Num | Bool + +type ParamList = Array[Symbol] class Arg(val spread: Opt[Bool], val value: Path) @@ -26,7 +24,7 @@ class Case with constructor Lit(val lit: Literal) Cls(val cls: Symbol, val path: Path) - Tup(val len: Int) + Tup(val len: Int) // TODO: remove inf? class Result with constructor @@ -44,8 +42,8 @@ class Path extends Result with class Defn with constructor ValDefn(val sym: Symbol, val rhs: Path) - ClsLikeDefn(val sym: Symbol, val companion: Opt[ClsLikeBody]) // companion unused - FunDefn(val sym: Symbol, val params: Array[ParamList], val body: Block) + ClsLikeDefn(val sym: Symbol, val paramsOpt: Opt[ParamList], val companion: Opt[ClsLikeBody]) // unused + FunDefn(val sym: Symbol, val params: ParamList, val body: Block, val stage: Bool) class ClsLikeBody(val isym: Symbol, val methods: Array[FunDefn], val publicFields: Array[[Symbol, Symbol]]) // unused @@ -116,10 +114,10 @@ fun showDefn(d) = if d is ValDefn(sym, rhs) then "let " + showSymbol(sym) + " = " + showPath(rhs) - FunDefn(sym, params, body) then + FunDefn(sym, params, body, stage) then "fun " + showSymbol(sym) + "(" + params.map(showSymbol) + ") =" + (if body is Return(_, _) then " " else "\n ") + showBlock(body) - ClsLikeDefn(sym, paramsOpt) then + ClsLikeDefn(sym, paramsOpt, _) then "class " + showSymbol(sym) + showParamsOpt(paramsOpt) fun showBlock(b) = diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls index 7ed0f5c60e..ed97d00cb1 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -78,9 +78,3 @@ fun sel(s1: ShapeSet, s2: ShapeSet) = fun mrg(s1: ShapeSet, s2: ShapeSet) = mkDyn() // TODO - -open Block { Block } - -fun pruneBadArms(arms: Array[[ShapeSet, Block]]) = - val rem = arms.filter(arm => not (arm.0.isEmpty() and arm.1 is End)) - [flat(rem.map(_.0)), rem.map(_.1)] diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index cdfd7583c8..6db1604147 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -106,20 +106,20 @@ staged module Expressions with :staging class Outside(a) staged module ClassInstrumentation with - class Inside(a, b) + class Class(a, b) class NoArg fun inst1() = new Outside(1) fun inst2() = new NoArg //│ > class NoArg() //│ > -//│ > class Inside(a, b) +//│ > class Class(a, b) //│ > //│ > Class(Outside, [Lit(1)]) //│ > new Outside(1) //│ > Class(NoArg, []) //│ > new ClassInstrumentation.NoArg() -// debug printing fails, collision with class name? +// collision with class name? :js :staging :fixme @@ -128,7 +128,7 @@ staged module A with fun f() = 1 //│ ═══[RUNTIME ERROR] TypeError: A1.f_gen is not a function -// debug printing fails, unable to reference the class when calling the instrumented function +// unable to reference the class when calling the instrumented function for debugging :js :staging :fixme From 79c90eed2010d25599a665659c99b4a10192ce27 Mon Sep 17 00:00:00 2001 From: TYeung Date: Wed, 26 Nov 2025 23:28:23 +0800 Subject: [PATCH 187/268] Revert "update pretty printing to print actual mlscript" This reverts commit 5d63091e0d1e91de74d0601fc8bf2ad5155f2c59. --- .../src/test/mlscript-compile/Block.mls | 175 +++++++++++------- .../src/test/mlscript/staging/PrintCode.mls | 41 +--- 2 files changed, 108 insertions(+), 108 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index e6e4906d4b..ea54c8b3f6 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -1,6 +1,9 @@ +import "./Predef.mls" import "./Option.mls" import "./StrOps.mls" +open Predef +open StrOps open Option module Block with... @@ -18,8 +21,10 @@ type Literal = null | undefined | Str | Int | Num | Bool type ParamList = Array[Symbol] -class Arg(val spread: Opt[Bool], val value: Path) - +// Classes defined in Block.scala + +class Arg(val spread: Opt[Bool], val value: Path) + class Case with constructor Lit(val lit: Literal) @@ -43,20 +48,18 @@ class Defn with constructor ValDefn(val sym: Symbol, val rhs: Path) ClsLikeDefn(val sym: Symbol, val paramsOpt: Opt[ParamList], val companion: Opt[ClsLikeBody]) // unused - FunDefn(val sym: Symbol, val params: ParamList, val body: Block, val stage: Bool) + FunDefn(val sym: Symbol, val params: Array[ParamList], val body: Block) class ClsLikeBody(val isym: Symbol, val methods: Array[FunDefn], val publicFields: Array[[Symbol, Symbol]]) // unused -class Arm(val cse: Case, val body: Block) - class Block with constructor - Match(val scrut: Path, val arms: Array[Arm], val dflt: Opt[Block], val rest: Block) + Match(val scrut: Path, val arms: Array[[Case, Block]], val dflt: Opt[Block], val rest: Block) Return(val res: Result, val implct: Bool) Assign(val lhs: Symbol, val rhs: Result, val rest: Block) Define(val defn: Defn, val rest: Block) End() - + fun concat(b1: Block, b2: Block) = if b1 is Match(scrut, arms, dflt, rest) then Match(scrut, arms, dflt, concat(rest, b2)) Return(res, implct) then b2 // discard return? @@ -64,78 +67,112 @@ fun concat(b1: Block, b2: Block) = if b1 is Define(defn, rest) then Define(defn, concat(rest, b2)) End() then b2 -fun showSymbol(s) = s.name +fun showBool(b: Bool) = if b then "true" else "false" -fun showLiteral(l) = +fun showLiteral(l: Literal) = if l is undefined then "undefined" - _ then l.toString() - -fun showPath(p) = + null then "null" + else l.toString() + +fun showSymbol(s: Symbol) = + // console.log("printing " + s) + if s is + ClassSymbol(name, args) then + "ClassSymbol(" + "\"" + name + "\"" + + if args + is Some(args) then ":[" + args.map(showSymbol).join(", ") + "]" + is None then "" + + ")" + _ then "Symbol(" + "\"" + s.name + "\"" + ")" + +fun showIdent(i: Ident) = showSymbol(i) + +fun showPath(p: Path): Str = if p is - Select(qual, name) then showPath(qual) + "." + showSymbol(name) - DynSelect(qual, fld, idx) then showPath(qual) + "[" + showPath(fld) + "]" - ValueRef(s) then showSymbol(s) - ValueLit(l) then showLiteral(l) - _ then "" - -fun showArg(a) = - (if a.spread is Some(true) then "..." else "") + showPath(a.value) - -fun showArgs(args) = - args.map(showArg) + Select(qual, name) then + "Select(" + showPath(qual) + ", " + showIdent(name) + ")" + DynSelect(qual, fld, arrayIdx) then + "DynSelect(" + showPath(qual) + ", " + showPath(fld) + ", " + showBool(arrayIdx) + ")" + ValueRef(l) then + "Ref(" + showSymbol(l) + ")" + ValueLit(lit) then + "Lit(" + showLiteral(lit) + ")" + +fun showArg(arg: Arg) = + if arg.spread is Some(true) then "..." + showPath(arg.value) + else showPath(arg.value) + +fun showArgs(args: Array[Arg]) = + "[" + args.map(showArg).join(", ") + "]" + +// Case (match arm patterns) +fun showCase(c: Case): Str = + if c is + Lit(lit) then "Lit(" + showLiteral(lit) + ")" + Cls(cls, path) then "Cls(" + showSymbol(cls) + ", " + showPath(path) + ")" + Tup(len) then "Tup(" + len + ")" -fun showResult(r) = +fun showResult(r: Result): Str = if r is - Call(f, args) then showPath(f) + "(" + showArgs(args) + ")" - Instantiate(cls, args) then "new " + showPath(cls) + "(" + showArgs(args) + ")" - Tuple(elems) then "[" + showArgs(elems) + "]" Path then showPath(r) + Call(f, args) then "Call(" + showPath(f) + ", " + showArgs(args) + ")" + Instantiate(cls, args) then "Instantiate(" + showPath(cls) + ", " + showArgs(args) + ")" + Tuple(elems) then "Tuple(" + showArgs(elems) + ")" -fun showCase(c) = - if c is - Lit(l) then showLiteral(l) - Cls(cls, p) then showSymbol(cls) + "(" + showPath(p) + ")" - Tup(len) then "Tuple" - _ then "_" - -fun showArm(a) = - showCase(a.cse) + " then " + showBlock(a.body) - -fun showParamsOpt(p) = - if p is - Some(s) then showParams(s) - None then "()" - -fun showParams(p: ParamList) = - "(" + p.map(showSymbol).join(", ") + ")" +fun showParamList(ps: ParamList) = + "[" + ps.map(s => showSymbol(s)).join(", ") + "]" -fun showDefn(d) = +fun showDefn(d: Defn): Str = if d is ValDefn(sym, rhs) then - "let " + showSymbol(sym) + " = " + showPath(rhs) - FunDefn(sym, params, body, stage) then - "fun " + showSymbol(sym) + "(" + params.map(showSymbol) + ") =" + - (if body is Return(_, _) then " " else "\n ") + showBlock(body) - ClsLikeDefn(sym, paramsOpt, _) then - "class " + showSymbol(sym) + showParamsOpt(paramsOpt) - -fun showBlock(b) = + "ValDefn(" + showSymbol(sym) + ", " + showPath(rhs) + ")" + FunDefn(sym, params, body) then + "FunDefn(" + showSymbol(sym) + ", " + + showParamList(params) + ", " + + showBlock(body) + ")" + ClsLikeDefn(sym, paramsOpt, companion) then + // TODO: print rest of the arguments + "ClsLikeDefn(" + showSymbol(sym) + ", " + + if paramsOpt is + Some(params) then "(" + showParamList(params) + ")" + None then "()" + + ", " + + "TODO" + ")" + +fun showOptBlock(ob: Opt[Block]) = + if ob is Some(b) then showBlock(b) else "None" + +fun showArm(pair: Case -> Block) = + if pair is [cse, body] then showCase(cse) + " -> " + showBlock(body) else "" + +fun showBlock(b: Block): Str = if b is - Assign(lhs, rhs, rest) then - "let " + showSymbol(lhs) + " = " + showResult(rhs) + "\n" + showBlock(rest) - Define(d, rest) then - showDefn(d) + "\n" + showBlock(rest) - Return(res, _) then - showResult(res) Match(scrut, arms, dflt, rest) then - "if " + showPath(scrut) + " is\n" - + arms.map(showArm).join("\n") + - (if dflt is Some(db) then "\nelse " + showBlock(db) else "") + - "\n" + showBlock(rest) - End() then "" - x then x - -fun printCode(p: Block) = - let s = showBlock(p) in - console.log(s) + "Match(" + + showPath(scrut) + ", " + + "[" + arms.map(showArm).join(", ") + "], " + + showOptBlock(dflt) + ", " + + showBlock(rest) + ")" + Return(res, implct) then + "Return(" + showResult(res) + ", " + showBool(implct) + ")" + Assign(lhs, rhs, rest) then + "Assign(" + showSymbol(lhs) + ", " + showResult(rhs) + ", " + showBlock(rest) + ")" + Define(defn, rest) then + "Define(" + showDefn(defn) + ", " + showBlock(rest) + ")" + End() then "End" + +fun show(x) = + if x is + Symbol then showSymbol(x) + Path then showPath(x) + Result then showResult(x) + Case then showCase(x) + Defn then showDefn(x) + Block then showBlock(x) + else + "" + +fun printCode(x) = print(show(x)) + +fun compile(p: Block) = ??? \ No newline at end of file diff --git a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls index a907b98bc4..21e4d1e5aa 100644 --- a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls +++ b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls @@ -3,7 +3,6 @@ //│ Block = class Block { //│ Symbol: fun Symbol { class: class Symbol }, -//│ ClassSymbol: fun ClassSymbol { class: class ClassSymbol }, //│ Arg: fun Arg { class: class Arg }, //│ Case: class Case, //│ Lit: fun Lit { class: class Lit }, @@ -23,7 +22,6 @@ //│ ClsLikeDefn: fun ClsLikeDefn { class: class ClsLikeDefn }, //│ FunDefn: fun FunDefn { class: class FunDefn }, //│ ClsLikeBody: fun ClsLikeBody { class: class ClsLikeBody }, -//│ Arm: fun Arm { class: class Arm }, //│ Block: class Block, //│ Match: fun Match { class: class Match }, //│ Return: fun Return { class: class Return }, @@ -32,42 +30,7 @@ //│ End: fun End { class: class End } //│ } //│ ShapeSet = class ShapeSet { ShapeSet: fun ShapeSet { class: class ShapeSet } } -import "../../mlscript-compile/Option.mls" -open Option -Block.printCode(Block.Return(Block.ValueLit(1),false)) -//│ > 1 - -Block.printCode(Block.Define(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x")], Block.Return(Block.ValueRef(Block.Symbol("x"))), false), Block.Return(Block.ValueRef(Block.Symbol("x"))), false)) -//│ > fun f(x) = x -//│ > x - -Block.printCode( - Block.Define( - Block.ClsLikeDefn(Block.Symbol("C"), Some([Block.Symbol("x"), Block.Symbol("y")]), None), - Block.Assign( - Block.Symbol("x"), - Block.Instantiate( - Block.ValueRef(Block.Symbol("C")), [Block.Arg(Some(false), Block.ValueLit("1")), Block.Arg(Some(false), Block.ValueLit("2"))] - ), - Block.Return( - Block.Select(Block.ValueRef(Block.Symbol("x")), Block.Symbol("y")) - false - ) - ) - ) -) -//│ > class C(x, y) -//│ > let x = new C(1,2) -//│ > x.y - -Block.printCode(Block.Return(Block.Tuple([Block.Arg(None, Block.ValueLit(1)), Block.Arg(None, Block.ValueLit(2))]), false)) -//│ > [1,2] - -Block.printCode(Block.Match(Block.ValueLit(2), [Block.Arm(Block.Lit(1), Block.Return(Block.ValueLit(1), false)), Block.Arm(Block.Lit(2), Block.Return(Block.ValueLit(2), false))], Some(Block.Return(Block.ValueLit(3), false)), Block.End())) -//│ > if 2 is -//│ > 1 then 1 -//│ > 2 then 2 -//│ > else 3 -//│ > +Block.printCode(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x")], Block.Return(Block.ValueLit(1), false))) +//│ > FunDefn(Symbol("f"), [Symbol("x")], Return(Lit(1), false)) From ff58a1ab503b365a7c209f8fe0ab843315bec107 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 27 Nov 2025 22:03:46 +0800 Subject: [PATCH 188/268] Reapply "Merge remote-tracking branch 'origin/instrument' into instrument" This reverts commit a3925e5da38dfbb0b92d9a0ddf59aee45ccabedf. --- .../scala/hkmc2/codegen/Instrumentation.scala | 148 +++++++++--------- .../src/test/mlscript-compile/Block.mls | 16 +- .../src/test/mlscript-compile/ShapeSet.mls | 6 + .../src/test/mlscript/staging/Functions.mls | 8 +- 4 files changed, 91 insertions(+), 87 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 6b0d15f74c..f6ffb6fde5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -129,6 +129,8 @@ class InstrumentationImpl(using State): def fnConcat(p1: Path, p2: Path)(k: Path => Block): Block = blockCall("concat", Ls(p1, p2))(k) + def fnPruneBadArms(arms: Path)(k: Path => Block): Block = + shapeSetCall("pruneBadArms", Ls(arms))(k) def fnMrg(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = shapeSetCall("mrg", Ls(s1, s2))(s => k(ShapeSet(s))) def fnSel(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = @@ -137,18 +139,15 @@ class InstrumentationImpl(using State): shapeSetCall("filter", Ls(s1, s2))(s => k(ShapeSet(s))) def fnUnion(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = shapeSetCall("union", Ls(s1, s2))(s => k(ShapeSet(s))) - def fnFlat(s: Ls[ShapeSet])(k: ShapeSet => Block): Block = - tuple(s): tup => - shapeSetCall("flat", Ls(tup))(s => k(ShapeSet(s))) // transformation helpers - def transformSymbol[S <: Symbol](sym: S)(k: Path => Block): Block = + def transformSymbol[S <: Symbol](sym: S, symName: Str = "sym")(k: Path => Block): Block = sym match case clsSym: ClassSymbol => - stageParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => - blockCtor("ClassSymbol", Ls(toValue(sym.nme), paramsOpt))(k) - case _ => blockCtor("Symbol", Ls(toValue(sym.nme)), "sym")(k) + transformParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => + blockCtor("ClassSymbol", Ls(toValue(sym.nme), paramsOpt), symName)(k) + case _ => blockCtor("Symbol", Ls(toValue(sym.nme)), symName)(k) def transformOption[A](xOpt: Opt[A], f: A => (Path => Block) => Block)(k: Path => Block): Block = xOpt match @@ -157,78 +156,77 @@ class InstrumentationImpl(using State): // instrumentation rules - def ruleLit(l: Value.Lit)(k: StagedPath => Block): Block = + def ruleLit(l: Value.Lit, symName: String = "lit")(k: StagedPath => Block): Block = shapeLit(l): sp => blockCtor("ValueLit", Ls(l)): cde => - StagedPath(sp, cde, "lit")(k) + StagedPath(sp, cde, symName)(k) // not in formalization - def ruleVar(r: Value.Ref)(k: StagedPath => Block): Block = + def ruleVar(r: Value.Ref, symName: String = "var")(k: StagedPath => Block): Block = val Value.Ref(l, disamb) = r transformSymbol(disamb.getOrElse(l)): sym => blockCtor("ValueRef", Ls(sym)): cde => // variable defined outside of scope, may be a reference to a class shapeDyn(): sp => - StagedPath(sp, cde, "var")(k) + StagedPath(sp, cde, symName)(k) - def ruleTup(t: Tuple)(using Context)(k: StagedPath => Block): Block = + def ruleTup(t: Tuple, symName: String = "tup")(using Context)(k: StagedPath => Block): Block = assert(!t.mut, "mutable tuple not supported") transformArgs(t.elems): xs => shapeArr(xs.map(_.shapes)): sp => tuple(xs.map(_.code)): codes => blockCtor("Tuple", Ls(codes)): cde => - StagedPath(sp, cde, "tup")(k) + StagedPath(sp, cde, symName)(k) - def ruleSel(s: Select)(using Context)(k: StagedPath => Block): Block = + def ruleSel(s: Select, symName: String = "sel")(using Context)(k: StagedPath => Block): Block = val Select(p, i @ Tree.Ident(name)) = s transformPath(p): x => shapeLit(toValue(name)): n => fnSel(x.shapes, n): sp => blockCtor("Symbol", Ls(toValue(name))): name => blockCtor("Select", Ls(x.code, name)): cde => - StagedPath(sp, cde, "sel")(k) + StagedPath(sp, cde, symName)(k) - def ruleDynSel(d: DynSelect)(using Context)(k: StagedPath => Block): Block = + def ruleDynSel(d: DynSelect, symName: String = "dynsel")(using Context)(k: StagedPath => Block): Block = transformPath(d.qual): x => transformPath(d.fld): y => fnSel(x.shapes, y.shapes): sp => blockCtor("DynSelect", Ls(x.code, y.code, toValue(d.arrayIdx))): cde => - StagedPath(sp, cde, "dynsel")(k) + StagedPath(sp, cde, symName)(k) - def ruleInst(i: Instantiate)(using Context)(k: StagedPath => Block): Block = + def ruleInst(i: Instantiate, symName: String = "inst")(using Context)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i assert(!mut, "mutable instantiation not supported") transformArgs(args): xs => - tuple(xs.map(_.shapes)): shapes => - val sym = cls match - // TODO: if class is staged, we can just use Symbol without storing the arguments - case Value.Ref(l, S(disamb)) => transformSymbol(disamb) - case s: Select if s.symbol.isDefined => transformSymbol(s.symbol.get) - case _ => transformSymbol(TempSymbol(N, "TODO")) - sym: sym => - shapeClass(sym, xs.map(_.shapes)): sp => - // reuse instrumentation logic, shape of cls is discarded - // possible to skip this? this uses ruleVar, which is not in formalization - transformPath(cls): cls => - tuple(xs.map(_.code)): codes => - blockCtor("Instantiate", Ls(cls.code, codes)): cde => - StagedPath(sp, cde, "inst")(k) - - def ruleReturn(r: Return)(using Context)(k: (StagedPath, Context) => Block): Block = + val sym = cls match + // TODO: if class is staged, we can just use Symbol without storing the arguments + case Value.Ref(l, S(disamb)) => transformSymbol(disamb) + case s: Select if s.symbol.isDefined => transformSymbol(s.symbol.get) + case _ => transformSymbol(TempSymbol(N, "TODO")) + sym: sym => + shapeClass(sym, xs.map(_.shapes)): sp => + // reuse instrumentation logic, shape of cls is discarded + // possible to skip this? this uses ruleVar, which is not in formalization + transformPath(cls): cls => + tuple(xs.map(_.code)): codes => + blockCtor("Instantiate", Ls(cls.code, codes)): cde => + StagedPath(sp, cde, symName)(k) + + def ruleReturn(r: Return, symName: String = "return")(using Context)(k: (StagedPath, Context) => Block): Block = transformResult(r.res): x => blockCtor("Return", Ls(x.code, toValue(false))): cde => - StagedPath(x.shapes, cde, "return")(k(_, summon)) + StagedPath(x.shapes, cde, symName)(k(_, summon)) - def ruleMatch(m: Match)(using Context)(k: (StagedPath, Context) => Block): Block = + def ruleMatch(m: Match, symName: String = "match")(using Context)(k: (StagedPath, Context) => Block): Block = val Match(p, ks, dflt, rest) = m transformPath(p): x => ruleBranches(x, p, ks, dflt): (stagedMatch, ctx1) => transformBlock(rest)(using ctx1): (z, ctx2) => fnMrg(stagedMatch.shapes, z.shapes): sp => fnConcat(stagedMatch.code, z.code): cde => - StagedPath(sp, cde)(k(_, ctx2)) + StagedPath(sp, cde, symName)(k(_, ctx2)) - def ruleAssign(a: Assign)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def ruleAssign(a: Assign, symName: String = "assign")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Assign(x, r, b) = a transformResult(r): y => transformSymbol(x): xSym => @@ -243,7 +241,7 @@ class InstrumentationImpl(using State): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => - StagedPath(z.shapes, cde, "assign")(k(_, ctx)) + StagedPath(z.shapes, cde, symName)(k(_, ctx)) case N => StagedPath(y.shapes, xStaged): x2 => // propagate shape information for future references to x @@ -251,9 +249,9 @@ class InstrumentationImpl(using State): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => - StagedPath(z.shapes, cde, "assign")(k(_, ctx)) + StagedPath(z.shapes, cde, symName)(k(_, ctx)) - def ruleLet(x: BlockMemberSymbol, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def ruleLet(x: BlockMemberSymbol, b: Block, symName: String = "_let")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = shapeBot(): bot => transformSymbol(x): xSym => StagedPath(bot, xSym): y => @@ -262,12 +260,12 @@ class InstrumentationImpl(using State): transformBlock(b): (z, ctx) => blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => blockCtor("Assign", Ls(xSym, undefined, z.code)): cde => - StagedPath(z.shapes, cde, "_let")(k(_, summon)) + StagedPath(z.shapes, cde, symName)(k(_, summon)) - def ruleEnd()(k: StagedPath => Block): Block = + def ruleEnd(symName: String = "end")(k: StagedPath => Block): Block = shapeBot(): sp => blockCtor("End", Ls()): cde => - StagedPath(sp, cde, "end")(k) + StagedPath(sp, cde, symName)(k) def ruleBlk(b: Block)(using Context)(k: Path => Block): Block = transformBlock(b)(k apply _.code) @@ -276,19 +274,22 @@ class InstrumentationImpl(using State): assert(cls.companion.isEmpty, "nested module not supported") (Define(cls, _)): transformBlock(rest): p => - transformSymbol(cls.sym): c => - stageParamsOpt(cls.paramsOpt): paramsOpt => + transformParamsOpt(cls.paramsOpt): paramsOpt => + transformSymbol(cls.isym): c => optionNone(): none => // TODO: handle companion object - blockCtor("ClsLikeDefn", Ls(c, paramsOpt, none)): cls => + blockCtor("ClsLikeDefn", Ls(c, none)): cls => blockCtor("Define", Ls(cls, p.code))(k) - def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block])(using Context)(k: (StagedPath, Context) => Block): Block = + def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block], symName: String = "branches")(using Context)(k: (StagedPath, Context) => Block): Block = arms.map((cse, block) => (f: StagedPath => Context => Block) => (ruleBranch(x, p, cse, block)(using _)).flip(f(_)(_))) .collectApply .pipe(_.flip(summon)): arms => ctx => - fnFlat(arms.map(_.shapes)): sp => - tuple(arms.map(_.code)): arms => + tuple(arms.map(_.p)): tup => + fnPruneBadArms(tup): res => + val result = StagedPath(res) + val sp = result.shapes + val arms = result.code blockCtor("End", Ls()): e => // TODO: use transformOption here def dfltStaged(k: (Path, Context) => Block) = dflt match @@ -297,30 +298,29 @@ class InstrumentationImpl(using State): case N => optionNone()(k(_, ctx)) dfltStaged: (dflt, ctx) => blockCtor("Match", Ls(x.code, arms, dflt, e)): m => - StagedPath(sp, m, "branches")(k(_, ctx)) + StagedPath(sp, m, symName)(k(_, ctx)) - def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block, symName: String = "branch")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = transformCase(cse): cse => fnFilter(x.shapes, cse): sp => - StagedPath(sp, x.code): x0 => - call(x0.shapes.p.selSN("isEmpty"), Ls()): scrut => - ruleEnd(): e => - tuple(Ls(cse, e.code)): armStaged => - // returns Case -> Block, instead of End as in formalization - StagedPath(e.shapes, armStaged): badArm => - val arm = Case.Lit(Tree.BoolLit(true)) -> k(badArm, ctx) - (Match(scrut, Ls(arm), N, _)): - given Context = ctx.clone() += p -> x0 - transformBlock(b): (y1, ctx) => - // TODO: use Arm type instead of Tup - tuple(Ls(cse, y1.code)): cde => - StagedPath(y1.shapes, cde, "branch")(k(_, ctx.clone() -= p)) - - // not in formalization - // this partially applies rules from filter to account for difference in Block.Case and Match pattern in the formalization - // to avoid defining the `_` pattern in Block.Case, we use the fact that filter(s, _) = s + call(sp.p.selSN("isEmpty"), Ls()): scrut => + ruleEnd(): e => + val res = new TempSymbol(N, "tmp") + val arm = Case.Lit(Tree.BoolLit(true)) -> Assign(res, e.p, End()) + val dflt = + StagedPath(sp, x.code): x0 => + given Context = ctx.clone() += p -> x0 + transformBlock(b): (y1, ctx) => + // TODO: use Arm type instead of Tup + tuple(Ls(cse, y1.code)): cde => + StagedPath(y1.shapes, cde, symName): ret => + Assign(res, ret.p, End()) + (Match(scrut, Ls(arm), S(dflt), _)): + k(StagedPath(Value.Ref(res)), ctx.clone() -= p) + + // this partially applies rules from filter to account for difference between Block.Case and Match pattern in the formalization + // to avoid defining the `_` pattern in Block.Case, we apply filter(s, _) = s def ruleWildCard(x: StagedPath, p: Path, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = - // when pattern = _, x0 = x call(x.shapes.p.selSN("isEmpty"), Ls()): scrut => val arm = Case.Lit(Tree.BoolLit(true)) -> ruleEnd()(p => Return(p.p, false)) (Match(scrut, Ls(arm), N, _)): @@ -359,11 +359,11 @@ class InstrumentationImpl(using State): def transformArgs(args: Ls[Arg])(using Context)(k: Ls[StagedPath] => Block): Block = args.map(transformArg).collectApply(k) - def stageParamList(ps: ParamList)(k: Path => Block) = + def transformParamList(ps: ParamList)(k: Path => Block) = ps.params.map(p => transformSymbol(p.sym)).collectApply(tuple(_)(k)) - def stageParamsOpt(pOpt: Opt[ParamList])(k: Path => Block) = - transformOption(pOpt, stageParamList)(k) + def transformParamsOpt(pOpt: Opt[ParamList])(k: Path => Block) = + transformOption(pOpt, transformParamList)(k) def transformCase(cse: Case)(using Context)(k: Path => Block): Block = cse match @@ -427,7 +427,7 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): case d @ Define(defn, rest) => defn match // find modules with staged annotation - case c: ClsLikeDefn if c.companion.isDefined => + case c: ClsLikeDefn if c.companion.exists(_.isym.defn.exists(_.hasStagedModifier.isDefined)) => val sym = c.sym.subst val companion = c.companion.get val (stagedMethods, debugPrintCode) = companion.methods diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index ea54c8b3f6..dd02e04171 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -12,16 +12,14 @@ type Opt[A] = Option[A] // dependancies referenced in Block classes, referencing implementation in Term.mls -class Symbol(val name: Str) -type Ident = Symbol -// this is so that we're able to retrieve information about the class from the symbol -class ClassSymbol(val name: Str, val args: Opt[Array[Symbol]]) extends Symbol(name) - type Literal = null | undefined | Str | Int | Num | Bool type ParamList = Array[Symbol] -// Classes defined in Block.scala +class Symbol(val name: Str) +type Ident = Symbol +// this is so that we're able to retrieve information about the class from the symbol +class ClassSymbol(val name: Str, val paramsOpt: Opt[ParamList]) extends Symbol(name) class Arg(val spread: Opt[Bool], val value: Path) @@ -29,7 +27,7 @@ class Case with constructor Lit(val lit: Literal) Cls(val cls: Symbol, val path: Path) - Tup(val len: Int) // TODO: remove inf? + Tup(val len: Int) class Result with constructor @@ -47,8 +45,8 @@ class Path extends Result with class Defn with constructor ValDefn(val sym: Symbol, val rhs: Path) - ClsLikeDefn(val sym: Symbol, val paramsOpt: Opt[ParamList], val companion: Opt[ClsLikeBody]) // unused - FunDefn(val sym: Symbol, val params: Array[ParamList], val body: Block) + ClsLikeDefn(val sym: ClassSymbol, val paramsOpt: Opt[ParamList], val companion: Opt[ClsLikeBody]) // unused + FunDefn(val sym: Symbol, val params: ParamList, val body: Block, val stage: Bool) class ClsLikeBody(val isym: Symbol, val methods: Array[FunDefn], val publicFields: Array[[Symbol, Symbol]]) // unused diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls index ed97d00cb1..7ed0f5c60e 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -78,3 +78,9 @@ fun sel(s1: ShapeSet, s2: ShapeSet) = fun mrg(s1: ShapeSet, s2: ShapeSet) = mkDyn() // TODO + +open Block { Block } + +fun pruneBadArms(arms: Array[[ShapeSet, Block]]) = + val rem = arms.filter(arm => not (arm.0.isEmpty() and arm.1 is End)) + [flat(rem.map(_.0)), rem.map(_.1)] diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 6db1604147..cdfd7583c8 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -106,20 +106,20 @@ staged module Expressions with :staging class Outside(a) staged module ClassInstrumentation with - class Class(a, b) + class Inside(a, b) class NoArg fun inst1() = new Outside(1) fun inst2() = new NoArg //│ > class NoArg() //│ > -//│ > class Class(a, b) +//│ > class Inside(a, b) //│ > //│ > Class(Outside, [Lit(1)]) //│ > new Outside(1) //│ > Class(NoArg, []) //│ > new ClassInstrumentation.NoArg() -// collision with class name? +// debug printing fails, collision with class name? :js :staging :fixme @@ -128,7 +128,7 @@ staged module A with fun f() = 1 //│ ═══[RUNTIME ERROR] TypeError: A1.f_gen is not a function -// unable to reference the class when calling the instrumented function for debugging +// debug printing fails, unable to reference the class when calling the instrumented function :js :staging :fixme From 50b6fd531421a550eae1600c804f7460e189d546 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 27 Nov 2025 22:04:31 +0800 Subject: [PATCH 189/268] fix static impl --- hkmc2/shared/src/test/mlscript-compile/Shape.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index 223940c38c..4d67c40aa4 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -81,7 +81,7 @@ fun static(s: Shape) = if s is Dyn then false Lit(l) then not (l is Str and isPrimitiveType(l)) // redundant bracket? - Class(_, params) then params.every(static(_.1)) + Class(_, params) then params.every(static) Arr(shapes) then shapes.every(static) open Block { Case } From 087c9604653b50b6d95cfbe15188f4b49a2645da Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 26 Nov 2025 23:09:28 +0800 Subject: [PATCH 190/268] add inf back to Tup still need a test case for it --- .../scala/hkmc2/codegen/Instrumentation.scala | 24 ++-- .../src/test/mlscript-compile/Block.mls | 4 +- .../src/test/mlscript-compile/Shape.mls | 33 +++-- .../src/test/mlscript-compile/ShapeSet.mls | 4 +- .../src/test/mlscript/staging/Functions.mls | 120 +++++------------- 5 files changed, 68 insertions(+), 117 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index f6ffb6fde5..f7fe3c7631 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -120,9 +120,9 @@ class InstrumentationImpl(using State): shapeSetCall("mkDyn", Ls())(s => k(ShapeSet(s))) def shapeLit(p: Path)(k: ShapeSet => Block): Block = shapeSetCall("mkLit", Ls(p))(s => k(ShapeSet(s))) - def shapeArr(ps: Ls[ShapeSet])(k: ShapeSet => Block): Block = + def shapeArr(ps: Ls[ShapeSet], inf: Bool)(k: ShapeSet => Block): Block = tuple(ps, "test"): tup => - shapeSetCall("mkArr", Ls(tup))(s => k(ShapeSet(s))) + shapeSetCall("mkArr", Ls(tup, toValue(inf)))(s => k(ShapeSet(s))) def shapeClass(cls: Path, params: Ls[ShapeSet])(k: ShapeSet => Block): Block = tuple(params): params => shapeSetCall("mkClass", Ls(cls, params))(s => k(ShapeSet(s))) @@ -173,8 +173,8 @@ class InstrumentationImpl(using State): def ruleTup(t: Tuple, symName: String = "tup")(using Context)(k: StagedPath => Block): Block = assert(!t.mut, "mutable tuple not supported") transformArgs(t.elems): xs => - shapeArr(xs.map(_.shapes)): sp => - tuple(xs.map(_.code)): codes => + shapeArr(xs.map(_._1.shapes), xs.exists(_._2)): sp => + tuple(xs.map(_._1.code)): codes => blockCtor("Tuple", Ls(codes)): cde => StagedPath(sp, cde, symName)(k) @@ -204,11 +204,11 @@ class InstrumentationImpl(using State): case s: Select if s.symbol.isDefined => transformSymbol(s.symbol.get) case _ => transformSymbol(TempSymbol(N, "TODO")) sym: sym => - shapeClass(sym, xs.map(_.shapes)): sp => + shapeClass(sym, xs.map(_._1.shapes)): sp => // reuse instrumentation logic, shape of cls is discarded // possible to skip this? this uses ruleVar, which is not in formalization transformPath(cls): cls => - tuple(xs.map(_.code)): codes => + tuple(xs.map(_._1.code)): codes => blockCtor("Instantiate", Ls(cls.code, codes)): cde => StagedPath(sp, cde, symName)(k) @@ -348,15 +348,15 @@ class InstrumentationImpl(using State): case c: Call => ??? case _ => ??? // not supported - def transformArg(a: Arg)(using Context)(k: StagedPath => Block): Block = + def transformArg(a: Arg)(using Context)(k: ((StagedPath, Bool)) => Block): Block = val Arg(spread, value) = a - optionNone(): opt => + transformOption(spread, bool => assign(toValue(bool))): spreadStaged => transformPath(value): value => - blockCtor("Arg", Ls(opt, value.code)): cde => - StagedPath(value.shapes, cde)(k) + blockCtor("Arg", Ls(spreadStaged, value.code)): cde => + StagedPath(value.shapes, cde): res => + k(res, spread.isDefined) - // provides list of shapes and list of codes to continuation - def transformArgs(args: Ls[Arg])(using Context)(k: Ls[StagedPath] => Block): Block = + def transformArgs(args: Ls[Arg])(using Context)(k: Ls[(StagedPath, Bool)] => Block): Block = args.map(transformArg).collectApply(k) def transformParamList(ps: ParamList)(k: Path => Block) = diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index dd02e04171..9fd280b9ff 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -27,7 +27,7 @@ class Case with constructor Lit(val lit: Literal) Cls(val cls: Symbol, val path: Path) - Tup(val len: Int) + Tup(val len: Int, val inf: Bool) class Result with constructor @@ -109,7 +109,7 @@ fun showCase(c: Case): Str = if c is Lit(lit) then "Lit(" + showLiteral(lit) + ")" Cls(cls, path) then "Cls(" + showSymbol(cls) + ", " + showPath(path) + ")" - Tup(len) then "Tup(" + len + ")" + Tup(len, inf) then "Tup(" + len + ", " + inf + ")" fun showResult(r: Result): Str = if r is diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index 4d67c40aa4..ed1e3483fe 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -28,31 +28,32 @@ class Shape with constructor Dyn() Lit(val l: Literal) - Arr(val shapes: Array[Shape]) + Arr(val shapes: Array[Shape], val inf: Bool) Class(val sym: ClassSymbol, val params: Array[Shape]) fun show(s: Shape) = if s is Dyn then "Dyn" Lit(lit) then "Lit(" + Block.showLiteral(lit) + ")" - Arr(shapes) then "Arr(" + shapes.map(show).join(", ") + ")" + Arr(shapes, inf) then "Arr([" + shapes.map(show).join(", ") + "], " + inf + ")" Class(sym, params) then "Class(" + showSymbol(sym) + ", [" + params.map(show).join(", ") + "])" fun zipMrg[A](a: Array[A], b: Array[A]): Array[A] = a.map((a, i, _) => mrg2(a, b.at(i))) -fun mrg2(s1: Shape, s2: Shape) = if s1 - == s2 then s1 - is - Lit(l) and s2 is Class(sym, params) +fun mrg2(s1: Shape, s2: Shape) = + // we want different objects with same parameters to be equal + if show(s1) == show(s2) then s1 + else if [s1, s2] is + [Lit(l), Class(sym, params)] and isPrimitiveTypeOf(sym, l) then Class(sym, params) - Class(sym1, ps) and s2 is Class(sym2, s2) + [Class(sym1, ps), Class(sym2, s2)] and sym1.name == sym2.name then Class(sym1, ps.map(p => [p.0, zipMrg(p.1, s2)])) - Arr(s1) and s2 is Arr(s2) + [Arr(s1, false), Arr(s2, false)] and s1.length == s2.length - then Arr(zipMrg(s1, s2)) + then Arr(zipMrg(s1, s2), false) else Dyn() fun mrg(s1: Array[Shape]) = @@ -67,10 +68,11 @@ fun sel(s1: Shape, s2: Shape): Array[Shape] = is i then [params.(i)] [Dyn, Lit(n)] and n is Str then [Dyn()] - [Arr(shapes), Lit(n)] and n is Int + [Arr(shapes, false), Lit(n)] and n is Int then [shapes.(n)] - [Arr(shapes), Dyn] then + [Arr(shapes, false), Dyn] then shapes + [Arr(shapes, true), _] then [Dyn()] // TODO [Dyn, Lit(n)] and n is Int then [Dyn()] [Dyn, Dyn] @@ -82,7 +84,8 @@ fun static(s: Shape) = Dyn then false Lit(l) then not (l is Str and isPrimitiveType(l)) // redundant bracket? Class(_, params) then params.every(static) - Arr(shapes) then shapes.every(static) + Arr(shapes, false) then shapes.every(static) + Arr(shapes, true) then false // TODO open Block { Case } @@ -91,13 +94,15 @@ fun silh(p: Case): Shape = if p is Block.Cls(sym, path) then val size = if sym.args is Some(i) then i else 0 Class(sym, Array(size).fill(Dyn)) - Block.Tup(n) then Arr(Array(n).fill(Dyn)) + Block.Tup(n, inf) then Arr(Array(n).fill(Dyn), inf) fun filter(s: Shape, p: Case): Array[Shape] = if [s, p] is [Lit(l1), Block.Lit(l2)] and l1 == l2 then [s] [Lit(l), Block.Cls(c, _)] and isPrimitiveTypeOf(c, l) then [s] - [Arr(ls), Block.Tup(n)] and ls.length == n then [s] + [Arr(ls, false), Block.Tup(n, false)] and ls.length == n then [s] + [Arr(ls, true), _] then [s] // TODO + [_, Block.Tup(ls, true)] then [s] // TODO [Class(c1, _), Block.Cls(c2, _)] and c1.name == c2.name then [s] [Dyn, _] then [silh(p)] else [] diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls index 7ed0f5c60e..f11d334b50 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -54,11 +54,11 @@ fun mkDyn() = lift(Dyn()) fun mkLit(l) = lift(Lit(l)) -fun mkArr(shapes: Array[ShapeSet]) = +fun mkArr(shapes: Array[ShapeSet], inf: Bool) = shapes .map(_.underlying.values().toArray()) |> prod - .map(x => Arr(x)) + .map(x => Arr(x, inf)) |> liftMany fun mkClass(sym: ClassSymbol, params: Array[ShapeSet]) = diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index cdfd7583c8..74f7239fe9 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -1,40 +1,7 @@ -:js -:staging - -//│ Block = class Block { -//│ Symbol: fun Symbol { class: class Symbol }, -//│ ClassSymbol: fun ClassSymbol { class: class ClassSymbol }, -//│ Arg: fun Arg { class: class Arg }, -//│ Case: class Case, -//│ Lit: fun Lit { class: class Lit }, -//│ Cls: fun Cls { class: class Cls }, -//│ Tup: fun Tup { class: class Tup }, -//│ Result: class Result, -//│ Call: fun Call { class: class Call }, -//│ Instantiate: fun Instantiate { class: class Instantiate }, -//│ Tuple: fun Tuple { class: class Tuple }, -//│ Path: class Path, -//│ Select: fun Select { class: class Select }, -//│ DynSelect: fun DynSelect { class: class DynSelect }, -//│ ValueRef: fun ValueRef { class: class ValueRef }, -//│ ValueLit: fun ValueLit { class: class ValueLit }, -//│ Defn: class Defn, -//│ ValDefn: fun ValDefn { class: class ValDefn }, -//│ ClsLikeDefn: fun ClsLikeDefn { class: class ClsLikeDefn }, -//│ FunDefn: fun FunDefn { class: class FunDefn }, -//│ ClsLikeBody: fun ClsLikeBody { class: class ClsLikeBody }, -//│ Arm: fun Arm { class: class Arm }, -//│ Block: class Block, -//│ Match: fun Match { class: class Match }, -//│ Return: fun Return { class: class Return }, -//│ Assign: fun Assign { class: class Assign }, -//│ Define: fun Define { class: class Define }, -//│ End: fun End { class: class End } -//│ } -//│ ShapeSet = class ShapeSet { ShapeSet: fun ShapeSet { class: class ShapeSet } } -:slot :js +:staging +val x = [1, 2, 3] staged module Expressions with fun lit() = 1 fun assign() = @@ -44,63 +11,38 @@ staged module Expressions with fun _var() = val x = 1 x - fun tup() = [1, 2] + fun tup1() = [1, 2] + fun tup2() = [1, ..x] fun dynsel() = [1].(0) - fun match() = + fun match1() = if 9 is 8 then 1 9 then 2 Int then 3 Bool then 4 + else 0 + fun match2() = + if [...x] is + [] then 1 // [1, 2] then 5 // TODO: Case.Tup, needs handling for Label, Break else 0 -//│ Pretty Lowered: -//│ -//│ define staged class Expressions in -//│ set tmp = Expressions.lit_gen() in -//│ set tmp1 = shapeSet.printShapeSet(tmp.(0)) in -//│ set tmp2 = Block.printCode(tmp.(1)) in -//│ set tmp3 = Expressions.assign_gen() in -//│ set tmp4 = shapeSet.printShapeSet(tmp3.(0)) in -//│ set tmp5 = Block.printCode(tmp3.(1)) in -//│ set tmp6 = Expressions._var_gen() in -//│ set tmp7 = shapeSet.printShapeSet(tmp6.(0)) in -//│ set tmp8 = Block.printCode(tmp6.(1)) in -//│ set tmp9 = Expressions.tup_gen() in -//│ set tmp10 = shapeSet.printShapeSet(tmp9.(0)) in -//│ set tmp11 = Block.printCode(tmp9.(1)) in -//│ set tmp12 = Expressions.dynsel_gen() in -//│ set tmp13 = shapeSet.printShapeSet(tmp12.(0)) in -//│ set tmp14 = Block.printCode(tmp12.(1)) in -//│ set tmp15 = Expressions.match_gen() in -//│ set tmp16 = shapeSet.printShapeSet(tmp15.(0)) in -//│ set tmp17 = Block.printCode(tmp15.(1)) in -//│ set block$res2 = undefined in -//│ end //│ > Lit(1) -//│ > 1 +//│ > Return(Lit(1), false) //│ > Lit(42) -//│ > let x = 42 -//│ > let y = x -//│ > y +//│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) //│ > Dyn -//│ > let x = undefined -//│ > let x = 1 -//│ > x +//│ > Assign(Symbol("x"), Lit(undefined), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false))) //│ > Arr(Lit(1), Lit(2)) -//│ > [1,2] +//│ > Return(Tuple([Lit(1), Lit(2)]), false) +//│ > Arr(Lit(1), Dyn) +//│ > Return(Tuple([Lit(1), Ref(Symbol("x"))]), false) //│ > Lit(1) -//│ > let tmp = [1] -//│ > tmp[0] +//│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) +//│ > Dyn +//│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Lit(9) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End)) //│ > Dyn -//│ > let scrut = 9 -//│ > if scrut is -//│ > _ then undefined -//│ > _ then undefined -//│ > _ then undefined -//│ > _ then undefined -//│ > else 0 -//│ > +//│ > Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [], Return(Lit(0), false), End)) +//│ x = [1, 2, 3] :js :staging @@ -110,14 +52,12 @@ staged module ClassInstrumentation with class NoArg fun inst1() = new Outside(1) fun inst2() = new NoArg -//│ > class NoArg() -//│ > -//│ > class Inside(a, b) -//│ > -//│ > Class(Outside, [Lit(1)]) -//│ > new Outside(1) -//│ > Class(NoArg, []) -//│ > new ClassInstrumentation.NoArg() +//│ > Define(ClsLikeDefn(ClassSymbol("NoArg"), (), TODO), End) +//│ > Define(ClsLikeDefn(ClassSymbol("Inside":[Symbol("a"), Symbol("b")]), (), TODO), End) +//│ > Class(ClassSymbol("Outside":[Symbol("a")]), [Lit(1)]) +//│ > Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) +//│ > Class(ClassSymbol("NoArg"), []) +//│ > Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), Symbol("NoArg")), []), false) // debug printing fails, collision with class name? :js @@ -135,4 +75,10 @@ staged module A with module A with staged module B with fun f() = 1 -//│ /!!!\ Uncaught error: java.lang.AssertionError: assertion failed: nested module not supported +//│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' +//│ ╟── which references the symbol introduced here +//│ ║ l.76: staged module B with +//│ ║ ^^^^^^ +//│ ║ l.77: fun f() = 1 +//│ ╙── ^^^^^^^^^^^^^^^ +//│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From 302e3103a2b40297dad252d8bb73e386b5e7f527 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 27 Nov 2025 01:02:31 +0800 Subject: [PATCH 191/268] fix showArg printing --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 9fd280b9ff..6f528ed2ec 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -98,8 +98,12 @@ fun showPath(p: Path): Str = "Lit(" + showLiteral(lit) + ")" fun showArg(arg: Arg) = - if arg.spread is Some(true) then "..." + showPath(arg.value) - else showPath(arg.value) + if arg.spread is + Some(true) then "..." + Some(false) then ".." + else "" + + showPath(arg.value) + fun showArgs(args: Array[Arg]) = "[" + args.map(showArg).join(", ") + "]" From 4d8e46c0fa9613c754b9ec487c38a6c5bfec82c6 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 27 Nov 2025 01:35:25 +0800 Subject: [PATCH 192/268] add more Tup test cases --- .../scala/hkmc2/codegen/Instrumentation.scala | 22 +++++++++++++++++-- .../src/test/mlscript/staging/Functions.mls | 13 ++++++----- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index f7fe3c7631..2e34cd3e75 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -194,6 +194,15 @@ class InstrumentationImpl(using State): blockCtor("DynSelect", Ls(x.code, y.code, toValue(d.arrayIdx))): cde => StagedPath(sp, cde, symName)(k) + // TODO + def ruleApp(c: Call, symName: String = "app")(using Context)(k: StagedPath => Block): Block = + transformPath(c.fun): fun => + transformArgs(c.args): args => + tuple(args.map(_._1.code)): tup => + shapeDyn(): dyn => + blockCtor("Call", Ls(fun.code, tup)): res => + StagedPath(dyn, res, symName)(k) + def ruleInst(i: Instantiate, symName: String = "inst")(using Context)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i assert(!mut, "mutable instantiation not supported") @@ -345,7 +354,7 @@ class InstrumentationImpl(using State): case p: Path => transformPath(p)(k) case t: Tuple => ruleTup(t)(k) case i: Instantiate => ruleInst(i)(k) - case c: Call => ??? + case c: Call => ruleApp(c)(k) case _ => ??? // not supported def transformArg(a: Arg)(using Context)(k: ((StagedPath, Bool)) => Block): Block = @@ -402,6 +411,14 @@ class InstrumentationImpl(using State): ruleEnd(): b => fnPrintCode(p)(k(b, summon)) + // TODO + // discards result of sub + def transformBegin(b: Begin)(using Context)(k: (StagedPath, Context) => Block): Block = + transformBlock(b.sub): (sub, ctx) => + transformBlock(b.rest): (rest, ctx) => + fnConcat(sub.code, rest.code): block => + StagedPath(rest.shapes, block)(k(_, ctx)) + // ruleBlk? def transformBlock(b: Block)(using Context)(k: StagedPath => Block): Block = transformBlock(b)((p, _) => k(p)) @@ -416,7 +433,8 @@ class InstrumentationImpl(using State): case m: Match => ruleMatch(m)(k) // temporary measure to accept returning an array // use BlockTransformer here? - case Begin(b1, b2) => transformBlock(concat(b1, b2))(k) + case b: Begin => transformBegin(b)(k) + // case Begin(b1, b2) => transformBlock(concat(b1, b2))(k) case _ => ??? // not supported // TODO: rename as InstrumentationTransformer? diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 74f7239fe9..0240b5b0e1 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -24,7 +24,8 @@ staged module Expressions with fun match2() = if [...x] is [] then 1 - // [1, 2] then 5 // TODO: Case.Tup, needs handling for Label, Break + [a, ...] then 2 + // [1, 2] then 5 // TODO: needs handling for Label, Break else 0 //│ > Lit(1) //│ > Return(Lit(1), false) @@ -32,16 +33,16 @@ staged module Expressions with //│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) //│ > Dyn //│ > Assign(Symbol("x"), Lit(undefined), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false))) -//│ > Arr(Lit(1), Lit(2)) +//│ > Arr([Lit(1), Lit(2)], false) //│ > Return(Tuple([Lit(1), Lit(2)]), false) -//│ > Arr(Lit(1), Dyn) +//│ > Arr([Lit(1), Dyn], true) //│ > Return(Tuple([Lit(1), Ref(Symbol("x"))]), false) //│ > Lit(1) //│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) //│ > Dyn //│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Lit(9) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End)) //│ > Dyn -//│ > Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [], Return(Lit(0), false), End)) +//│ > Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Return(Lit(1), false), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Return(Lit(2), false))))], Return(Lit(0), false), End)) //│ x = [1, 2, 3] :js @@ -77,8 +78,8 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.76: staged module B with +//│ ║ l.77: staged module B with //│ ║ ^^^^^^ -//│ ║ l.77: fun f() = 1 +//│ ║ l.78: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From f3ee1c696f7aa68d74d6d96f67026b4d3f1eadb7 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 27 Nov 2025 01:36:20 +0800 Subject: [PATCH 193/268] formatting --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 1 - 1 file changed, 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 6f528ed2ec..033349c0f2 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -103,7 +103,6 @@ fun showArg(arg: Arg) = Some(false) then ".." else "" + showPath(arg.value) - fun showArgs(args: Array[Arg]) = "[" + args.map(showArg).join(", ") + "]" From c7037957e6bd903723b0a65c1d6ec636d5701bf9 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 27 Nov 2025 22:16:46 +0800 Subject: [PATCH 194/268] fix params type in FunDefn --- .../src/test/mlscript-compile/Block.mls | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 033349c0f2..614936b509 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -45,8 +45,8 @@ class Path extends Result with class Defn with constructor ValDefn(val sym: Symbol, val rhs: Path) - ClsLikeDefn(val sym: ClassSymbol, val paramsOpt: Opt[ParamList], val companion: Opt[ClsLikeBody]) // unused - FunDefn(val sym: Symbol, val params: ParamList, val body: Block, val stage: Bool) + ClsLikeDefn(val sym: ClassSymbol, val companion: Opt[ClsLikeBody]) // companion unused + FunDefn(val sym: Symbol, val params: Array[ParamList], val body: Block, val stage: Bool) class ClsLikeBody(val isym: Symbol, val methods: Array[FunDefn], val publicFields: Array[[Symbol, Symbol]]) // unused @@ -128,18 +128,14 @@ fun showDefn(d: Defn): Str = if d is ValDefn(sym, rhs) then "ValDefn(" + showSymbol(sym) + ", " + showPath(rhs) + ")" - FunDefn(sym, params, body) then + FunDefn(sym, params, body, stage) then "FunDefn(" + showSymbol(sym) + ", " + - showParamList(params) + ", " + - showBlock(body) + ")" - ClsLikeDefn(sym, paramsOpt, companion) then + "(" + params.map(showParamList) + "), " + + showBlock(body) + ", " + + stage + ")" + ClsLikeDefn(sym, companion) then // TODO: print rest of the arguments - "ClsLikeDefn(" + showSymbol(sym) + ", " + - if paramsOpt is - Some(params) then "(" + showParamList(params) + ")" - None then "()" - + ", " + - "TODO" + ")" + "ClsLikeDefn(" + showSymbol(sym) + ", " + "TODO" + ")" fun showOptBlock(ob: Opt[Block]) = if ob is Some(b) then showBlock(b) else "None" From c124135f1ecb7fbc4240f32ae635b698f185f91b Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 28 Nov 2025 14:10:38 +0800 Subject: [PATCH 195/268] add Context to ruleEnd --- .../main/scala/hkmc2/codegen/Instrumentation.scala | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 2e34cd3e75..3d67daed62 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -271,10 +271,10 @@ class InstrumentationImpl(using State): blockCtor("Assign", Ls(xSym, undefined, z.code)): cde => StagedPath(z.shapes, cde, symName)(k(_, summon)) - def ruleEnd(symName: String = "end")(k: StagedPath => Block): Block = + def ruleEnd(symName: String = "end")(using Context)(k: (StagedPath, Context) => Block): Block = shapeBot(): sp => blockCtor("End", Ls()): cde => - StagedPath(sp, cde, symName)(k) + StagedPath(sp, cde, symName)(k(_, summon)) def ruleBlk(b: Block)(using Context)(k: Path => Block): Block = transformBlock(b)(k apply _.code) @@ -313,7 +313,7 @@ class InstrumentationImpl(using State): transformCase(cse): cse => fnFilter(x.shapes, cse): sp => call(sp.p.selSN("isEmpty"), Ls()): scrut => - ruleEnd(): e => + ruleEnd(): (e, ctx) => val res = new TempSymbol(N, "tmp") val arm = Case.Lit(Tree.BoolLit(true)) -> Assign(res, e.p, End()) val dflt = @@ -331,7 +331,7 @@ class InstrumentationImpl(using State): // to avoid defining the `_` pattern in Block.Case, we apply filter(s, _) = s def ruleWildCard(x: StagedPath, p: Path, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = call(x.shapes.p.selSN("isEmpty"), Ls()): scrut => - val arm = Case.Lit(Tree.BoolLit(true)) -> ruleEnd()(p => Return(p.p, false)) + val arm = Case.Lit(Tree.BoolLit(true)) -> ruleEnd()((p, _) => Return(p.p, false)) (Match(scrut, Ls(arm), N, _)): given Context = ctx.clone() += p -> x transformBlock(b): (y1, ctx) => @@ -408,8 +408,8 @@ class InstrumentationImpl(using State): ruleLet(x, Assign(x, r, d.rest))(k) case c: ClsLikeDefn => ruleCls(c, d.rest): p => - ruleEnd(): b => - fnPrintCode(p)(k(b, summon)) + ruleEnd(): (b, ctx) => + fnPrintCode(p)(k(b, ctx)) // TODO // discards result of sub @@ -429,7 +429,7 @@ class InstrumentationImpl(using State): case r: Return => ruleReturn(r)(k) case a: Assign => ruleAssign(a)(k) case d: Define => transformDefine(d)(k) - case End(_) => ruleEnd()(k2) + case End(_) => ruleEnd()(k) case m: Match => ruleMatch(m)(k) // temporary measure to accept returning an array // use BlockTransformer here? From 45b7b5e71baaba260250061bd5bbbc35b2d97e67 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 28 Nov 2025 16:15:30 +0800 Subject: [PATCH 196/268] uppdate Match rules this implements the rest function that narrows the shape as more match statements are processed --- .../scala/hkmc2/codegen/Instrumentation.scala | 92 ++++++++++--------- .../src/test/mlscript-compile/Shape.mls | 12 +++ .../src/test/mlscript-compile/ShapeSet.mls | 2 + .../src/test/mlscript/staging/Functions.mls | 18 ++-- 4 files changed, 72 insertions(+), 52 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 3d67daed62..c4d8810093 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -137,6 +137,8 @@ class InstrumentationImpl(using State): shapeSetCall("sel", Ls(s1, s2))(s => k(ShapeSet(s))) def fnFilter(s1: ShapeSet, s2: Path)(k: ShapeSet => Block): Block = shapeSetCall("filter", Ls(s1, s2))(s => k(ShapeSet(s))) + def fnRest(s1: ShapeSet, s2: Path)(k: ShapeSet => Block): Block = + shapeSetCall("rest", Ls(s1, s2))(s => k(ShapeSet(s))) def fnUnion(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = shapeSetCall("union", Ls(s1, s2))(s => k(ShapeSet(s))) @@ -231,7 +233,7 @@ class InstrumentationImpl(using State): transformPath(p): x => ruleBranches(x, p, ks, dflt): (stagedMatch, ctx1) => transformBlock(rest)(using ctx1): (z, ctx2) => - fnMrg(stagedMatch.shapes, z.shapes): sp => + fnUnion(stagedMatch.shapes, z.shapes): sp => fnConcat(stagedMatch.code, z.code): cde => StagedPath(sp, cde, symName)(k(_, ctx2)) @@ -290,52 +292,56 @@ class InstrumentationImpl(using State): blockCtor("Define", Ls(cls, p.code))(k) def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block], symName: String = "branches")(using Context)(k: (StagedPath, Context) => Block): Block = - arms.map((cse, block) => (f: StagedPath => Context => Block) => (ruleBranch(x, p, cse, block)(using _)).flip(f(_)(_))) - .collectApply - .pipe(_.flip(summon)): arms => - ctx => - tuple(arms.map(_.p)): tup => - fnPruneBadArms(tup): res => - val result = StagedPath(res) - val sp = result.shapes - val arms = result.code - blockCtor("End", Ls()): e => - // TODO: use transformOption here - def dfltStaged(k: (Path, Context) => Block) = dflt match - case S(dflt) => ruleWildCard(x, p, dflt): (dflt, ctx) => - optionSome(dflt.code)(k(_, ctx)) - case N => optionNone()(k(_, ctx)) - dfltStaged: (dflt, ctx) => - blockCtor("Match", Ls(x.code, arms, dflt, e)): m => - StagedPath(sp, m, symName)(k(_, ctx)) - - def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block, symName: String = "branch")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def applyRuleBranch(cse: Case, block: Block)(f: StagedPath => (Context, StagedPath) => Block)(ctx: Context, x: StagedPath): Block = + ruleBranch(x, p, cse, block)(using ctx)((y, ctx, x) => f(y)(ctx, x)) + + val a = arms.map(applyRuleBranch).collectApply + ((f: (Ls[StagedPath], Context) => Block) => a(ys => (ctx, _) => f(ys, ctx))(summon, x)): (arms, ctx) => + tuple(arms.map(_.p)): tup => + fnPruneBadArms(tup): res => + val result = StagedPath(res) + val sp = result.shapes + val arms = result.code + blockCtor("End", Ls()): e => + // TODO: use transformOption here + def dfltStaged(k: (Path, Context) => Block) = dflt match + case S(dflt) => ruleWildCard(x, p, dflt): (dflt, ctx) => + optionSome(dflt.code)(k(_, ctx)) + case N => optionNone()(k(_, ctx)) + dfltStaged: (dflt, ctx) => + blockCtor("Match", Ls(x.code, arms, dflt, e)): m => + StagedPath(sp, m, symName)(k(_, ctx)) + + def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block, symName: String = "branch")(using Context)(k: (StagedPath, Context, StagedPath) => Block): Block = transformCase(cse): cse => - fnFilter(x.shapes, cse): sp => - call(sp.p.selSN("isEmpty"), Ls()): scrut => - ruleEnd(): (e, ctx) => - val res = new TempSymbol(N, "tmp") - val arm = Case.Lit(Tree.BoolLit(true)) -> Assign(res, e.p, End()) - val dflt = - StagedPath(sp, x.code): x0 => - given Context = ctx.clone() += p -> x0 - transformBlock(b): (y1, ctx) => - // TODO: use Arm type instead of Tup - tuple(Ls(cse, y1.code)): cde => - StagedPath(y1.shapes, cde, symName): ret => - Assign(res, ret.p, End()) - (Match(scrut, Ls(arm), S(dflt), _)): - k(StagedPath(Value.Ref(res)), ctx.clone() -= p) - - // this partially applies rules from filter to account for difference between Block.Case and Match pattern in the formalization - // to avoid defining the `_` pattern in Block.Case, we apply filter(s, _) = s + fnFilter(x.shapes, cse): filtered => + StagedPath(filtered, x.code): x0 => + fnRest(x.shapes, cse): rest => + StagedPath(rest, x.code): x1 => + call(filtered.p.selSN("isEmpty"), Ls()): scrut => + ruleEnd(): (e, ctx) => + val res = new TempSymbol(N, "tmp") + val arm = Case.Lit(Tree.BoolLit(true)) -> Assign(res, e.p, End()) + transformBlock(b)(using ctx.clone() += p -> x0): (y, ctx) => + // TODO: use Arm type instead of Tup + tuple(Ls(cse, y.code)): cde => + StagedPath(y.shapes, cde, symName): ret => + val dflt = Assign(res, ret.p, End()) + (Match(scrut, Ls(arm), S(dflt), _)): + k(StagedPath(Value.Ref(res)), ctx.clone() -= p, x1) + + // this partially applies rules to account for difference between Block.Case and Match pattern in the formalization + // to avoid defining the `_` pattern in Block.Case, we apply filter(s, _) = s and rest(s, _) = bot def ruleWildCard(x: StagedPath, p: Path, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = call(x.shapes.p.selSN("isEmpty"), Ls()): scrut => - val arm = Case.Lit(Tree.BoolLit(true)) -> ruleEnd()((p, _) => Return(p.p, false)) - (Match(scrut, Ls(arm), N, _)): + ruleEnd(): (e, ctx) => + val res = new TempSymbol(N, "tmp") + val arm = Case.Lit(Tree.BoolLit(true)) -> Assign(res, e.p, End()) given Context = ctx.clone() += p -> x - transformBlock(b): (y1, ctx) => - k(y1, ctx.clone() -= p) + transformBlock(b): (y, ctx) => + val dflt = Assign(res, y.p, End()) + (Match(scrut, Ls(arm), S(dflt), _)): + k(StagedPath(Value.Ref(res)), ctx.clone() -= p) // transformations of Block diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index ed1e3483fe..3f3a34aac1 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -96,6 +96,7 @@ fun silh(p: Case): Shape = if p is Class(sym, Array(size).fill(Dyn)) Block.Tup(n, inf) then Arr(Array(n).fill(Dyn), inf) +// TODO: use Option instead, since all of them return at most one shape fun filter(s: Shape, p: Case): Array[Shape] = if [s, p] is [Lit(l1), Block.Lit(l2)] and l1 == l2 then [s] @@ -106,3 +107,14 @@ fun filter(s: Shape, p: Case): Array[Shape] = [Class(c1, _), Block.Cls(c2, _)] and c1.name == c2.name then [s] [Dyn, _] then [silh(p)] else [] + +fun rest(s: Shape, p: Case): Array[Shape] = + if [s, p] is + [Lit(l1), Block.Lit(l2)] and l1 == l2 then [] + [Lit(l), Block.Cls(c, _)] and isPrimitiveTypeOf(c, l) then [] + [Arr(ls, false), Block.Tup(n, false)] and ls.length == n then [] + [Arr(ls, true), _] then [s] // TODO + [_, Block.Tup(ls, true)] then [s] // TODO + [Class(c1, _), Block.Cls(c2, _)] and c1.name == c2.name then [] + [Dyn, _] then [s] + else [s] \ No newline at end of file diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls index f11d334b50..195284ebf4 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -71,6 +71,8 @@ fun mkClass(sym: ClassSymbol, params: Array[ShapeSet]) = fun filter(s: ShapeSet, p: Block.Case) = s.flatMap(Shape.filter(_, p)) +fun rest(s: ShapeSet, p: Block.Case) = s.flatMap(Shape.rest(_, p)) + fun sel(s1: ShapeSet, s2: ShapeSet) = prod([s1.values(), s2.values()]) .flatMap(pair => Shape.sel(pair.0, pair.1)) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 0240b5b0e1..43956160f1 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -16,10 +16,10 @@ staged module Expressions with fun dynsel() = [1].(0) fun match1() = if 9 is - 8 then 1 - 9 then 2 + Bool then 1 + 8 then 2 Int then 3 - Bool then 4 + 9 then 4 else 0 fun match2() = if [...x] is @@ -36,12 +36,12 @@ staged module Expressions with //│ > Arr([Lit(1), Lit(2)], false) //│ > Return(Tuple([Lit(1), Lit(2)]), false) //│ > Arr([Lit(1), Dyn], true) -//│ > Return(Tuple([Lit(1), Ref(Symbol("x"))]), false) +//│ > Return(Tuple([Lit(1), ..Ref(Symbol("x"))]), false) //│ > Lit(1) //│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) -//│ > Dyn -//│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Lit(9) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End)) -//│ > Dyn +//│ > Lit(3) +//│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End)) +//│ > Lit(1), Lit(2) //│ > Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Return(Lit(1), false), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Return(Lit(2), false))))], Return(Lit(0), false), End)) //│ x = [1, 2, 3] @@ -53,8 +53,8 @@ staged module ClassInstrumentation with class NoArg fun inst1() = new Outside(1) fun inst2() = new NoArg -//│ > Define(ClsLikeDefn(ClassSymbol("NoArg"), (), TODO), End) -//│ > Define(ClsLikeDefn(ClassSymbol("Inside":[Symbol("a"), Symbol("b")]), (), TODO), End) +//│ > Define(ClsLikeDefn(ClassSymbol("NoArg"), TODO), End) +//│ > Define(ClsLikeDefn(ClassSymbol("Inside":[Symbol("a"), Symbol("b")]), TODO), End) //│ > Class(ClassSymbol("Outside":[Symbol("a")]), [Lit(1)]) //│ > Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) //│ > Class(ClassSymbol("NoArg"), []) From 408733a318954caa55f9531017a75950461ba60c Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 28 Nov 2025 18:13:58 +0800 Subject: [PATCH 197/268] mark pretty printing equality as fixme --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 2 -- hkmc2/shared/src/test/mlscript-compile/Block.mls | 1 + hkmc2/shared/src/test/mlscript-compile/Shape.mls | 6 ++++-- hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index c4d8810093..a06231fa29 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -131,8 +131,6 @@ class InstrumentationImpl(using State): blockCall("concat", Ls(p1, p2))(k) def fnPruneBadArms(arms: Path)(k: Path => Block): Block = shapeSetCall("pruneBadArms", Ls(arms))(k) - def fnMrg(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = - shapeSetCall("mrg", Ls(s1, s2))(s => k(ShapeSet(s))) def fnSel(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = shapeSetCall("sel", Ls(s1, s2))(s => k(ShapeSet(s))) def fnFilter(s1: ShapeSet, s2: Path)(k: ShapeSet => Block): Block = diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 614936b509..d8ec8b1b3f 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -71,6 +71,7 @@ fun showLiteral(l: Literal) = if l is undefined then "undefined" null then "null" + String then "\"" + l.toString() + "\"" else l.toString() fun showSymbol(s: Symbol) = diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index 3f3a34aac1..c6ef68ad74 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -31,6 +31,9 @@ class Shape with Arr(val shapes: Array[Shape], val inf: Bool) Class(val sym: ClassSymbol, val params: Array[Shape]) +// FIXME: hack to check equality of classes if they have the same paramters +fun equals(a: Shape, b: Shape) = show(a) == show(b) + fun show(s: Shape) = if s is Dyn then "Dyn" @@ -42,8 +45,7 @@ fun zipMrg[A](a: Array[A], b: Array[A]): Array[A] = a.map((a, i, _) => mrg2(a, b.at(i))) fun mrg2(s1: Shape, s2: Shape) = - // we want different objects with same parameters to be equal - if show(s1) == show(s2) then s1 + if equals(s1, s2) then s1 else if [s1, s2] is [Lit(l), Class(sym, params)] and isPrimitiveTypeOf(sym, l) diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls index 195284ebf4..89b0554d89 100644 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls @@ -10,6 +10,7 @@ type ShapeSet = ShapeSet.ShapeSet module ShapeSet with... +// FIXME: hash is based on uniqueness of pretty printing fun hash(s: Shape) = show(s) fun printShapeSet(s: ShapeSet) = console.log([... s.keys()].join(", ")) From 0e2fec8ead49d0acf3d7b201e7e419d9e8170ab2 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 12 Dec 2025 13:03:18 +0800 Subject: [PATCH 198/268] progress: deprecate ShapeSet from StagedPath --- .../scala/hkmc2/codegen/Instrumentation.scala | 60 ++++++++++--------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index a06231fa29..9ef9bab9b8 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -20,6 +20,7 @@ import syntax.{Literal, Tree} // it should be possible to cache some common constructions (End, Option) into the context // this avoids having to rebuild the same shapes everytime they are needed +// transform Block to Block IR so that it can be instrumented in mlscript class InstrumentationImpl(using State): type ArgWrappable = Path | Symbol | ShapeSet type Context = HashMap[Path, StagedPath] @@ -94,17 +95,20 @@ class InstrumentationImpl(using State): call(shapeSetMod(name), args, symName = symName)(k) // helpers to create and access the components of a staged value + @deprecated case class ShapeSet(p: Path) // A StagedPath is a path that points to a (ShapeSet, code) tuple - case class StagedPath(p: Path): - def shapes: ShapeSet = ShapeSet(DynSelect(p, toValue(0), false)) - def code: Path = DynSelect(p, toValue(1), false) - def end: Block = Return(p, false) + case class StagedPath(code: Path): + @deprecated + def shapes: ShapeSet = ??? + @deprecated + def p: Path = ??? + def end: Block = Return(code, false) object StagedPath: - def apply(shapeSet: ShapeSet, code: Path, symName: Str = "tmp")(k: StagedPath => Block): Block = - tuple(Ls(shapeSet.p, code), symName)(p => k(StagedPath(p))) + def apply(code: Path, symName: Str = "tmp")(k: StagedPath => Block): Block = + k(StagedPath(code)) // linking functions defined in MLscipt @@ -159,7 +163,7 @@ class InstrumentationImpl(using State): def ruleLit(l: Value.Lit, symName: String = "lit")(k: StagedPath => Block): Block = shapeLit(l): sp => blockCtor("ValueLit", Ls(l)): cde => - StagedPath(sp, cde, symName)(k) + StagedPath(cde, symName)(k) // not in formalization def ruleVar(r: Value.Ref, symName: String = "var")(k: StagedPath => Block): Block = @@ -168,7 +172,7 @@ class InstrumentationImpl(using State): blockCtor("ValueRef", Ls(sym)): cde => // variable defined outside of scope, may be a reference to a class shapeDyn(): sp => - StagedPath(sp, cde, symName)(k) + StagedPath(cde, symName)(k) def ruleTup(t: Tuple, symName: String = "tup")(using Context)(k: StagedPath => Block): Block = assert(!t.mut, "mutable tuple not supported") @@ -176,7 +180,7 @@ class InstrumentationImpl(using State): shapeArr(xs.map(_._1.shapes), xs.exists(_._2)): sp => tuple(xs.map(_._1.code)): codes => blockCtor("Tuple", Ls(codes)): cde => - StagedPath(sp, cde, symName)(k) + StagedPath(cde, symName)(k) def ruleSel(s: Select, symName: String = "sel")(using Context)(k: StagedPath => Block): Block = val Select(p, i @ Tree.Ident(name)) = s @@ -185,14 +189,14 @@ class InstrumentationImpl(using State): fnSel(x.shapes, n): sp => blockCtor("Symbol", Ls(toValue(name))): name => blockCtor("Select", Ls(x.code, name)): cde => - StagedPath(sp, cde, symName)(k) + StagedPath(cde, symName)(k) def ruleDynSel(d: DynSelect, symName: String = "dynsel")(using Context)(k: StagedPath => Block): Block = transformPath(d.qual): x => transformPath(d.fld): y => fnSel(x.shapes, y.shapes): sp => blockCtor("DynSelect", Ls(x.code, y.code, toValue(d.arrayIdx))): cde => - StagedPath(sp, cde, symName)(k) + StagedPath(cde, symName)(k) // TODO def ruleApp(c: Call, symName: String = "app")(using Context)(k: StagedPath => Block): Block = @@ -201,7 +205,7 @@ class InstrumentationImpl(using State): tuple(args.map(_._1.code)): tup => shapeDyn(): dyn => blockCtor("Call", Ls(fun.code, tup)): res => - StagedPath(dyn, res, symName)(k) + StagedPath(res, symName)(k) def ruleInst(i: Instantiate, symName: String = "inst")(using Context)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i @@ -219,12 +223,12 @@ class InstrumentationImpl(using State): transformPath(cls): cls => tuple(xs.map(_._1.code)): codes => blockCtor("Instantiate", Ls(cls.code, codes)): cde => - StagedPath(sp, cde, symName)(k) + StagedPath(cde, symName)(k) def ruleReturn(r: Return, symName: String = "return")(using Context)(k: (StagedPath, Context) => Block): Block = transformResult(r.res): x => blockCtor("Return", Ls(x.code, toValue(false))): cde => - StagedPath(x.shapes, cde, symName)(k(_, summon)) + StagedPath(cde, symName)(k(_, summon)) def ruleMatch(m: Match, symName: String = "match")(using Context)(k: (StagedPath, Context) => Block): Block = val Match(p, ks, dflt, rest) = m @@ -233,7 +237,7 @@ class InstrumentationImpl(using State): transformBlock(rest)(using ctx1): (z, ctx2) => fnUnion(stagedMatch.shapes, z.shapes): sp => fnConcat(stagedMatch.code, z.code): cde => - StagedPath(sp, cde, symName)(k(_, ctx2)) + StagedPath(cde, symName)(k(_, ctx2)) def ruleAssign(a: Assign, symName: String = "assign")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Assign(x, r, b) = a @@ -245,36 +249,36 @@ class InstrumentationImpl(using State): ctx.get(x.asPath) match case S(x1) => fnUnion(y.shapes, x1.shapes): sp => - StagedPath(sp, xStaged): x2 => + StagedPath(xStaged, "tmp"): x2 => (Assign(x, x2.p, _)): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => - StagedPath(z.shapes, cde, symName)(k(_, ctx)) + StagedPath(cde, symName)(k(_, ctx)) case N => - StagedPath(y.shapes, xStaged): x2 => + StagedPath(xStaged, "tmp"): x2 => // propagate shape information for future references to x (Assign(x, y.p, _)): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => - StagedPath(z.shapes, cde, symName)(k(_, ctx)) + StagedPath(cde, symName)(k(_, ctx)) def ruleLet(x: BlockMemberSymbol, b: Block, symName: String = "_let")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = shapeBot(): bot => transformSymbol(x): xSym => - StagedPath(bot, xSym): y => + StagedPath(xSym, "tmp"): y => (Assign(x, y.p, _)): given Context = ctx.clone() += x.asPath -> y transformBlock(b): (z, ctx) => blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => blockCtor("Assign", Ls(xSym, undefined, z.code)): cde => - StagedPath(z.shapes, cde, symName)(k(_, summon)) + StagedPath(cde, symName)(k(_, summon)) def ruleEnd(symName: String = "end")(using Context)(k: (StagedPath, Context) => Block): Block = shapeBot(): sp => blockCtor("End", Ls()): cde => - StagedPath(sp, cde, symName)(k(_, summon)) + StagedPath(cde, symName)(k(_, summon)) def ruleBlk(b: Block)(using Context)(k: Path => Block): Block = transformBlock(b)(k apply _.code) @@ -308,14 +312,14 @@ class InstrumentationImpl(using State): case N => optionNone()(k(_, ctx)) dfltStaged: (dflt, ctx) => blockCtor("Match", Ls(x.code, arms, dflt, e)): m => - StagedPath(sp, m, symName)(k(_, ctx)) + StagedPath(m, symName)(k(_, ctx)) def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block, symName: String = "branch")(using Context)(k: (StagedPath, Context, StagedPath) => Block): Block = transformCase(cse): cse => fnFilter(x.shapes, cse): filtered => - StagedPath(filtered, x.code): x0 => + StagedPath(x.code, "tmp"): x0 => fnRest(x.shapes, cse): rest => - StagedPath(rest, x.code): x1 => + StagedPath(x.code, "tmp"): x1 => call(filtered.p.selSN("isEmpty"), Ls()): scrut => ruleEnd(): (e, ctx) => val res = new TempSymbol(N, "tmp") @@ -323,7 +327,7 @@ class InstrumentationImpl(using State): transformBlock(b)(using ctx.clone() += p -> x0): (y, ctx) => // TODO: use Arm type instead of Tup tuple(Ls(cse, y.code)): cde => - StagedPath(y.shapes, cde, symName): ret => + StagedPath(cde, symName): ret => val dflt = Assign(res, ret.p, End()) (Match(scrut, Ls(arm), S(dflt), _)): k(StagedPath(Value.Ref(res)), ctx.clone() -= p, x1) @@ -366,7 +370,7 @@ class InstrumentationImpl(using State): transformOption(spread, bool => assign(toValue(bool))): spreadStaged => transformPath(value): value => blockCtor("Arg", Ls(spreadStaged, value.code)): cde => - StagedPath(value.shapes, cde): res => + StagedPath(cde, "tmp"): res => k(res, spread.isDefined) def transformArgs(args: Ls[Arg])(using Context)(k: Ls[(StagedPath, Bool)] => Block): Block = @@ -421,7 +425,7 @@ class InstrumentationImpl(using State): transformBlock(b.sub): (sub, ctx) => transformBlock(b.rest): (rest, ctx) => fnConcat(sub.code, rest.code): block => - StagedPath(rest.shapes, block)(k(_, ctx)) + StagedPath(block, "tmp")(k(_, ctx)) // ruleBlk? def transformBlock(b: Block)(using Context)(k: StagedPath => Block): Block = From 97ede408fdee41c44b01e31412063695be020411 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 12 Dec 2025 13:06:39 +0800 Subject: [PATCH 199/268] progress: strip shape logic from rules --- .../scala/hkmc2/codegen/Instrumentation.scala | 161 +++++++----------- 1 file changed, 60 insertions(+), 101 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 9ef9bab9b8..726ed513e6 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -100,8 +100,6 @@ class InstrumentationImpl(using State): // A StagedPath is a path that points to a (ShapeSet, code) tuple case class StagedPath(code: Path): - @deprecated - def shapes: ShapeSet = ??? @deprecated def p: Path = ??? def end: Block = Return(code, false) @@ -115,34 +113,11 @@ class InstrumentationImpl(using State): def fnPrintCode(p: Path)(k: Block): Block = // discard result, we only care about side effect blockCall("printCode", Ls(p))(_ => k) - def fnPrintShapeSet(p: ShapeSet)(rest: Block): Block = - shapeSetCall("printShapeSet", Ls(p.p))(_ => rest) - - def shapeBot()(k: ShapeSet => Block): Block = - shapeSetCall("mkBot", Ls())(s => k(ShapeSet(s))) - def shapeDyn()(k: ShapeSet => Block): Block = - shapeSetCall("mkDyn", Ls())(s => k(ShapeSet(s))) - def shapeLit(p: Path)(k: ShapeSet => Block): Block = - shapeSetCall("mkLit", Ls(p))(s => k(ShapeSet(s))) - def shapeArr(ps: Ls[ShapeSet], inf: Bool)(k: ShapeSet => Block): Block = - tuple(ps, "test"): tup => - shapeSetCall("mkArr", Ls(tup, toValue(inf)))(s => k(ShapeSet(s))) - def shapeClass(cls: Path, params: Ls[ShapeSet])(k: ShapeSet => Block): Block = - tuple(params): params => - shapeSetCall("mkClass", Ls(cls, params))(s => k(ShapeSet(s))) def fnConcat(p1: Path, p2: Path)(k: Path => Block): Block = blockCall("concat", Ls(p1, p2))(k) def fnPruneBadArms(arms: Path)(k: Path => Block): Block = shapeSetCall("pruneBadArms", Ls(arms))(k) - def fnSel(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = - shapeSetCall("sel", Ls(s1, s2))(s => k(ShapeSet(s))) - def fnFilter(s1: ShapeSet, s2: Path)(k: ShapeSet => Block): Block = - shapeSetCall("filter", Ls(s1, s2))(s => k(ShapeSet(s))) - def fnRest(s1: ShapeSet, s2: Path)(k: ShapeSet => Block): Block = - shapeSetCall("rest", Ls(s1, s2))(s => k(ShapeSet(s))) - def fnUnion(s1: ShapeSet, s2: ShapeSet)(k: ShapeSet => Block): Block = - shapeSetCall("union", Ls(s1, s2))(s => k(ShapeSet(s))) // transformation helpers @@ -161,9 +136,8 @@ class InstrumentationImpl(using State): // instrumentation rules def ruleLit(l: Value.Lit, symName: String = "lit")(k: StagedPath => Block): Block = - shapeLit(l): sp => - blockCtor("ValueLit", Ls(l)): cde => - StagedPath(cde, symName)(k) + blockCtor("ValueLit", Ls(l)): cde => + StagedPath(cde, symName)(k) // not in formalization def ruleVar(r: Value.Ref, symName: String = "var")(k: StagedPath => Block): Block = @@ -171,41 +145,35 @@ class InstrumentationImpl(using State): transformSymbol(disamb.getOrElse(l)): sym => blockCtor("ValueRef", Ls(sym)): cde => // variable defined outside of scope, may be a reference to a class - shapeDyn(): sp => - StagedPath(cde, symName)(k) + StagedPath(cde, symName)(k) def ruleTup(t: Tuple, symName: String = "tup")(using Context)(k: StagedPath => Block): Block = assert(!t.mut, "mutable tuple not supported") transformArgs(t.elems): xs => - shapeArr(xs.map(_._1.shapes), xs.exists(_._2)): sp => - tuple(xs.map(_._1.code)): codes => - blockCtor("Tuple", Ls(codes)): cde => - StagedPath(cde, symName)(k) + tuple(xs.map(_._1.code)): codes => + blockCtor("Tuple", Ls(codes)): cde => + StagedPath(cde, symName)(k) def ruleSel(s: Select, symName: String = "sel")(using Context)(k: StagedPath => Block): Block = val Select(p, i @ Tree.Ident(name)) = s transformPath(p): x => - shapeLit(toValue(name)): n => - fnSel(x.shapes, n): sp => - blockCtor("Symbol", Ls(toValue(name))): name => - blockCtor("Select", Ls(x.code, name)): cde => - StagedPath(cde, symName)(k) + blockCtor("Symbol", Ls(toValue(name))): name => + blockCtor("Select", Ls(x.code, name)): cde => + StagedPath(cde, symName)(k) def ruleDynSel(d: DynSelect, symName: String = "dynsel")(using Context)(k: StagedPath => Block): Block = transformPath(d.qual): x => transformPath(d.fld): y => - fnSel(x.shapes, y.shapes): sp => - blockCtor("DynSelect", Ls(x.code, y.code, toValue(d.arrayIdx))): cde => - StagedPath(cde, symName)(k) + blockCtor("DynSelect", Ls(x.code, y.code, toValue(d.arrayIdx))): cde => + StagedPath(cde, symName)(k) // TODO def ruleApp(c: Call, symName: String = "app")(using Context)(k: StagedPath => Block): Block = transformPath(c.fun): fun => transformArgs(c.args): args => tuple(args.map(_._1.code)): tup => - shapeDyn(): dyn => - blockCtor("Call", Ls(fun.code, tup)): res => - StagedPath(res, symName)(k) + blockCtor("Call", Ls(fun.code, tup)): res => + StagedPath(res, symName)(k) def ruleInst(i: Instantiate, symName: String = "inst")(using Context)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i @@ -217,13 +185,12 @@ class InstrumentationImpl(using State): case s: Select if s.symbol.isDefined => transformSymbol(s.symbol.get) case _ => transformSymbol(TempSymbol(N, "TODO")) sym: sym => - shapeClass(sym, xs.map(_._1.shapes)): sp => - // reuse instrumentation logic, shape of cls is discarded - // possible to skip this? this uses ruleVar, which is not in formalization - transformPath(cls): cls => - tuple(xs.map(_._1.code)): codes => - blockCtor("Instantiate", Ls(cls.code, codes)): cde => - StagedPath(cde, symName)(k) + // reuse instrumentation logic, shape of cls is discarded + // possible to skip this? this uses ruleVar, which is not in formalization + transformPath(cls): cls => + tuple(xs.map(_._1.code)): codes => + blockCtor("Instantiate", Ls(cls.code, codes)): cde => + StagedPath(cde, symName)(k) def ruleReturn(r: Return, symName: String = "return")(using Context)(k: (StagedPath, Context) => Block): Block = transformResult(r.res): x => @@ -235,9 +202,8 @@ class InstrumentationImpl(using State): transformPath(p): x => ruleBranches(x, p, ks, dflt): (stagedMatch, ctx1) => transformBlock(rest)(using ctx1): (z, ctx2) => - fnUnion(stagedMatch.shapes, z.shapes): sp => - fnConcat(stagedMatch.code, z.code): cde => - StagedPath(cde, symName)(k(_, ctx2)) + fnConcat(stagedMatch.code, z.code): cde => + StagedPath(cde, symName)(k(_, ctx2)) def ruleAssign(a: Assign, symName: String = "assign")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Assign(x, r, b) = a @@ -248,13 +214,12 @@ class InstrumentationImpl(using State): // otherwise, x is defined here ctx.get(x.asPath) match case S(x1) => - fnUnion(y.shapes, x1.shapes): sp => - StagedPath(xStaged, "tmp"): x2 => - (Assign(x, x2.p, _)): - given Context = ctx.clone() += x.asPath -> x2 - transformBlock(b): (z, ctx) => - blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => - StagedPath(cde, symName)(k(_, ctx)) + StagedPath(xStaged, "tmp"): x2 => + (Assign(x, x2.p, _)): + given Context = ctx.clone() += x.asPath -> x2 + transformBlock(b): (z, ctx) => + blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => + StagedPath(cde, symName)(k(_, ctx)) case N => StagedPath(xStaged, "tmp"): x2 => // propagate shape information for future references to x @@ -265,20 +230,18 @@ class InstrumentationImpl(using State): StagedPath(cde, symName)(k(_, ctx)) def ruleLet(x: BlockMemberSymbol, b: Block, symName: String = "_let")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = - shapeBot(): bot => - transformSymbol(x): xSym => - StagedPath(xSym, "tmp"): y => - (Assign(x, y.p, _)): - given Context = ctx.clone() += x.asPath -> y - transformBlock(b): (z, ctx) => - blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => - blockCtor("Assign", Ls(xSym, undefined, z.code)): cde => - StagedPath(cde, symName)(k(_, summon)) + transformSymbol(x): xSym => + StagedPath(xSym, "tmp"): y => + (Assign(x, y.p, _)): + given Context = ctx.clone() += x.asPath -> y + transformBlock(b): (z, ctx) => + blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => + blockCtor("Assign", Ls(xSym, undefined, z.code)): cde => + StagedPath(cde, symName)(k(_, summon)) def ruleEnd(symName: String = "end")(using Context)(k: (StagedPath, Context) => Block): Block = - shapeBot(): sp => - blockCtor("End", Ls()): cde => - StagedPath(cde, symName)(k(_, summon)) + blockCtor("End", Ls()): cde => + StagedPath(cde, symName)(k(_, summon)) def ruleBlk(b: Block)(using Context)(k: Path => Block): Block = transformBlock(b)(k apply _.code) @@ -302,7 +265,6 @@ class InstrumentationImpl(using State): tuple(arms.map(_.p)): tup => fnPruneBadArms(tup): res => val result = StagedPath(res) - val sp = result.shapes val arms = result.code blockCtor("End", Ls()): e => // TODO: use transformOption here @@ -316,34 +278,32 @@ class InstrumentationImpl(using State): def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block, symName: String = "branch")(using Context)(k: (StagedPath, Context, StagedPath) => Block): Block = transformCase(cse): cse => - fnFilter(x.shapes, cse): filtered => - StagedPath(x.code, "tmp"): x0 => - fnRest(x.shapes, cse): rest => - StagedPath(x.code, "tmp"): x1 => - call(filtered.p.selSN("isEmpty"), Ls()): scrut => - ruleEnd(): (e, ctx) => - val res = new TempSymbol(N, "tmp") - val arm = Case.Lit(Tree.BoolLit(true)) -> Assign(res, e.p, End()) - transformBlock(b)(using ctx.clone() += p -> x0): (y, ctx) => - // TODO: use Arm type instead of Tup - tuple(Ls(cse, y.code)): cde => - StagedPath(cde, symName): ret => - val dflt = Assign(res, ret.p, End()) - (Match(scrut, Ls(arm), S(dflt), _)): - k(StagedPath(Value.Ref(res)), ctx.clone() -= p, x1) + StagedPath(x.code, "tmp"): x0 => + StagedPath(x.code, "tmp"): x1 => + val scrut = ??? + ruleEnd(): (e, ctx) => + val res = new TempSymbol(N, "tmp") + val arm = Case.Lit(Tree.BoolLit(true)) -> Assign(res, e.p, End()) + transformBlock(b)(using ctx.clone() += p -> x0): (y, ctx) => + // TODO: use Arm type instead of Tup + tuple(Ls(cse, y.code)): cde => + StagedPath(cde, symName): ret => + val dflt = Assign(res, ret.p, End()) + (Match(scrut, Ls(arm), S(dflt), _)): + k(StagedPath(Value.Ref(res)), ctx.clone() -= p, x1) // this partially applies rules to account for difference between Block.Case and Match pattern in the formalization // to avoid defining the `_` pattern in Block.Case, we apply filter(s, _) = s and rest(s, _) = bot def ruleWildCard(x: StagedPath, p: Path, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = - call(x.shapes.p.selSN("isEmpty"), Ls()): scrut => - ruleEnd(): (e, ctx) => - val res = new TempSymbol(N, "tmp") - val arm = Case.Lit(Tree.BoolLit(true)) -> Assign(res, e.p, End()) - given Context = ctx.clone() += p -> x - transformBlock(b): (y, ctx) => - val dflt = Assign(res, y.p, End()) - (Match(scrut, Ls(arm), S(dflt), _)): - k(StagedPath(Value.Ref(res)), ctx.clone() -= p) + val scrut = ??? + ruleEnd(): (e, ctx) => + val res = new TempSymbol(N, "tmp") + val arm = Case.Lit(Tree.BoolLit(true)) -> Assign(res, e.p, End()) + given Context = ctx.clone() += p -> x + transformBlock(b): (y, ctx) => + val dflt = Assign(res, y.p, End()) + (Match(scrut, Ls(arm), S(dflt), _)): + k(StagedPath(Value.Ref(res)), ctx.clone() -= p) // transformations of Block @@ -402,8 +362,7 @@ class InstrumentationImpl(using State): val debug = call(sym, Nil): ret => val p = StagedPath(ret) - (fnPrintShapeSet(p.shapes)(_)): - fnPrintCode(p.code)(End()) + fnPrintCode(p.code)(End()) // NOTE: this debug printing only works for top-level modules, nested modules don't work (f.copy(sym = genSym, body = transformBlock(f.body)(_.end))(false), debug) From d507d3fe3f6655a9c225fd59ede6b2518e8a630f Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 12 Dec 2025 13:21:29 +0800 Subject: [PATCH 200/268] remove inferring shape from Instrumentation as discussed in the meeting, we will perform the within mlscript to reduce complexity --- .../scala/hkmc2/codegen/Instrumentation.scala | 59 ++++++++----------- .../src/test/mlscript/staging/Functions.mls | 16 +---- 2 files changed, 27 insertions(+), 48 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 726ed513e6..a38c0ea861 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -22,14 +22,13 @@ import syntax.{Literal, Tree} // transform Block to Block IR so that it can be instrumented in mlscript class InstrumentationImpl(using State): - type ArgWrappable = Path | Symbol | ShapeSet + type ArgWrappable = Path | Symbol type Context = HashMap[Path, StagedPath] def asArg(x: ArgWrappable): Arg = x match case p: Path => p.asArg case l: Symbol => l.asPath.asArg - case ShapeSet(p) => p.asArg // null and undefined are missing def toValue(lit: Str | Int | BigDecimal | Bool): Value = @@ -100,8 +99,6 @@ class InstrumentationImpl(using State): // A StagedPath is a path that points to a (ShapeSet, code) tuple case class StagedPath(code: Path): - @deprecated - def p: Path = ??? def end: Block = Return(code, false) object StagedPath: @@ -116,8 +113,6 @@ class InstrumentationImpl(using State): def fnConcat(p1: Path, p2: Path)(k: Path => Block): Block = blockCall("concat", Ls(p1, p2))(k) - def fnPruneBadArms(arms: Path)(k: Path => Block): Block = - shapeSetCall("pruneBadArms", Ls(arms))(k) // transformation helpers @@ -215,7 +210,7 @@ class InstrumentationImpl(using State): ctx.get(x.asPath) match case S(x1) => StagedPath(xStaged, "tmp"): x2 => - (Assign(x, x2.p, _)): + (Assign(x, x2.code, _)): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => @@ -223,7 +218,7 @@ class InstrumentationImpl(using State): case N => StagedPath(xStaged, "tmp"): x2 => // propagate shape information for future references to x - (Assign(x, y.p, _)): + (Assign(x, y.code, _)): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => @@ -232,7 +227,7 @@ class InstrumentationImpl(using State): def ruleLet(x: BlockMemberSymbol, b: Block, symName: String = "_let")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = transformSymbol(x): xSym => StagedPath(xSym, "tmp"): y => - (Assign(x, y.p, _)): + (Assign(x, y.code, _)): given Context = ctx.clone() += x.asPath -> y transformBlock(b): (z, ctx) => blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => @@ -262,48 +257,42 @@ class InstrumentationImpl(using State): val a = arms.map(applyRuleBranch).collectApply ((f: (Ls[StagedPath], Context) => Block) => a(ys => (ctx, _) => f(ys, ctx))(summon, x)): (arms, ctx) => - tuple(arms.map(_.p)): tup => - fnPruneBadArms(tup): res => - val result = StagedPath(res) - val arms = result.code - blockCtor("End", Ls()): e => - // TODO: use transformOption here - def dfltStaged(k: (Path, Context) => Block) = dflt match - case S(dflt) => ruleWildCard(x, p, dflt): (dflt, ctx) => - optionSome(dflt.code)(k(_, ctx)) - case N => optionNone()(k(_, ctx)) - dfltStaged: (dflt, ctx) => - blockCtor("Match", Ls(x.code, arms, dflt, e)): m => - StagedPath(m, symName)(k(_, ctx)) + tuple(arms.map(_.code)): tup => + val res = tup + val result = StagedPath(res) + val arms = result.code + blockCtor("End", Ls()): e => + // TODO: use transformOption here + def dfltStaged(k: (Path, Context) => Block) = dflt match + case S(dflt) => ruleWildCard(x, p, dflt): (dflt, ctx) => + optionSome(dflt.code)(k(_, ctx)) + case N => optionNone()(k(_, ctx)) + dfltStaged: (dflt, ctx) => + blockCtor("Match", Ls(x.code, arms, dflt, e)): m => + StagedPath(m, symName)(k(_, ctx)) def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block, symName: String = "branch")(using Context)(k: (StagedPath, Context, StagedPath) => Block): Block = transformCase(cse): cse => StagedPath(x.code, "tmp"): x0 => StagedPath(x.code, "tmp"): x1 => - val scrut = ??? ruleEnd(): (e, ctx) => val res = new TempSymbol(N, "tmp") - val arm = Case.Lit(Tree.BoolLit(true)) -> Assign(res, e.p, End()) transformBlock(b)(using ctx.clone() += p -> x0): (y, ctx) => // TODO: use Arm type instead of Tup tuple(Ls(cse, y.code)): cde => StagedPath(cde, symName): ret => - val dflt = Assign(res, ret.p, End()) - (Match(scrut, Ls(arm), S(dflt), _)): + val dflt = Assign(res, ret.code, _) + dflt: k(StagedPath(Value.Ref(res)), ctx.clone() -= p, x1) // this partially applies rules to account for difference between Block.Case and Match pattern in the formalization // to avoid defining the `_` pattern in Block.Case, we apply filter(s, _) = s and rest(s, _) = bot def ruleWildCard(x: StagedPath, p: Path, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = - val scrut = ??? - ruleEnd(): (e, ctx) => - val res = new TempSymbol(N, "tmp") - val arm = Case.Lit(Tree.BoolLit(true)) -> Assign(res, e.p, End()) - given Context = ctx.clone() += p -> x - transformBlock(b): (y, ctx) => - val dflt = Assign(res, y.p, End()) - (Match(scrut, Ls(arm), S(dflt), _)): - k(StagedPath(Value.Ref(res)), ctx.clone() -= p) + val res = new TempSymbol(N, "tmp") + given Context = ctx.clone() += p -> x + transformBlock(b): (y, ctx) => + val dflt = Assign(res, y.code, _) + dflt(k(StagedPath(Value.Ref(res)), ctx.clone() -= p)) // transformations of Block diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 43956160f1..c3eeb06081 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -27,21 +27,13 @@ staged module Expressions with [a, ...] then 2 // [1, 2] then 5 // TODO: needs handling for Label, Break else 0 -//│ > Lit(1) //│ > Return(Lit(1), false) -//│ > Lit(42) //│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) -//│ > Dyn //│ > Assign(Symbol("x"), Lit(undefined), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false))) -//│ > Arr([Lit(1), Lit(2)], false) //│ > Return(Tuple([Lit(1), Lit(2)]), false) -//│ > Arr([Lit(1), Dyn], true) //│ > Return(Tuple([Lit(1), ..Ref(Symbol("x"))]), false) -//│ > Lit(1) //│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) -//│ > Lit(3) -//│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End)) -//│ > Lit(1), Lit(2) +//│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End)) //│ > Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Return(Lit(1), false), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Return(Lit(2), false))))], Return(Lit(0), false), End)) //│ x = [1, 2, 3] @@ -55,9 +47,7 @@ staged module ClassInstrumentation with fun inst2() = new NoArg //│ > Define(ClsLikeDefn(ClassSymbol("NoArg"), TODO), End) //│ > Define(ClsLikeDefn(ClassSymbol("Inside":[Symbol("a"), Symbol("b")]), TODO), End) -//│ > Class(ClassSymbol("Outside":[Symbol("a")]), [Lit(1)]) //│ > Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) -//│ > Class(ClassSymbol("NoArg"), []) //│ > Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), Symbol("NoArg")), []), false) // debug printing fails, collision with class name? @@ -78,8 +68,8 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.77: staged module B with +//│ ║ l.67: staged module B with //│ ║ ^^^^^^ -//│ ║ l.78: fun f() = 1 +//│ ║ l.68: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From ff7385d4f4b96cac0d3fc599e000a3be3302347d Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 12 Dec 2025 13:30:48 +0800 Subject: [PATCH 201/268] progress: add StagedPath to ArgWrappable --- .../scala/hkmc2/codegen/Instrumentation.scala | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index a38c0ea861..7b44328f91 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -22,12 +22,13 @@ import syntax.{Literal, Tree} // transform Block to Block IR so that it can be instrumented in mlscript class InstrumentationImpl(using State): - type ArgWrappable = Path | Symbol + type ArgWrappable = Path | StagedPath | Symbol type Context = HashMap[Path, StagedPath] def asArg(x: ArgWrappable): Arg = x match case p: Path => p.asArg + case s: StagedPath => s.code.asArg case l: Symbol => l.asPath.asArg // null and undefined are missing @@ -93,10 +94,6 @@ class InstrumentationImpl(using State): def shapeSetCall(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = call(shapeSetMod(name), args, symName = symName)(k) - // helpers to create and access the components of a staged value - @deprecated - case class ShapeSet(p: Path) - // A StagedPath is a path that points to a (ShapeSet, code) tuple case class StagedPath(code: Path): def end: Block = Return(code, false) @@ -145,7 +142,7 @@ class InstrumentationImpl(using State): def ruleTup(t: Tuple, symName: String = "tup")(using Context)(k: StagedPath => Block): Block = assert(!t.mut, "mutable tuple not supported") transformArgs(t.elems): xs => - tuple(xs.map(_._1.code)): codes => + tuple(xs.map(_._1)): codes => blockCtor("Tuple", Ls(codes)): cde => StagedPath(cde, symName)(k) @@ -153,21 +150,21 @@ class InstrumentationImpl(using State): val Select(p, i @ Tree.Ident(name)) = s transformPath(p): x => blockCtor("Symbol", Ls(toValue(name))): name => - blockCtor("Select", Ls(x.code, name)): cde => + blockCtor("Select", Ls(x, name)): cde => StagedPath(cde, symName)(k) def ruleDynSel(d: DynSelect, symName: String = "dynsel")(using Context)(k: StagedPath => Block): Block = transformPath(d.qual): x => transformPath(d.fld): y => - blockCtor("DynSelect", Ls(x.code, y.code, toValue(d.arrayIdx))): cde => + blockCtor("DynSelect", Ls(x, y, toValue(d.arrayIdx))): cde => StagedPath(cde, symName)(k) // TODO def ruleApp(c: Call, symName: String = "app")(using Context)(k: StagedPath => Block): Block = transformPath(c.fun): fun => transformArgs(c.args): args => - tuple(args.map(_._1.code)): tup => - blockCtor("Call", Ls(fun.code, tup)): res => + tuple(args.map(_._1)): tup => + blockCtor("Call", Ls(fun, tup)): res => StagedPath(res, symName)(k) def ruleInst(i: Instantiate, symName: String = "inst")(using Context)(k: StagedPath => Block): Block = @@ -183,8 +180,8 @@ class InstrumentationImpl(using State): // reuse instrumentation logic, shape of cls is discarded // possible to skip this? this uses ruleVar, which is not in formalization transformPath(cls): cls => - tuple(xs.map(_._1.code)): codes => - blockCtor("Instantiate", Ls(cls.code, codes)): cde => + tuple(xs.map(_._1)): codes => + blockCtor("Instantiate", Ls(cls, codes)): cde => StagedPath(cde, symName)(k) def ruleReturn(r: Return, symName: String = "return")(using Context)(k: (StagedPath, Context) => Block): Block = @@ -213,7 +210,7 @@ class InstrumentationImpl(using State): (Assign(x, x2.code, _)): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => - blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => + blockCtor("Assign", Ls(xSym, y, z)): cde => StagedPath(cde, symName)(k(_, ctx)) case N => StagedPath(xStaged, "tmp"): x2 => @@ -221,7 +218,7 @@ class InstrumentationImpl(using State): (Assign(x, y.code, _)): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => - blockCtor("Assign", Ls(xSym, y.code, z.code)): cde => + blockCtor("Assign", Ls(xSym, y, z)): cde => StagedPath(cde, symName)(k(_, ctx)) def ruleLet(x: BlockMemberSymbol, b: Block, symName: String = "_let")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = @@ -231,7 +228,7 @@ class InstrumentationImpl(using State): given Context = ctx.clone() += x.asPath -> y transformBlock(b): (z, ctx) => blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => - blockCtor("Assign", Ls(xSym, undefined, z.code)): cde => + blockCtor("Assign", Ls(xSym, undefined, z)): cde => StagedPath(cde, symName)(k(_, summon)) def ruleEnd(symName: String = "end")(using Context)(k: (StagedPath, Context) => Block): Block = @@ -249,7 +246,7 @@ class InstrumentationImpl(using State): transformSymbol(cls.isym): c => optionNone(): none => // TODO: handle companion object blockCtor("ClsLikeDefn", Ls(c, none)): cls => - blockCtor("Define", Ls(cls, p.code))(k) + blockCtor("Define", Ls(cls, p))(k) def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block], symName: String = "branches")(using Context)(k: (StagedPath, Context) => Block): Block = def applyRuleBranch(cse: Case, block: Block)(f: StagedPath => (Context, StagedPath) => Block)(ctx: Context, x: StagedPath): Block = @@ -257,7 +254,7 @@ class InstrumentationImpl(using State): val a = arms.map(applyRuleBranch).collectApply ((f: (Ls[StagedPath], Context) => Block) => a(ys => (ctx, _) => f(ys, ctx))(summon, x)): (arms, ctx) => - tuple(arms.map(_.code)): tup => + tuple(arms): tup => val res = tup val result = StagedPath(res) val arms = result.code @@ -279,7 +276,7 @@ class InstrumentationImpl(using State): val res = new TempSymbol(N, "tmp") transformBlock(b)(using ctx.clone() += p -> x0): (y, ctx) => // TODO: use Arm type instead of Tup - tuple(Ls(cse, y.code)): cde => + tuple(Ls(cse, y)): cde => StagedPath(cde, symName): ret => val dflt = Assign(res, ret.code, _) dflt: @@ -318,7 +315,7 @@ class InstrumentationImpl(using State): val Arg(spread, value) = a transformOption(spread, bool => assign(toValue(bool))): spreadStaged => transformPath(value): value => - blockCtor("Arg", Ls(spreadStaged, value.code)): cde => + blockCtor("Arg", Ls(spreadStaged, value)): cde => StagedPath(cde, "tmp"): res => k(res, spread.isDefined) @@ -337,7 +334,7 @@ class InstrumentationImpl(using State): case Case.Cls(cls, path) => transformSymbol(cls): cls => transformPath(path): path => - blockCtor("Cls", Ls(cls, path.code))(k) + blockCtor("Cls", Ls(cls, path))(k) case Case.Tup(len, inf) => blockCtor("Tup", Ls(len, inf).map(toValue))(k) case Case.Field(name, safe) => ??? // not supported From 6db1ee796887aba3174d5fbfe5c69579e45b64c2 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 12 Dec 2025 13:50:09 +0800 Subject: [PATCH 202/268] progress: simplify impl --- .../scala/hkmc2/codegen/Instrumentation.scala | 34 +++++++------------ 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 7b44328f91..81527d0032 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -94,9 +94,7 @@ class InstrumentationImpl(using State): def shapeSetCall(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = call(shapeSetMod(name), args, symName = symName)(k) - // A StagedPath is a path that points to a (ShapeSet, code) tuple - case class StagedPath(code: Path): - def end: Block = Return(code, false) + case class StagedPath(code: Path) object StagedPath: def apply(code: Path, symName: Str = "tmp")(k: StagedPath => Block): Block = @@ -223,13 +221,13 @@ class InstrumentationImpl(using State): def ruleLet(x: BlockMemberSymbol, b: Block, symName: String = "_let")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = transformSymbol(x): xSym => - StagedPath(xSym, "tmp"): y => - (Assign(x, y.code, _)): - given Context = ctx.clone() += x.asPath -> y - transformBlock(b): (z, ctx) => - blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => - blockCtor("Assign", Ls(xSym, undefined, z)): cde => - StagedPath(cde, symName)(k(_, summon)) + val y = StagedPath(xSym) + (Assign(x, y.code, _)): + given Context = ctx.clone() += x.asPath -> y + transformBlock(b): (z, ctx) => + blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => + blockCtor("Assign", Ls(xSym, undefined, z)): cde => + StagedPath(cde, symName)(k(_, summon)) def ruleEnd(symName: String = "end")(using Context)(k: (StagedPath, Context) => Block): Block = blockCtor("End", Ls()): cde => @@ -254,10 +252,7 @@ class InstrumentationImpl(using State): val a = arms.map(applyRuleBranch).collectApply ((f: (Ls[StagedPath], Context) => Block) => a(ys => (ctx, _) => f(ys, ctx))(summon, x)): (arms, ctx) => - tuple(arms): tup => - val res = tup - val result = StagedPath(res) - val arms = result.code + tuple(arms): arms => blockCtor("End", Ls()): e => // TODO: use transformOption here def dfltStaged(k: (Path, Context) => Block) = dflt match @@ -273,23 +268,18 @@ class InstrumentationImpl(using State): StagedPath(x.code, "tmp"): x0 => StagedPath(x.code, "tmp"): x1 => ruleEnd(): (e, ctx) => - val res = new TempSymbol(N, "tmp") transformBlock(b)(using ctx.clone() += p -> x0): (y, ctx) => // TODO: use Arm type instead of Tup tuple(Ls(cse, y)): cde => StagedPath(cde, symName): ret => - val dflt = Assign(res, ret.code, _) - dflt: - k(StagedPath(Value.Ref(res)), ctx.clone() -= p, x1) + k(ret, ctx.clone() -= p, x1) // this partially applies rules to account for difference between Block.Case and Match pattern in the formalization // to avoid defining the `_` pattern in Block.Case, we apply filter(s, _) = s and rest(s, _) = bot def ruleWildCard(x: StagedPath, p: Path, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = - val res = new TempSymbol(N, "tmp") given Context = ctx.clone() += p -> x transformBlock(b): (y, ctx) => - val dflt = Assign(res, y.code, _) - dflt(k(StagedPath(Value.Ref(res)), ctx.clone() -= p)) + k(y, ctx.clone() -= p) // transformations of Block @@ -351,7 +341,7 @@ class InstrumentationImpl(using State): fnPrintCode(p.code)(End()) // NOTE: this debug printing only works for top-level modules, nested modules don't work - (f.copy(sym = genSym, body = transformBlock(f.body)(_.end))(false), debug) + (f.copy(sym = genSym, body = transformBlock(f.body)(p => Return(p.code, false)))(false), debug) def transformDefine(d: Define)(using Context)(k: (StagedPath, Context) => Block): Block = d.defn match From 977433a7567b28be9b2e236ab683832ba4202b8e Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 13 Dec 2025 01:01:31 +0800 Subject: [PATCH 203/268] progress: formatting --- .../scala/hkmc2/codegen/Instrumentation.scala | 56 ++++++++----------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 81527d0032..8b9d5af367 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -56,9 +56,6 @@ class InstrumentationImpl(using State): k(head :: tail) )(f) - extension [A, B, C](f: A => B => C) - def flip: B => A => C = b => f(_)(b) - // helpers for constructing Block def assign(res: Result, symName: Str = "tmp")(k: Path => Block): Assign = @@ -80,7 +77,6 @@ class InstrumentationImpl(using State): def blockMod(name: Str) = summon[State].blockSymbol.asPath.selSN(name) def optionMod(name: Str) = summon[State].optionSymbol.asPath.selSN(name) - def shapeSetMod(name: Str) = summon[State].shapeSetSymbol.asPath.selSN(name) def blockCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = ctor(blockMod(name), args, symName)(k) @@ -91,8 +87,6 @@ class InstrumentationImpl(using State): def blockCall(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = call(blockMod(name), args, symName = symName)(k) - def shapeSetCall(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = - call(shapeSetMod(name), args, symName = symName)(k) case class StagedPath(code: Path) @@ -134,7 +128,6 @@ class InstrumentationImpl(using State): val Value.Ref(l, disamb) = r transformSymbol(disamb.getOrElse(l)): sym => blockCtor("ValueRef", Ls(sym)): cde => - // variable defined outside of scope, may be a reference to a class StagedPath(cde, symName)(k) def ruleTup(t: Tuple, symName: String = "tup")(using Context)(k: StagedPath => Block): Block = @@ -204,20 +197,20 @@ class InstrumentationImpl(using State): // otherwise, x is defined here ctx.get(x.asPath) match case S(x1) => - StagedPath(xStaged, "tmp"): x2 => - (Assign(x, x2.code, _)): - given Context = ctx.clone() += x.asPath -> x2 - transformBlock(b): (z, ctx) => - blockCtor("Assign", Ls(xSym, y, z)): cde => - StagedPath(cde, symName)(k(_, ctx)) + val x2 = StagedPath(xStaged) + (Assign(x, x2.code, _)): + given Context = ctx.clone() += x.asPath -> x2 + transformBlock(b): (z, ctx) => + blockCtor("Assign", Ls(xSym, y, z)): cde => + StagedPath(cde, symName)(k(_, ctx)) case N => - StagedPath(xStaged, "tmp"): x2 => - // propagate shape information for future references to x - (Assign(x, y.code, _)): - given Context = ctx.clone() += x.asPath -> x2 - transformBlock(b): (z, ctx) => - blockCtor("Assign", Ls(xSym, y, z)): cde => - StagedPath(cde, symName)(k(_, ctx)) + val x2 = StagedPath(xStaged) + // propagate shape information for future references to x + (Assign(x, y.code, _)): + given Context = ctx.clone() += x.asPath -> x2 + transformBlock(b): (z, ctx) => + blockCtor("Assign", Ls(xSym, y, z)): cde => + StagedPath(cde, symName)(k(_, ctx)) def ruleLet(x: BlockMemberSymbol, b: Block, symName: String = "_let")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = transformSymbol(x): xSym => @@ -263,19 +256,14 @@ class InstrumentationImpl(using State): blockCtor("Match", Ls(x.code, arms, dflt, e)): m => StagedPath(m, symName)(k(_, ctx)) - def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block, symName: String = "branch")(using Context)(k: (StagedPath, Context, StagedPath) => Block): Block = + def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block, symName: String = "branch")(using ctx: Context)(k: (StagedPath, Context, StagedPath) => Block): Block = transformCase(cse): cse => - StagedPath(x.code, "tmp"): x0 => - StagedPath(x.code, "tmp"): x1 => - ruleEnd(): (e, ctx) => - transformBlock(b)(using ctx.clone() += p -> x0): (y, ctx) => - // TODO: use Arm type instead of Tup - tuple(Ls(cse, y)): cde => - StagedPath(cde, symName): ret => - k(ret, ctx.clone() -= p, x1) - - // this partially applies rules to account for difference between Block.Case and Match pattern in the formalization - // to avoid defining the `_` pattern in Block.Case, we apply filter(s, _) = s and rest(s, _) = bot + transformBlock(b)(using ctx.clone() += p -> x): (y, ctx) => + // TODO: use Arm type instead of Tup + tuple(Ls(cse, y)): cde => + StagedPath(cde, symName): ret => + k(ret, ctx.clone() -= p, x) + def ruleWildCard(x: StagedPath, p: Path, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = given Context = ctx.clone() += p -> x transformBlock(b): (y, ctx) => @@ -306,8 +294,8 @@ class InstrumentationImpl(using State): transformOption(spread, bool => assign(toValue(bool))): spreadStaged => transformPath(value): value => blockCtor("Arg", Ls(spreadStaged, value)): cde => - StagedPath(cde, "tmp"): res => - k(res, spread.isDefined) + val res = StagedPath(cde) + k(res, spread.isDefined) def transformArgs(args: Ls[Arg])(using Context)(k: Ls[(StagedPath, Bool)] => Block): Block = args.map(transformArg).collectApply(k) From e21bff2ac304e7b1a1dd97a3abbcd58f22943ddf Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 18 Dec 2025 12:57:23 +0800 Subject: [PATCH 204/268] fix printCode syntax --- hkmc2/shared/src/test/mlscript/staging/PrintCode.mls | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls index 21e4d1e5aa..aac4722e59 100644 --- a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls +++ b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls @@ -3,6 +3,7 @@ //│ Block = class Block { //│ Symbol: fun Symbol { class: class Symbol }, +//│ ClassSymbol: fun ClassSymbol { class: class ClassSymbol }, //│ Arg: fun Arg { class: class Arg }, //│ Case: class Case, //│ Lit: fun Lit { class: class Lit }, @@ -31,6 +32,7 @@ //│ } //│ ShapeSet = class ShapeSet { ShapeSet: fun ShapeSet { class: class ShapeSet } } -Block.printCode(Block.FunDefn(Block.Symbol("f"), [Block.Symbol("x")], Block.Return(Block.ValueLit(1), false))) -//│ > FunDefn(Symbol("f"), [Symbol("x")], Return(Lit(1), false)) +Block.printCode(Block.FunDefn(Block.Symbol("f"), [[Block.Symbol("x")]], Block.Return(Block.ValueLit(1), false))) +//│ > [ Symbol { name: 'x' } ] +//│ > FunDefn(Symbol("f"), ([Symbol("x")]), Return(Lit(1), false), undefined) From 55e10756a23b28e68b971893ac251dc54f3dac23 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 18 Dec 2025 13:10:56 +0800 Subject: [PATCH 205/268] remove equality hack in Shape.mls --- hkmc2/shared/src/test/mlscript-compile/Shape.mls | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index c6ef68ad74..0b724cfcd7 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -31,9 +31,6 @@ class Shape with Arr(val shapes: Array[Shape], val inf: Bool) Class(val sym: ClassSymbol, val params: Array[Shape]) -// FIXME: hack to check equality of classes if they have the same paramters -fun equals(a: Shape, b: Shape) = show(a) == show(b) - fun show(s: Shape) = if s is Dyn then "Dyn" @@ -44,8 +41,9 @@ fun show(s: Shape) = fun zipMrg[A](a: Array[A], b: Array[A]): Array[A] = a.map((a, i, _) => mrg2(a, b.at(i))) +// TODO: remove, this is no longer in use fun mrg2(s1: Shape, s2: Shape) = - if equals(s1, s2) then s1 + if s1 == s2 then s1 else if [s1, s2] is [Lit(l), Class(sym, params)] and isPrimitiveTypeOf(sym, l) From aa72ded2aaee6bfb8d0fe30f0914605ec8b8db81 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 18 Dec 2025 14:39:20 +0800 Subject: [PATCH 206/268] switch from ValDefn to Scoped --- .../scala/hkmc2/codegen/Instrumentation.scala | 26 +++++++------------ .../src/test/mlscript/staging/Functions.mls | 4 --- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 8b9d5af367..b036dc411e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -58,7 +58,7 @@ class InstrumentationImpl(using State): // helpers for constructing Block - def assign(res: Result, symName: Str = "tmp")(k: Path => Block): Assign = + def assign(res: Result, symName: Str = "tmp")(k: Path => Block): Block = // TODO: skip assignment if res: Path? val sym = new TempSymbol(N, symName) Assign(sym, res, k(sym.asPath)) @@ -212,16 +212,6 @@ class InstrumentationImpl(using State): blockCtor("Assign", Ls(xSym, y, z)): cde => StagedPath(cde, symName)(k(_, ctx)) - def ruleLet(x: BlockMemberSymbol, b: Block, symName: String = "_let")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = - transformSymbol(x): xSym => - val y = StagedPath(xSym) - (Assign(x, y.code, _)): - given Context = ctx.clone() += x.asPath -> y - transformBlock(b): (z, ctx) => - blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undefined => - blockCtor("Assign", Ls(xSym, undefined, z)): cde => - StagedPath(cde, symName)(k(_, summon)) - def ruleEnd(symName: String = "end")(using Context)(k: (StagedPath, Context) => Block): Block = blockCtor("End", Ls()): cde => StagedPath(cde, symName)(k(_, summon)) @@ -333,14 +323,11 @@ class InstrumentationImpl(using State): def transformDefine(d: Define)(using Context)(k: (StagedPath, Context) => Block): Block = d.defn match - case f: FunDefn => ??? - case v: ValDefn => - val ValDefn(_, x, r) = v - ruleLet(x, Assign(x, r, d.rest))(k) case c: ClsLikeDefn => ruleCls(c, d.rest): p => ruleEnd(): (b, ctx) => fnPrintCode(p)(k(b, ctx)) + case _: FunDefn | _: ValDefn => ??? // TODO // discards result of sub @@ -350,12 +337,18 @@ class InstrumentationImpl(using State): fnConcat(sub.code, rest.code): block => StagedPath(block, "tmp")(k(_, ctx)) + def transformScoped(s: Scoped)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + val Scoped(syms, body) = s + blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undef => + val newCtx = ctx.clone() ++ syms.map(Value.Ref(_, N) -> StagedPath(undef)) + transformBlock(body)(using newCtx): (p, ctx) => + k(p, ctx) + // ruleBlk? def transformBlock(b: Block)(using Context)(k: StagedPath => Block): Block = transformBlock(b)((p, _) => k(p)) def transformBlock(b: Block)(using Context)(k: (StagedPath, Context) => Block): Block = - val k2 = k(_, summon) b match case r: Return => ruleReturn(r)(k) case a: Assign => ruleAssign(a)(k) @@ -366,6 +359,7 @@ class InstrumentationImpl(using State): // use BlockTransformer here? case b: Begin => transformBegin(b)(k) // case Begin(b1, b2) => transformBlock(concat(b1, b2))(k) + case s: Scoped => transformScoped(s)(k) case _ => ??? // not supported // TODO: rename as InstrumentationTransformer? diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index c3eeb06081..5b92dacfa5 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -8,9 +8,6 @@ staged module Expressions with let x = 42 let y = x y - fun _var() = - val x = 1 - x fun tup1() = [1, 2] fun tup2() = [1, ..x] fun dynsel() = [1].(0) @@ -29,7 +26,6 @@ staged module Expressions with else 0 //│ > Return(Lit(1), false) //│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) -//│ > Assign(Symbol("x"), Lit(undefined), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false))) //│ > Return(Tuple([Lit(1), Lit(2)]), false) //│ > Return(Tuple([Lit(1), ..Ref(Symbol("x"))]), false) //│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) From 326ac69100e29141e0d296c0985fbda8d8be922f Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 18 Dec 2025 15:07:21 +0800 Subject: [PATCH 207/268] fix: make new dSym when cloning FunDefn --- .../shared/src/main/scala/hkmc2/codegen/Instrumentation.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index b036dc411e..dbb2f0265e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -319,7 +319,9 @@ class InstrumentationImpl(using State): fnPrintCode(p.code)(End()) // NOTE: this debug printing only works for top-level modules, nested modules don't work - (f.copy(sym = genSym, body = transformBlock(f.body)(p => Return(p.code, false)))(false), debug) + val dSym = TermSymbol(f.dSym.k, f.dSym.owner, Tree.Ident(f.sym.nme + "_gen")) + val newFun = f.copy(sym = genSym, dSym = dSym, body = transformBlock(f.body)(p => Return(p.code, false)))(false) + (newFun, debug) def transformDefine(d: Define)(using Context)(k: (StagedPath, Context) => Block): Block = d.defn match From 77acb045d5ec78df5829360a099114a6f13f474d Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 18 Dec 2025 15:20:44 +0800 Subject: [PATCH 208/268] remove context from ruleEnd --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index dbb2f0265e..05b83f9a08 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -212,9 +212,9 @@ class InstrumentationImpl(using State): blockCtor("Assign", Ls(xSym, y, z)): cde => StagedPath(cde, symName)(k(_, ctx)) - def ruleEnd(symName: String = "end")(using Context)(k: (StagedPath, Context) => Block): Block = + def ruleEnd(symName: String = "end")(k: StagedPath => Block): Block = blockCtor("End", Ls()): cde => - StagedPath(cde, symName)(k(_, summon)) + StagedPath(cde, symName)(k) def ruleBlk(b: Block)(using Context)(k: Path => Block): Block = transformBlock(b)(k apply _.code) @@ -327,8 +327,8 @@ class InstrumentationImpl(using State): d.defn match case c: ClsLikeDefn => ruleCls(c, d.rest): p => - ruleEnd(): (b, ctx) => - fnPrintCode(p)(k(b, ctx)) + ruleEnd(): b => + fnPrintCode(p)(k(b, summon)) case _: FunDefn | _: ValDefn => ??? // TODO @@ -355,7 +355,7 @@ class InstrumentationImpl(using State): case r: Return => ruleReturn(r)(k) case a: Assign => ruleAssign(a)(k) case d: Define => transformDefine(d)(k) - case End(_) => ruleEnd()(k) + case End(_) => ruleEnd()(k(_, summon)) case m: Match => ruleMatch(m)(k) // temporary measure to accept returning an array // use BlockTransformer here? From ccc950d165ba3be5f9ec23a2178c7ce741c6a9b2 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 18 Dec 2025 16:44:01 +0800 Subject: [PATCH 209/268] add staging for functions with arguments --- .../scala/hkmc2/codegen/Instrumentation.scala | 60 +++++++++---------- .../src/test/mlscript/staging/Functions.mls | 10 ++++ 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 05b83f9a08..68a068cea5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -193,24 +193,14 @@ class InstrumentationImpl(using State): transformResult(r): y => transformSymbol(x): xSym => blockCtor("ValueRef", Ls(xSym)): xStaged => - // if ctx contains x, x was defined earlier - // otherwise, x is defined here - ctx.get(x.asPath) match - case S(x1) => - val x2 = StagedPath(xStaged) - (Assign(x, x2.code, _)): - given Context = ctx.clone() += x.asPath -> x2 - transformBlock(b): (z, ctx) => - blockCtor("Assign", Ls(xSym, y, z)): cde => - StagedPath(cde, symName)(k(_, ctx)) - case N => - val x2 = StagedPath(xStaged) - // propagate shape information for future references to x - (Assign(x, y.code, _)): - given Context = ctx.clone() += x.asPath -> x2 - transformBlock(b): (z, ctx) => - blockCtor("Assign", Ls(xSym, y, z)): cde => - StagedPath(cde, symName)(k(_, ctx)) + // x should always be defined, either as an argument to the function or in a Scope Block + assert(ctx.get(x.asPath).isDefined) + val x2 = StagedPath(xStaged) + (Assign(x, x2.code, _)): + given Context = ctx.clone() += x.asPath -> x2 + transformBlock(b): (z, ctx) => + blockCtor("Assign", Ls(xSym, y, z)): cde => + StagedPath(cde, symName)(k(_, ctx)) def ruleEnd(symName: String = "end")(k: StagedPath => Block): Block = blockCtor("End", Ls()): cde => @@ -236,7 +226,7 @@ class InstrumentationImpl(using State): val a = arms.map(applyRuleBranch).collectApply ((f: (Ls[StagedPath], Context) => Block) => a(ys => (ctx, _) => f(ys, ctx))(summon, x)): (arms, ctx) => tuple(arms): arms => - blockCtor("End", Ls()): e => + ruleEnd(): e => // TODO: use transformOption here def dfltStaged(k: (Path, Context) => Block) = dflt match case S(dflt) => ruleWildCard(x, p, dflt): (dflt, ctx) => @@ -308,19 +298,29 @@ class InstrumentationImpl(using State): // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function // so we pass modSym instead - def transformFunDefn(modSym: BlockMemberSymbol, f: FunDefn)(using Context): (FunDefn, Block) = + def transformFunDefn(modSym: BlockMemberSymbol, f: FunDefn): (FunDefn, Block) = val genSym = BlockMemberSymbol(f.sym.nme + "_gen", Nil, true) - // TODO: remove it. only for test - // TODO: put correct parameters instead of Nil val sym = modSym.asPath.selSN(genSym.nme) + // NOTE: this debug printing only works for top-level modules, nested modules don't work + // TODO: remove it. only for test val debug = - call(sym, Nil): ret => - val p = StagedPath(ret) - fnPrintCode(p.code)(End()) + blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undef => + // TODO: put correct parameters instead of End + // TODO: handle curried arguments + val argsList = f.params.map(ps => List.fill(ps.params.length)(undef)) + def makeCalls(k: Path => Block) = + argsList.foldRight(k)((args, cont) => res => call(res, args)(cont))(sym) + makeCalls: ret => + val p = StagedPath(ret) + fnPrintCode(p.code)(End()) - // NOTE: this debug printing only works for top-level modules, nested modules don't work val dSym = TermSymbol(f.dSym.k, f.dSym.owner, Tree.Ident(f.sym.nme + "_gen")) - val newFun = f.copy(sym = genSym, dSym = dSym, body = transformBlock(f.body)(p => Return(p.code, false)))(false) + val args = f.params.flatMap(_.params).map(_.sym) + val newBody = + ruleEnd(): end => + given Context = HashMap(args.map(s => Value.Ref(s, N) -> StagedPath(Value.Ref(s, N)))*) + transformBlock(f.body)(p => Return(p.code, false)) + val newFun = f.copy(sym = genSym, dSym = dSym, body = newBody)(false) (newFun, debug) def transformDefine(d: Define)(using Context)(k: (StagedPath, Context) => Block): Block = @@ -335,14 +335,14 @@ class InstrumentationImpl(using State): // discards result of sub def transformBegin(b: Begin)(using Context)(k: (StagedPath, Context) => Block): Block = transformBlock(b.sub): (sub, ctx) => - transformBlock(b.rest): (rest, ctx) => + transformBlock(b.rest)(using ctx): (rest, ctx) => fnConcat(sub.code, rest.code): block => StagedPath(block, "tmp")(k(_, ctx)) def transformScoped(s: Scoped)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Scoped(syms, body) = s blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undef => - val newCtx = ctx.clone() ++ syms.map(Value.Ref(_, N) -> StagedPath(undef)) + val newCtx = ctx.clone() ++ syms.map(_.asPath -> StagedPath(undef)) transformBlock(body)(using newCtx): (p, ctx) => k(p, ctx) @@ -376,7 +376,7 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): val sym = c.sym.subst val companion = c.companion.get val (stagedMethods, debugPrintCode) = companion.methods - .map(impl.transformFunDefn(sym, _)(using new HashMap())) // fold instead to retain env? + .map(impl.transformFunDefn(sym, _)) .unzip val newCtor = impl.transformBlock(companion.ctor)(using new HashMap())(_ => End()) val newCompanion = companion.copy(methods = companion.methods ++ stagedMethods, ctor = newCtor) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 5b92dacfa5..4955cb1749 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -46,6 +46,16 @@ staged module ClassInstrumentation with //│ > Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) //│ > Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), Symbol("NoArg")), []), false) +:js +:staging +staged module Arguments with + fun f(x) = + x = 1 + x + fun g(x)(y, z)() = z +//│ > Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)) +//│ > Return(Lit(undefined), false) + // debug printing fails, collision with class name? :js :staging From dee92b143c1727d5cf7a069c6bce4967e622ddb6 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 18 Dec 2025 16:53:30 +0800 Subject: [PATCH 210/268] progress: simplify StagedPath --- .../scala/hkmc2/codegen/Instrumentation.scala | 64 +++++++++---------- .../src/test/mlscript/staging/Functions.mls | 4 +- 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 68a068cea5..df0c15aeb2 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -90,18 +90,14 @@ class InstrumentationImpl(using State): case class StagedPath(code: Path) - object StagedPath: - def apply(code: Path, symName: Str = "tmp")(k: StagedPath => Block): Block = - k(StagedPath(code)) - // linking functions defined in MLscipt def fnPrintCode(p: Path)(k: Block): Block = // discard result, we only care about side effect blockCall("printCode", Ls(p))(_ => k) - def fnConcat(p1: Path, p2: Path)(k: Path => Block): Block = - blockCall("concat", Ls(p1, p2))(k) + def fnConcat(p1: Path, p2: Path, symName: String = "concat")(k: Path => Block): Block = + blockCall("concat", Ls(p1, p2), symName)(k) // transformation helpers @@ -120,43 +116,43 @@ class InstrumentationImpl(using State): // instrumentation rules def ruleLit(l: Value.Lit, symName: String = "lit")(k: StagedPath => Block): Block = - blockCtor("ValueLit", Ls(l)): cde => - StagedPath(cde, symName)(k) + blockCtor("ValueLit", Ls(l), symName): cde => + k(StagedPath(cde)) // not in formalization def ruleVar(r: Value.Ref, symName: String = "var")(k: StagedPath => Block): Block = val Value.Ref(l, disamb) = r transformSymbol(disamb.getOrElse(l)): sym => - blockCtor("ValueRef", Ls(sym)): cde => - StagedPath(cde, symName)(k) + blockCtor("ValueRef", Ls(sym), symName): cde => + k(StagedPath(cde)) def ruleTup(t: Tuple, symName: String = "tup")(using Context)(k: StagedPath => Block): Block = assert(!t.mut, "mutable tuple not supported") transformArgs(t.elems): xs => tuple(xs.map(_._1)): codes => - blockCtor("Tuple", Ls(codes)): cde => - StagedPath(cde, symName)(k) + blockCtor("Tuple", Ls(codes), symName): cde => + k(StagedPath(cde)) def ruleSel(s: Select, symName: String = "sel")(using Context)(k: StagedPath => Block): Block = val Select(p, i @ Tree.Ident(name)) = s transformPath(p): x => blockCtor("Symbol", Ls(toValue(name))): name => - blockCtor("Select", Ls(x, name)): cde => - StagedPath(cde, symName)(k) + blockCtor("Select", Ls(x, name), symName): cde => + k(StagedPath(cde)) def ruleDynSel(d: DynSelect, symName: String = "dynsel")(using Context)(k: StagedPath => Block): Block = transformPath(d.qual): x => transformPath(d.fld): y => - blockCtor("DynSelect", Ls(x, y, toValue(d.arrayIdx))): cde => - StagedPath(cde, symName)(k) + blockCtor("DynSelect", Ls(x, y, toValue(d.arrayIdx)), symName): cde => + k(StagedPath(cde)) // TODO def ruleApp(c: Call, symName: String = "app")(using Context)(k: StagedPath => Block): Block = transformPath(c.fun): fun => transformArgs(c.args): args => tuple(args.map(_._1)): tup => - blockCtor("Call", Ls(fun, tup)): res => - StagedPath(res, symName)(k) + blockCtor("Call", Ls(fun, tup), symName): res => + k(StagedPath(res)) def ruleInst(i: Instantiate, symName: String = "inst")(using Context)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i @@ -172,21 +168,21 @@ class InstrumentationImpl(using State): // possible to skip this? this uses ruleVar, which is not in formalization transformPath(cls): cls => tuple(xs.map(_._1)): codes => - blockCtor("Instantiate", Ls(cls, codes)): cde => - StagedPath(cde, symName)(k) + blockCtor("Instantiate", Ls(cls, codes), symName): cde => + k(StagedPath(cde)) def ruleReturn(r: Return, symName: String = "return")(using Context)(k: (StagedPath, Context) => Block): Block = transformResult(r.res): x => - blockCtor("Return", Ls(x.code, toValue(false))): cde => - StagedPath(cde, symName)(k(_, summon)) + blockCtor("Return", Ls(x.code, toValue(false)), symName): cde => + k(StagedPath(cde), summon) def ruleMatch(m: Match, symName: String = "match")(using Context)(k: (StagedPath, Context) => Block): Block = val Match(p, ks, dflt, rest) = m transformPath(p): x => ruleBranches(x, p, ks, dflt): (stagedMatch, ctx1) => transformBlock(rest)(using ctx1): (z, ctx2) => - fnConcat(stagedMatch.code, z.code): cde => - StagedPath(cde, symName)(k(_, ctx2)) + fnConcat(stagedMatch.code, z.code, symName): cde => + k(StagedPath(cde), ctx2) def ruleAssign(a: Assign, symName: String = "assign")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Assign(x, r, b) = a @@ -199,12 +195,12 @@ class InstrumentationImpl(using State): (Assign(x, x2.code, _)): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => - blockCtor("Assign", Ls(xSym, y, z)): cde => - StagedPath(cde, symName)(k(_, ctx)) + blockCtor("Assign", Ls(xSym, y, z), symName): cde => + k(StagedPath(cde), ctx) def ruleEnd(symName: String = "end")(k: StagedPath => Block): Block = - blockCtor("End", Ls()): cde => - StagedPath(cde, symName)(k) + blockCtor("End", Ls(), symName): cde => + k(StagedPath(cde)) def ruleBlk(b: Block)(using Context)(k: Path => Block): Block = transformBlock(b)(k apply _.code) @@ -233,16 +229,16 @@ class InstrumentationImpl(using State): optionSome(dflt.code)(k(_, ctx)) case N => optionNone()(k(_, ctx)) dfltStaged: (dflt, ctx) => - blockCtor("Match", Ls(x.code, arms, dflt, e)): m => - StagedPath(m, symName)(k(_, ctx)) + blockCtor("Match", Ls(x.code, arms, dflt, e), symName): m => + k(StagedPath(m), ctx) def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block, symName: String = "branch")(using ctx: Context)(k: (StagedPath, Context, StagedPath) => Block): Block = transformCase(cse): cse => transformBlock(b)(using ctx.clone() += p -> x): (y, ctx) => // TODO: use Arm type instead of Tup - tuple(Ls(cse, y)): cde => - StagedPath(cde, symName): ret => - k(ret, ctx.clone() -= p, x) + tuple(Ls(cse, y), symName): cde => + val ret = StagedPath(cde) + k(ret, ctx.clone() -= p, x) def ruleWildCard(x: StagedPath, p: Path, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = given Context = ctx.clone() += p -> x @@ -337,7 +333,7 @@ class InstrumentationImpl(using State): transformBlock(b.sub): (sub, ctx) => transformBlock(b.rest)(using ctx): (rest, ctx) => fnConcat(sub.code, rest.code): block => - StagedPath(block, "tmp")(k(_, ctx)) + k(StagedPath(block), ctx) def transformScoped(s: Scoped)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Scoped(syms, body) = s diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 4955cb1749..c33981860c 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -74,8 +74,8 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.67: staged module B with +//│ ║ l.73: staged module B with //│ ║ ^^^^^^ -//│ ║ l.68: fun f() = 1 +//│ ║ l.74: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From e6fd90ab13bb0e55dd63b0fc0a585528c5e6d905 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 18 Dec 2025 17:02:09 +0800 Subject: [PATCH 211/268] progress: Make blockCtor produce StagedPath --- .../scala/hkmc2/codegen/Instrumentation.scala | 52 ++++++++----------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index df0c15aeb2..f1b4fa79f1 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -78,8 +78,8 @@ class InstrumentationImpl(using State): def blockMod(name: Str) = summon[State].blockSymbol.asPath.selSN(name) def optionMod(name: Str) = summon[State].optionSymbol.asPath.selSN(name) - def blockCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = - ctor(blockMod(name), args, symName)(k) + def blockCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: StagedPath => Block): Block = + ctor(blockMod(name), args, symName)(p => k(StagedPath(p))) def optionSome(arg: ArgWrappable, symName: Str = "tmp")(k: Path => Block): Block = ctor(optionMod("Some"), Ls(arg), symName)(k) def optionNone(symName: Str = "tmp")(k: Path => Block): Block = @@ -92,7 +92,7 @@ class InstrumentationImpl(using State): // linking functions defined in MLscipt - def fnPrintCode(p: Path)(k: Block): Block = + def fnPrintCode(p: StagedPath)(k: Block): Block = // discard result, we only care about side effect blockCall("printCode", Ls(p))(_ => k) @@ -101,7 +101,7 @@ class InstrumentationImpl(using State): // transformation helpers - def transformSymbol[S <: Symbol](sym: S, symName: Str = "sym")(k: Path => Block): Block = + def transformSymbol[S <: Symbol](sym: S, symName: Str = "sym")(k: StagedPath => Block): Block = sym match case clsSym: ClassSymbol => transformParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => @@ -116,43 +116,37 @@ class InstrumentationImpl(using State): // instrumentation rules def ruleLit(l: Value.Lit, symName: String = "lit")(k: StagedPath => Block): Block = - blockCtor("ValueLit", Ls(l), symName): cde => - k(StagedPath(cde)) + blockCtor("ValueLit", Ls(l), symName)(k) // not in formalization def ruleVar(r: Value.Ref, symName: String = "var")(k: StagedPath => Block): Block = val Value.Ref(l, disamb) = r transformSymbol(disamb.getOrElse(l)): sym => - blockCtor("ValueRef", Ls(sym), symName): cde => - k(StagedPath(cde)) + blockCtor("ValueRef", Ls(sym), symName)(k) def ruleTup(t: Tuple, symName: String = "tup")(using Context)(k: StagedPath => Block): Block = assert(!t.mut, "mutable tuple not supported") transformArgs(t.elems): xs => tuple(xs.map(_._1)): codes => - blockCtor("Tuple", Ls(codes), symName): cde => - k(StagedPath(cde)) + blockCtor("Tuple", Ls(codes), symName)(k) def ruleSel(s: Select, symName: String = "sel")(using Context)(k: StagedPath => Block): Block = val Select(p, i @ Tree.Ident(name)) = s transformPath(p): x => blockCtor("Symbol", Ls(toValue(name))): name => - blockCtor("Select", Ls(x, name), symName): cde => - k(StagedPath(cde)) + blockCtor("Select", Ls(x, name), symName)(k) def ruleDynSel(d: DynSelect, symName: String = "dynsel")(using Context)(k: StagedPath => Block): Block = transformPath(d.qual): x => transformPath(d.fld): y => - blockCtor("DynSelect", Ls(x, y, toValue(d.arrayIdx)), symName): cde => - k(StagedPath(cde)) + blockCtor("DynSelect", Ls(x, y, toValue(d.arrayIdx)), symName)(k) // TODO def ruleApp(c: Call, symName: String = "app")(using Context)(k: StagedPath => Block): Block = transformPath(c.fun): fun => transformArgs(c.args): args => tuple(args.map(_._1)): tup => - blockCtor("Call", Ls(fun, tup), symName): res => - k(StagedPath(res)) + blockCtor("Call", Ls(fun, tup), symName)(k) def ruleInst(i: Instantiate, symName: String = "inst")(using Context)(k: StagedPath => Block): Block = val Instantiate(mut, cls, args) = i @@ -168,13 +162,12 @@ class InstrumentationImpl(using State): // possible to skip this? this uses ruleVar, which is not in formalization transformPath(cls): cls => tuple(xs.map(_._1)): codes => - blockCtor("Instantiate", Ls(cls, codes), symName): cde => - k(StagedPath(cde)) + blockCtor("Instantiate", Ls(cls, codes), symName)(k) def ruleReturn(r: Return, symName: String = "return")(using Context)(k: (StagedPath, Context) => Block): Block = transformResult(r.res): x => blockCtor("Return", Ls(x.code, toValue(false)), symName): cde => - k(StagedPath(cde), summon) + k(cde, summon) def ruleMatch(m: Match, symName: String = "match")(using Context)(k: (StagedPath, Context) => Block): Block = val Match(p, ks, dflt, rest) = m @@ -191,21 +184,20 @@ class InstrumentationImpl(using State): blockCtor("ValueRef", Ls(xSym)): xStaged => // x should always be defined, either as an argument to the function or in a Scope Block assert(ctx.get(x.asPath).isDefined) - val x2 = StagedPath(xStaged) + val x2 = xStaged (Assign(x, x2.code, _)): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y, z), symName): cde => - k(StagedPath(cde), ctx) + k(cde, ctx) def ruleEnd(symName: String = "end")(k: StagedPath => Block): Block = - blockCtor("End", Ls(), symName): cde => - k(StagedPath(cde)) + blockCtor("End", Ls(), symName)(k) def ruleBlk(b: Block)(using Context)(k: Path => Block): Block = transformBlock(b)(k apply _.code) - def ruleCls(cls: ClsLikeDefn, rest: Block)(using Context)(k: Path => Block): Block = + def ruleCls(cls: ClsLikeDefn, rest: Block)(using Context)(k: StagedPath => Block): Block = assert(cls.companion.isEmpty, "nested module not supported") (Define(cls, _)): transformBlock(rest): p => @@ -229,8 +221,7 @@ class InstrumentationImpl(using State): optionSome(dflt.code)(k(_, ctx)) case N => optionNone()(k(_, ctx)) dfltStaged: (dflt, ctx) => - blockCtor("Match", Ls(x.code, arms, dflt, e), symName): m => - k(StagedPath(m), ctx) + blockCtor("Match", Ls(x.code, arms, dflt, e), symName)(k(_, ctx)) def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block, symName: String = "branch")(using ctx: Context)(k: (StagedPath, Context, StagedPath) => Block): Block = transformCase(cse): cse => @@ -270,8 +261,7 @@ class InstrumentationImpl(using State): transformOption(spread, bool => assign(toValue(bool))): spreadStaged => transformPath(value): value => blockCtor("Arg", Ls(spreadStaged, value)): cde => - val res = StagedPath(cde) - k(res, spread.isDefined) + k(cde, spread.isDefined) def transformArgs(args: Ls[Arg])(using Context)(k: Ls[(StagedPath, Bool)] => Block): Block = args.map(transformArg).collectApply(k) @@ -282,7 +272,7 @@ class InstrumentationImpl(using State): def transformParamsOpt(pOpt: Opt[ParamList])(k: Path => Block) = transformOption(pOpt, transformParamList)(k) - def transformCase(cse: Case)(using Context)(k: Path => Block): Block = + def transformCase(cse: Case)(using Context)(k: StagedPath => Block): Block = cse match case Case.Lit(lit) => blockCtor("Lit", Ls(Value.Lit(lit)))(k) case Case.Cls(cls, path) => @@ -308,7 +298,7 @@ class InstrumentationImpl(using State): argsList.foldRight(k)((args, cont) => res => call(res, args)(cont))(sym) makeCalls: ret => val p = StagedPath(ret) - fnPrintCode(p.code)(End()) + fnPrintCode(p)(End()) val dSym = TermSymbol(f.dSym.k, f.dSym.owner, Tree.Ident(f.sym.nme + "_gen")) val args = f.params.flatMap(_.params).map(_.sym) @@ -338,7 +328,7 @@ class InstrumentationImpl(using State): def transformScoped(s: Scoped)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = val Scoped(syms, body) = s blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undef => - val newCtx = ctx.clone() ++ syms.map(_.asPath -> StagedPath(undef)) + val newCtx = ctx.clone() ++ syms.map(_.asPath -> undef) transformBlock(body)(using newCtx): (p, ctx) => k(p, ctx) From 59a4af21a4c108cb1e590f75626ac75108f55870 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 18 Dec 2025 18:21:37 +0800 Subject: [PATCH 212/268] use ClassSymbol for ruleApp --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 5 +++-- hkmc2/shared/src/test/mlscript/staging/Functions.mls | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index f1b4fa79f1..2e6467d654 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -101,11 +101,13 @@ class InstrumentationImpl(using State): // transformation helpers - def transformSymbol[S <: Symbol](sym: S, symName: Str = "sym")(k: StagedPath => Block): Block = + def transformSymbol(sym: Symbol, symName: Str = "sym")(k: StagedPath => Block): Block = sym match case clsSym: ClassSymbol => transformParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => blockCtor("ClassSymbol", Ls(toValue(sym.nme), paramsOpt), symName)(k) + case t: TermSymbol if t.defn.exists(_.sym.asCls.isDefined) => + transformSymbol(t.defn.get.sym.asCls.get, symName)(k) case _ => blockCtor("Symbol", Ls(toValue(sym.nme)), symName)(k) def transformOption[A](xOpt: Opt[A], f: A => (Path => Block) => Block)(k: Path => Block): Block = @@ -141,7 +143,6 @@ class InstrumentationImpl(using State): transformPath(d.fld): y => blockCtor("DynSelect", Ls(x, y, toValue(d.arrayIdx)), symName)(k) - // TODO def ruleApp(c: Call, symName: String = "app")(using Context)(k: StagedPath => Block): Block = transformPath(c.fun): fun => transformArgs(c.args): args => diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index c33981860c..a9de261955 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -41,10 +41,12 @@ staged module ClassInstrumentation with class NoArg fun inst1() = new Outside(1) fun inst2() = new NoArg + fun app() = Outside(1) //│ > Define(ClsLikeDefn(ClassSymbol("NoArg"), TODO), End) //│ > Define(ClsLikeDefn(ClassSymbol("Inside":[Symbol("a"), Symbol("b")]), TODO), End) //│ > Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) //│ > Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), Symbol("NoArg")), []), false) +//│ > Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) :js :staging From 5adcfa39aba77e55773be1ac0e792b92ec5e6d56 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 18 Dec 2025 18:30:27 +0800 Subject: [PATCH 213/268] formatting --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 9 ++++----- hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 2e6467d654..355c8fc475 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -96,7 +96,7 @@ class InstrumentationImpl(using State): // discard result, we only care about side effect blockCall("printCode", Ls(p))(_ => k) - def fnConcat(p1: Path, p2: Path, symName: String = "concat")(k: Path => Block): Block = + def fnConcat(p1: StagedPath, p2: StagedPath, symName: String = "concat")(k: Path => Block): Block = blockCall("concat", Ls(p1, p2), symName)(k) // transformation helpers @@ -175,7 +175,7 @@ class InstrumentationImpl(using State): transformPath(p): x => ruleBranches(x, p, ks, dflt): (stagedMatch, ctx1) => transformBlock(rest)(using ctx1): (z, ctx2) => - fnConcat(stagedMatch.code, z.code, symName): cde => + fnConcat(stagedMatch, z, symName): cde => k(StagedPath(cde), ctx2) def ruleAssign(a: Assign, symName: String = "assign")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = @@ -189,8 +189,7 @@ class InstrumentationImpl(using State): (Assign(x, x2.code, _)): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => - blockCtor("Assign", Ls(xSym, y, z), symName): cde => - k(cde, ctx) + blockCtor("Assign", Ls(xSym, y, z), symName)(k(_, ctx)) def ruleEnd(symName: String = "end")(k: StagedPath => Block): Block = blockCtor("End", Ls(), symName)(k) @@ -323,7 +322,7 @@ class InstrumentationImpl(using State): def transformBegin(b: Begin)(using Context)(k: (StagedPath, Context) => Block): Block = transformBlock(b.sub): (sub, ctx) => transformBlock(b.rest)(using ctx): (rest, ctx) => - fnConcat(sub.code, rest.code): block => + fnConcat(sub, rest): block => k(StagedPath(block), ctx) def transformScoped(s: Scoped)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index bfa47c79be..50a9e50b9b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -1065,7 +1065,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): val merged = MergeMatchArmTransformer.applyBlock(bufferable) val staged = - if config.stageCode then Instrumentation(using summon).applyBlock(merged) + if config.stageCode then Instrumentation().applyBlock(merged) else merged val res = From a4c8df09f3aa9bc29d47ac9178ce5aa9ba6b982c Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 18 Dec 2025 18:44:42 +0800 Subject: [PATCH 214/268] update tests --- .../src/test/mlscript/staging/Functions.mls | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index a9de261955..509fa8423f 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -21,8 +21,8 @@ staged module Expressions with fun match2() = if [...x] is [] then 1 - [a, ...] then 2 - // [1, 2] then 5 // TODO: needs handling for Label, Break + // [1, 2] then 2 // TODO: needs handling for Label, Break + [a, ...] then 3 else 0 //│ > Return(Lit(1), false) //│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) @@ -30,9 +30,20 @@ staged module Expressions with //│ > Return(Tuple([Lit(1), ..Ref(Symbol("x"))]), false) //│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) //│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End)) -//│ > Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Return(Lit(1), false), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Return(Lit(2), false))))], Return(Lit(0), false), End)) +//│ > Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Return(Lit(1), false), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Return(Lit(3), false))))], Return(Lit(0), false), End)) //│ x = [1, 2, 3] +:js +:staging +:fixme +staged module OtherBlocks with + fun breakAndLabel() = + if 1 is + 2 then 0 + 3 then 0 + else 0 +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + :js :staging class Outside(a) @@ -41,12 +52,14 @@ staged module ClassInstrumentation with class NoArg fun inst1() = new Outside(1) fun inst2() = new NoArg - fun app() = Outside(1) + fun app1() = Outside(1) + fun app2() = Inside(1, 2) //│ > Define(ClsLikeDefn(ClassSymbol("NoArg"), TODO), End) //│ > Define(ClsLikeDefn(ClassSymbol("Inside":[Symbol("a"), Symbol("b")]), TODO), End) //│ > Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) //│ > Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), Symbol("NoArg")), []), false) //│ > Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) +//│ > Return(Call(Select(Ref(Symbol("ClassInstrumentation")), Symbol("Inside")), [Lit(1), Lit(2)]), false) :js :staging @@ -76,8 +89,8 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.73: staged module B with +//│ ║ l.88: staged module B with //│ ║ ^^^^^^ -//│ ║ l.74: fun f() = 1 +//│ ║ l.89: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From 7abddf95ac7211d47aee38f07e46c3949fcdea51 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 22 Dec 2025 23:06:27 +0800 Subject: [PATCH 215/268] remove StagedPath after shape information is removed, the extra typechecking is no longer helpful --- .../scala/hkmc2/codegen/Instrumentation.scala | 127 ++++++++---------- 1 file changed, 57 insertions(+), 70 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 355c8fc475..0dd49eacab 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -22,13 +22,12 @@ import syntax.{Literal, Tree} // transform Block to Block IR so that it can be instrumented in mlscript class InstrumentationImpl(using State): - type ArgWrappable = Path | StagedPath | Symbol - type Context = HashMap[Path, StagedPath] + type ArgWrappable = Path | Symbol + type Context = HashMap[Path, Path] def asArg(x: ArgWrappable): Arg = x match case p: Path => p.asArg - case s: StagedPath => s.code.asArg case l: Symbol => l.asPath.asArg // null and undefined are missing @@ -40,12 +39,6 @@ class InstrumentationImpl(using State): case n: BigDecimal => Tree.DecLit(n) Value.Lit(l) - def concat(b1: Block, b2: Block): Block = - b1.mapTail { - case _: End => b2 - case _ => ??? - } - extension [A, B](ls: Ls[(A => B) => B]) def collectApply(f: Ls[A] => B): B = // defer applying k while prepending new elements to the list @@ -78,8 +71,8 @@ class InstrumentationImpl(using State): def blockMod(name: Str) = summon[State].blockSymbol.asPath.selSN(name) def optionMod(name: Str) = summon[State].optionSymbol.asPath.selSN(name) - def blockCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: StagedPath => Block): Block = - ctor(blockMod(name), args, symName)(p => k(StagedPath(p))) + def blockCtor(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = + ctor(blockMod(name), args, symName)(k) def optionSome(arg: ArgWrappable, symName: Str = "tmp")(k: Path => Block): Block = ctor(optionMod("Some"), Ls(arg), symName)(k) def optionNone(symName: Str = "tmp")(k: Path => Block): Block = @@ -88,20 +81,18 @@ class InstrumentationImpl(using State): def blockCall(name: Str, args: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = call(blockMod(name), args, symName = symName)(k) - case class StagedPath(code: Path) - // linking functions defined in MLscipt - def fnPrintCode(p: StagedPath)(k: Block): Block = + def fnPrintCode(p: Path)(k: Block): Block = // discard result, we only care about side effect blockCall("printCode", Ls(p))(_ => k) - def fnConcat(p1: StagedPath, p2: StagedPath, symName: String = "concat")(k: Path => Block): Block = + def fnConcat(p1: Path, p2: Path, symName: String = "concat")(k: Path => Block): Block = blockCall("concat", Ls(p1, p2), symName)(k) // transformation helpers - def transformSymbol(sym: Symbol, symName: Str = "sym")(k: StagedPath => Block): Block = + def transformSymbol(sym: Symbol, symName: Str = "sym")(k: Path => Block): Block = sym match case clsSym: ClassSymbol => transformParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => @@ -117,68 +108,60 @@ class InstrumentationImpl(using State): // instrumentation rules - def ruleLit(l: Value.Lit, symName: String = "lit")(k: StagedPath => Block): Block = + def ruleLit(l: Value.Lit, symName: String = "lit")(k: Path => Block): Block = blockCtor("ValueLit", Ls(l), symName)(k) // not in formalization - def ruleVar(r: Value.Ref, symName: String = "var")(k: StagedPath => Block): Block = + def ruleVar(r: Value.Ref, symName: String = "var")(k: Path => Block): Block = val Value.Ref(l, disamb) = r transformSymbol(disamb.getOrElse(l)): sym => blockCtor("ValueRef", Ls(sym), symName)(k) - def ruleTup(t: Tuple, symName: String = "tup")(using Context)(k: StagedPath => Block): Block = + def ruleTup(t: Tuple, symName: String = "tup")(using Context)(k: Path => Block): Block = assert(!t.mut, "mutable tuple not supported") transformArgs(t.elems): xs => tuple(xs.map(_._1)): codes => blockCtor("Tuple", Ls(codes), symName)(k) - def ruleSel(s: Select, symName: String = "sel")(using Context)(k: StagedPath => Block): Block = + def ruleSel(s: Select, symName: String = "sel")(using Context)(k: Path => Block): Block = val Select(p, i @ Tree.Ident(name)) = s transformPath(p): x => blockCtor("Symbol", Ls(toValue(name))): name => blockCtor("Select", Ls(x, name), symName)(k) - def ruleDynSel(d: DynSelect, symName: String = "dynsel")(using Context)(k: StagedPath => Block): Block = + def ruleDynSel(d: DynSelect, symName: String = "dynsel")(using Context)(k: Path => Block): Block = transformPath(d.qual): x => transformPath(d.fld): y => blockCtor("DynSelect", Ls(x, y, toValue(d.arrayIdx)), symName)(k) - def ruleApp(c: Call, symName: String = "app")(using Context)(k: StagedPath => Block): Block = + def ruleApp(c: Call, symName: String = "app")(using Context)(k: Path => Block): Block = transformPath(c.fun): fun => transformArgs(c.args): args => tuple(args.map(_._1)): tup => blockCtor("Call", Ls(fun, tup), symName)(k) - def ruleInst(i: Instantiate, symName: String = "inst")(using Context)(k: StagedPath => Block): Block = + def ruleInst(i: Instantiate, symName: String = "inst")(using Context)(k: Path => Block): Block = val Instantiate(mut, cls, args) = i assert(!mut, "mutable instantiation not supported") transformArgs(args): xs => - val sym = cls match - // TODO: if class is staged, we can just use Symbol without storing the arguments - case Value.Ref(l, S(disamb)) => transformSymbol(disamb) - case s: Select if s.symbol.isDefined => transformSymbol(s.symbol.get) - case _ => transformSymbol(TempSymbol(N, "TODO")) - sym: sym => - // reuse instrumentation logic, shape of cls is discarded - // possible to skip this? this uses ruleVar, which is not in formalization - transformPath(cls): cls => - tuple(xs.map(_._1)): codes => - blockCtor("Instantiate", Ls(cls, codes), symName)(k) - - def ruleReturn(r: Return, symName: String = "return")(using Context)(k: (StagedPath, Context) => Block): Block = + transformPath(cls): cls => + tuple(xs.map(_._1)): codes => + blockCtor("Instantiate", Ls(cls, codes), "inst")(k) + + def ruleReturn(r: Return, symName: String = "return")(using Context)(k: (Path, Context) => Block): Block = transformResult(r.res): x => - blockCtor("Return", Ls(x.code, toValue(false)), symName): cde => + blockCtor("Return", Ls(x, toValue(false)), symName): cde => k(cde, summon) - def ruleMatch(m: Match, symName: String = "match")(using Context)(k: (StagedPath, Context) => Block): Block = + def ruleMatch(m: Match, symName: String = "match")(using Context)(k: (Path, Context) => Block): Block = val Match(p, ks, dflt, rest) = m transformPath(p): x => ruleBranches(x, p, ks, dflt): (stagedMatch, ctx1) => transformBlock(rest)(using ctx1): (z, ctx2) => fnConcat(stagedMatch, z, symName): cde => - k(StagedPath(cde), ctx2) + k(cde, ctx2) - def ruleAssign(a: Assign, symName: String = "assign")(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def ruleAssign(a: Assign, symName: String = "assign")(using ctx: Context)(k: (Path, Context) => Block): Block = val Assign(x, r, b) = a transformResult(r): y => transformSymbol(x): xSym => @@ -186,18 +169,18 @@ class InstrumentationImpl(using State): // x should always be defined, either as an argument to the function or in a Scope Block assert(ctx.get(x.asPath).isDefined) val x2 = xStaged - (Assign(x, x2.code, _)): + (Assign(x, x2, _)): given Context = ctx.clone() += x.asPath -> x2 transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y, z), symName)(k(_, ctx)) - def ruleEnd(symName: String = "end")(k: StagedPath => Block): Block = + def ruleEnd(symName: String = "end")(k: Path => Block): Block = blockCtor("End", Ls(), symName)(k) def ruleBlk(b: Block)(using Context)(k: Path => Block): Block = - transformBlock(b)(k apply _.code) + transformBlock(b)(k) - def ruleCls(cls: ClsLikeDefn, rest: Block)(using Context)(k: StagedPath => Block): Block = + def ruleCls(cls: ClsLikeDefn, rest: Block)(using Context)(k: Path => Block): Block = assert(cls.companion.isEmpty, "nested module not supported") (Define(cls, _)): transformBlock(rest): p => @@ -207,38 +190,36 @@ class InstrumentationImpl(using State): blockCtor("ClsLikeDefn", Ls(c, none)): cls => blockCtor("Define", Ls(cls, p))(k) - def ruleBranches(x: StagedPath, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block], symName: String = "branches")(using Context)(k: (StagedPath, Context) => Block): Block = - def applyRuleBranch(cse: Case, block: Block)(f: StagedPath => (Context, StagedPath) => Block)(ctx: Context, x: StagedPath): Block = + def ruleBranches(x: Path, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block], symName: String = "branches")(using Context)(k: (Path, Context) => Block): Block = + def applyRuleBranch(cse: Case, block: Block)(f: Path => (Context, Path) => Block)(ctx: Context, x: Path): Block = ruleBranch(x, p, cse, block)(using ctx)((y, ctx, x) => f(y)(ctx, x)) val a = arms.map(applyRuleBranch).collectApply - ((f: (Ls[StagedPath], Context) => Block) => a(ys => (ctx, _) => f(ys, ctx))(summon, x)): (arms, ctx) => + ((f: (Ls[Path], Context) => Block) => a(ys => (ctx, _) => f(ys, ctx))(summon, x)): (arms, ctx) => tuple(arms): arms => ruleEnd(): e => // TODO: use transformOption here def dfltStaged(k: (Path, Context) => Block) = dflt match - case S(dflt) => ruleWildCard(x, p, dflt): (dflt, ctx) => - optionSome(dflt.code)(k(_, ctx)) + case S(dflt) => ruleWildCard(x, p, dflt)((dflt, ctx) => optionSome(dflt)(k(_, ctx))) case N => optionNone()(k(_, ctx)) dfltStaged: (dflt, ctx) => - blockCtor("Match", Ls(x.code, arms, dflt, e), symName)(k(_, ctx)) + blockCtor("Match", Ls(x, arms, dflt, e), symName)(k(_, ctx)) - def ruleBranch(x: StagedPath, p: Path, cse: Case, b: Block, symName: String = "branch")(using ctx: Context)(k: (StagedPath, Context, StagedPath) => Block): Block = + def ruleBranch(x: Path, p: Path, cse: Case, b: Block, symName: String = "branch")(using ctx: Context)(k: (Path, Context, Path) => Block): Block = transformCase(cse): cse => transformBlock(b)(using ctx.clone() += p -> x): (y, ctx) => // TODO: use Arm type instead of Tup tuple(Ls(cse, y), symName): cde => - val ret = StagedPath(cde) - k(ret, ctx.clone() -= p, x) + k(cde, ctx.clone() -= p, x) - def ruleWildCard(x: StagedPath, p: Path, b: Block)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def ruleWildCard(x: Path, p: Path, b: Block)(using ctx: Context)(k: (Path, Context) => Block): Block = given Context = ctx.clone() += p -> x transformBlock(b): (y, ctx) => k(y, ctx.clone() -= p) // transformations of Block - def transformPath(p: Path)(using ctx: Context)(k: StagedPath => Block): Block = + def transformPath(p: Path)(using ctx: Context)(k: Path => Block): Block = // rulePath ctx.get(p).map(k).getOrElse: p match @@ -248,7 +229,7 @@ class InstrumentationImpl(using State): case d: DynSelect => ruleDynSel(d)(k) case _ => ??? // not supported - def transformResult(r: Result)(using Context)(k: StagedPath => Block): Block = + def transformResult(r: Result)(using Context)(k: Path => Block): Block = r match case p: Path => transformPath(p)(k) case t: Tuple => ruleTup(t)(k) @@ -256,14 +237,14 @@ class InstrumentationImpl(using State): case c: Call => ruleApp(c)(k) case _ => ??? // not supported - def transformArg(a: Arg)(using Context)(k: ((StagedPath, Bool)) => Block): Block = + def transformArg(a: Arg)(using Context)(k: ((Path, Bool)) => Block): Block = val Arg(spread, value) = a transformOption(spread, bool => assign(toValue(bool))): spreadStaged => transformPath(value): value => blockCtor("Arg", Ls(spreadStaged, value)): cde => k(cde, spread.isDefined) - def transformArgs(args: Ls[Arg])(using Context)(k: Ls[(StagedPath, Bool)] => Block): Block = + def transformArgs(args: Ls[Arg])(using Context)(k: Ls[(Path, Bool)] => Block): Block = args.map(transformArg).collectApply(k) def transformParamList(ps: ParamList)(k: Path => Block) = @@ -272,7 +253,7 @@ class InstrumentationImpl(using State): def transformParamsOpt(pOpt: Opt[ParamList])(k: Path => Block) = transformOption(pOpt, transformParamList)(k) - def transformCase(cse: Case)(using Context)(k: StagedPath => Block): Block = + def transformCase(cse: Case)(using Context)(k: Path => Block): Block = cse match case Case.Lit(lit) => blockCtor("Lit", Ls(Value.Lit(lit)))(k) case Case.Cls(cls, path) => @@ -297,19 +278,19 @@ class InstrumentationImpl(using State): def makeCalls(k: Path => Block) = argsList.foldRight(k)((args, cont) => res => call(res, args)(cont))(sym) makeCalls: ret => - val p = StagedPath(ret) + val p = ret fnPrintCode(p)(End()) val dSym = TermSymbol(f.dSym.k, f.dSym.owner, Tree.Ident(f.sym.nme + "_gen")) val args = f.params.flatMap(_.params).map(_.sym) val newBody = ruleEnd(): end => - given Context = HashMap(args.map(s => Value.Ref(s, N) -> StagedPath(Value.Ref(s, N)))*) - transformBlock(f.body)(p => Return(p.code, false)) + given Context = HashMap(args.map(s => Value.Ref(s, N) -> Value.Ref(s, N))*) + transformBlock(f.body)(p => Return(p, false)) val newFun = f.copy(sym = genSym, dSym = dSym, body = newBody)(false) (newFun, debug) - def transformDefine(d: Define)(using Context)(k: (StagedPath, Context) => Block): Block = + def transformDefine(d: Define)(using Context)(k: (Path, Context) => Block): Block = d.defn match case c: ClsLikeDefn => ruleCls(c, d.rest): p => @@ -319,13 +300,13 @@ class InstrumentationImpl(using State): // TODO // discards result of sub - def transformBegin(b: Begin)(using Context)(k: (StagedPath, Context) => Block): Block = + def transformBegin(b: Begin)(using Context)(k: (Path, Context) => Block): Block = transformBlock(b.sub): (sub, ctx) => transformBlock(b.rest)(using ctx): (rest, ctx) => fnConcat(sub, rest): block => - k(StagedPath(block), ctx) + k(block, ctx) - def transformScoped(s: Scoped)(using ctx: Context)(k: (StagedPath, Context) => Block): Block = + def transformScoped(s: Scoped)(using ctx: Context)(k: (Path, Context) => Block): Block = val Scoped(syms, body) = s blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undef => val newCtx = ctx.clone() ++ syms.map(_.asPath -> undef) @@ -333,10 +314,10 @@ class InstrumentationImpl(using State): k(p, ctx) // ruleBlk? - def transformBlock(b: Block)(using Context)(k: StagedPath => Block): Block = + def transformBlock(b: Block)(using Context)(k: Path => Block): Block = transformBlock(b)((p, _) => k(p)) - def transformBlock(b: Block)(using Context)(k: (StagedPath, Context) => Block): Block = + def transformBlock(b: Block)(using Context)(k: (Path, Context) => Block): Block = b match case r: Return => ruleReturn(r)(k) case a: Assign => ruleAssign(a)(k) @@ -345,7 +326,7 @@ class InstrumentationImpl(using State): case m: Match => ruleMatch(m)(k) // temporary measure to accept returning an array // use BlockTransformer here? - case b: Begin => transformBegin(b)(k) + case b: Begin => ??? // transformBegin(b)(k) // case Begin(b1, b2) => transformBlock(concat(b1, b2))(k) case s: Scoped => transformScoped(s)(k) case _ => ??? // not supported @@ -354,6 +335,12 @@ class InstrumentationImpl(using State): class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): val impl = new InstrumentationImpl + def concat(b1: Block, b2: Block): Block = + b1.mapTail { + case _: End => b2 + case _ => ??? + } + override def applyBlock(b: Block): Block = super.applyBlock(b) match case d @ Define(defn, rest) => defn match @@ -368,7 +355,7 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): val newCompanion = companion.copy(methods = companion.methods ++ stagedMethods, ctor = newCtor) val newModule = c.copy(sym = sym, companion = S(newCompanion)) // debug is printed after definition - val debugBlock = debugPrintCode.foldRight(rest)(impl.concat) + val debugBlock = debugPrintCode.foldRight(rest)(concat) Define(newModule, debugBlock) case _ => d case b => b From f0c6f52b6b3275fdc85e5b31dab3ef370e4761fa Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 22 Dec 2025 23:17:56 +0800 Subject: [PATCH 216/268] formatting --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 0dd49eacab..c5d13f1e49 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -168,9 +168,8 @@ class InstrumentationImpl(using State): blockCtor("ValueRef", Ls(xSym)): xStaged => // x should always be defined, either as an argument to the function or in a Scope Block assert(ctx.get(x.asPath).isDefined) - val x2 = xStaged - (Assign(x, x2, _)): - given Context = ctx.clone() += x.asPath -> x2 + (Assign(x, xStaged, _)): + given Context = ctx.clone() += x.asPath -> xStaged transformBlock(b): (z, ctx) => blockCtor("Assign", Ls(xSym, y, z), symName)(k(_, ctx)) From a407e01b24519117db7304d9846870a875859d27 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 23 Dec 2025 00:06:18 +0800 Subject: [PATCH 217/268] inline functions --- .../scala/hkmc2/codegen/Instrumentation.scala | 274 +++++++----------- 1 file changed, 105 insertions(+), 169 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index c5d13f1e49..29c42ad81a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -14,9 +14,6 @@ import semantics.Elaborator.State import syntax.{Literal, Tree} -// it seems some logic should be deferred to BlockTransformer to dedup code -// but it doesn't accept the current context, so applications seem limited - // it should be possible to cache some common constructions (End, Option) into the context // this avoids having to rebuild the same shapes everytime they are needed @@ -108,90 +105,16 @@ class InstrumentationImpl(using State): // instrumentation rules - def ruleLit(l: Value.Lit, symName: String = "lit")(k: Path => Block): Block = - blockCtor("ValueLit", Ls(l), symName)(k) - - // not in formalization - def ruleVar(r: Value.Ref, symName: String = "var")(k: Path => Block): Block = - val Value.Ref(l, disamb) = r - transformSymbol(disamb.getOrElse(l)): sym => - blockCtor("ValueRef", Ls(sym), symName)(k) - - def ruleTup(t: Tuple, symName: String = "tup")(using Context)(k: Path => Block): Block = - assert(!t.mut, "mutable tuple not supported") - transformArgs(t.elems): xs => - tuple(xs.map(_._1)): codes => - blockCtor("Tuple", Ls(codes), symName)(k) - - def ruleSel(s: Select, symName: String = "sel")(using Context)(k: Path => Block): Block = - val Select(p, i @ Tree.Ident(name)) = s - transformPath(p): x => - blockCtor("Symbol", Ls(toValue(name))): name => - blockCtor("Select", Ls(x, name), symName)(k) - - def ruleDynSel(d: DynSelect, symName: String = "dynsel")(using Context)(k: Path => Block): Block = - transformPath(d.qual): x => - transformPath(d.fld): y => - blockCtor("DynSelect", Ls(x, y, toValue(d.arrayIdx)), symName)(k) - - def ruleApp(c: Call, symName: String = "app")(using Context)(k: Path => Block): Block = - transformPath(c.fun): fun => - transformArgs(c.args): args => - tuple(args.map(_._1)): tup => - blockCtor("Call", Ls(fun, tup), symName)(k) - - def ruleInst(i: Instantiate, symName: String = "inst")(using Context)(k: Path => Block): Block = - val Instantiate(mut, cls, args) = i - assert(!mut, "mutable instantiation not supported") - transformArgs(args): xs => - transformPath(cls): cls => - tuple(xs.map(_._1)): codes => - blockCtor("Instantiate", Ls(cls, codes), "inst")(k) - - def ruleReturn(r: Return, symName: String = "return")(using Context)(k: (Path, Context) => Block): Block = - transformResult(r.res): x => - blockCtor("Return", Ls(x, toValue(false)), symName): cde => - k(cde, summon) - - def ruleMatch(m: Match, symName: String = "match")(using Context)(k: (Path, Context) => Block): Block = - val Match(p, ks, dflt, rest) = m - transformPath(p): x => - ruleBranches(x, p, ks, dflt): (stagedMatch, ctx1) => - transformBlock(rest)(using ctx1): (z, ctx2) => - fnConcat(stagedMatch, z, symName): cde => - k(cde, ctx2) - - def ruleAssign(a: Assign, symName: String = "assign")(using ctx: Context)(k: (Path, Context) => Block): Block = - val Assign(x, r, b) = a - transformResult(r): y => - transformSymbol(x): xSym => - blockCtor("ValueRef", Ls(xSym)): xStaged => - // x should always be defined, either as an argument to the function or in a Scope Block - assert(ctx.get(x.asPath).isDefined) - (Assign(x, xStaged, _)): - given Context = ctx.clone() += x.asPath -> xStaged - transformBlock(b): (z, ctx) => - blockCtor("Assign", Ls(xSym, y, z), symName)(k(_, ctx)) - def ruleEnd(symName: String = "end")(k: Path => Block): Block = blockCtor("End", Ls(), symName)(k) - def ruleBlk(b: Block)(using Context)(k: Path => Block): Block = - transformBlock(b)(k) - - def ruleCls(cls: ClsLikeDefn, rest: Block)(using Context)(k: Path => Block): Block = - assert(cls.companion.isEmpty, "nested module not supported") - (Define(cls, _)): - transformBlock(rest): p => - transformParamsOpt(cls.paramsOpt): paramsOpt => - transformSymbol(cls.isym): c => - optionNone(): none => // TODO: handle companion object - blockCtor("ClsLikeDefn", Ls(c, none)): cls => - blockCtor("Define", Ls(cls, p))(k) - def ruleBranches(x: Path, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block], symName: String = "branches")(using Context)(k: (Path, Context) => Block): Block = def applyRuleBranch(cse: Case, block: Block)(f: Path => (Context, Path) => Block)(ctx: Context, x: Path): Block = - ruleBranch(x, p, cse, block)(using ctx)((y, ctx, x) => f(y)(ctx, x)) + transformCase(cse): cse => + transformBlock(block)(using ctx.clone() += p -> x): (y, ctx) => + // TODO: use Arm type instead of Tup + tuple(Ls(cse, y), "branch"): cde => + f(cde)(ctx.clone() -= p, x) val a = arms.map(applyRuleBranch).collectApply ((f: (Ls[Path], Context) => Block) => a(ys => (ctx, _) => f(ys, ctx))(summon, x)): (arms, ctx) => @@ -199,41 +122,54 @@ class InstrumentationImpl(using State): ruleEnd(): e => // TODO: use transformOption here def dfltStaged(k: (Path, Context) => Block) = dflt match - case S(dflt) => ruleWildCard(x, p, dflt)((dflt, ctx) => optionSome(dflt)(k(_, ctx))) + case S(dflt) => + transformBlock(dflt)(using ctx.clone() += p -> x): (dflt, ctx) => + optionSome(dflt)(k(_, ctx.clone() -= p)) case N => optionNone()(k(_, ctx)) dfltStaged: (dflt, ctx) => blockCtor("Match", Ls(x, arms, dflt, e), symName)(k(_, ctx)) - def ruleBranch(x: Path, p: Path, cse: Case, b: Block, symName: String = "branch")(using ctx: Context)(k: (Path, Context, Path) => Block): Block = - transformCase(cse): cse => - transformBlock(b)(using ctx.clone() += p -> x): (y, ctx) => - // TODO: use Arm type instead of Tup - tuple(Ls(cse, y), symName): cde => - k(cde, ctx.clone() -= p, x) - - def ruleWildCard(x: Path, p: Path, b: Block)(using ctx: Context)(k: (Path, Context) => Block): Block = - given Context = ctx.clone() += p -> x - transformBlock(b): (y, ctx) => - k(y, ctx.clone() -= p) - // transformations of Block def transformPath(p: Path)(using ctx: Context)(k: Path => Block): Block = // rulePath ctx.get(p).map(k).getOrElse: p match - case r: Value.Ref => ruleVar(r)(k) - case l: Value.Lit => ruleLit(l)(k) - case s: Select => ruleSel(s)(k) - case d: DynSelect => ruleDynSel(d)(k) + case Value.Ref(l, disamb) => + // not in formalization + transformSymbol(disamb.getOrElse(l)): sym => + blockCtor("ValueRef", Ls(sym), "var")(k) + case l: Value.Lit => + blockCtor("ValueLit", Ls(l), "lit")(k) + case Select(p, i @ Tree.Ident(name)) => + transformPath(p): x => + blockCtor("Symbol", Ls(toValue(name))): name => + blockCtor("Select", Ls(x, name), "sel")(k) + case DynSelect(qual, fld, arrayIdx) => + transformPath(qual): x => + transformPath(fld): y => + blockCtor("DynSelect", Ls(x, y, toValue(arrayIdx)), "dynsel")(k) case _ => ??? // not supported def transformResult(r: Result)(using Context)(k: Path => Block): Block = r match case p: Path => transformPath(p)(k) - case t: Tuple => ruleTup(t)(k) - case i: Instantiate => ruleInst(i)(k) - case c: Call => ruleApp(c)(k) + case Tuple(mut, elems) => + assert(!mut, "mutable tuple not supported") + transformArgs(elems): xs => + tuple(xs.map(_._1)): codes => + blockCtor("Tuple", Ls(codes), "tup")(k) + case Instantiate(mut, cls, args) => + assert(!mut, "mutable instantiation not supported") + transformArgs(args): xs => + transformPath(cls): cls => + tuple(xs.map(_._1)): codes => + blockCtor("Instantiate", Ls(cls, codes), "inst")(k) + case Call(fun, args) => + transformPath(fun): fun => + transformArgs(args): args => + tuple(args.map(_._1)): tup => + blockCtor("Call", Ls(fun, tup), "app")(k) case _ => ??? // not supported def transformArg(a: Arg)(using Context)(k: ((Path, Bool)) => Block): Block = @@ -262,6 +198,54 @@ class InstrumentationImpl(using State): case Case.Tup(len, inf) => blockCtor("Tup", Ls(len, inf).map(toValue))(k) case Case.Field(name, safe) => ??? // not supported + // ruleBlk? + def transformBlock(b: Block)(using Context)(k: Path => Block): Block = + transformBlock(b)((p, _) => k(p)) + + def transformBlock(b: Block)(using ctx: Context)(k: (Path, Context) => Block): Block = + b match + case Return(res, implct) => + transformResult(res): x => + blockCtor("Return", Ls(x, toValue(implct)), "return")(k(_, ctx)) + case Assign(x, r, b) => + transformResult(r): y => + transformSymbol(x): xSym => + blockCtor("ValueRef", Ls(xSym)): xStaged => + // x should always be defined, either as an argument to the function or in a Scope Block + assert(ctx.get(x.asPath).isDefined) + (Assign(x, xStaged, _)): + given Context = ctx.clone() += x.asPath -> xStaged + transformBlock(b): (z, ctx) => + blockCtor("Assign", Ls(xSym, y, z), "assign")(k(_, ctx)) + case Define(cls: ClsLikeDefn, rest) => + assert(cls.companion.isEmpty, "nested module not supported") + (Define(cls, _)): + transformBlock(rest): p => + transformParamsOpt(cls.paramsOpt): paramsOpt => + transformSymbol(cls.isym): c => + optionNone(): none => // TODO: handle companion object + blockCtor("ClsLikeDefn", Ls(c, none)): cls => + blockCtor("Define", Ls(cls, p)): p => + ruleEnd(): end => + fnPrintCode(p)(k(end, summon)) + case End(_) => ruleEnd()(k(_, summon)) + case Match(p, ks, dflt, rest) => + transformPath(p): x => + ruleBranches(x, p, ks, dflt): (stagedMatch, ctx1) => + transformBlock(rest)(using ctx1): (z, ctx2) => + fnConcat(stagedMatch, z, "match"): cde => + k(cde, ctx2) + case Begin(sub, rest) => + // TODO: This is untested as there is no test case that generates the Begin block yet + transformBlock(sub): (sub, ctx) => + transformBlock(rest)(using ctx): (rest, ctx) => + fnConcat(sub, rest)(k(_, ctx)) + case Scoped(syms, body) => + blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undef => + val newCtx = ctx.clone() ++ syms.map(_.asPath -> undef) + transformBlock(body)(using newCtx)(k) + case _ => ??? // not supported + // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function // so we pass modSym instead def transformFunDefn(modSym: BlockMemberSymbol, f: FunDefn): (FunDefn, Block) = @@ -269,16 +253,12 @@ class InstrumentationImpl(using State): val sym = modSym.asPath.selSN(genSym.nme) // NOTE: this debug printing only works for top-level modules, nested modules don't work // TODO: remove it. only for test - val debug = - blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undef => - // TODO: put correct parameters instead of End - // TODO: handle curried arguments - val argsList = f.params.map(ps => List.fill(ps.params.length)(undef)) - def makeCalls(k: Path => Block) = - argsList.foldRight(k)((args, cont) => res => call(res, args)(cont))(sym) - makeCalls: ret => - val p = ret - fnPrintCode(p)(End()) + val debug = blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undef => + // TODO: put correct parameters instead of End + val argsList = f.params.map(ps => List.fill(ps.params.length)(undef)) + def makeCalls(k: Path => Block) = + argsList.foldRight(k)((args, cont) => res => call(res, args)(cont))(sym) + makeCalls(fnPrintCode(_)(End())) val dSym = TermSymbol(f.dSym.k, f.dSym.owner, Tree.Ident(f.sym.nme + "_gen")) val args = f.params.flatMap(_.params).map(_.sym) @@ -289,47 +269,6 @@ class InstrumentationImpl(using State): val newFun = f.copy(sym = genSym, dSym = dSym, body = newBody)(false) (newFun, debug) - def transformDefine(d: Define)(using Context)(k: (Path, Context) => Block): Block = - d.defn match - case c: ClsLikeDefn => - ruleCls(c, d.rest): p => - ruleEnd(): b => - fnPrintCode(p)(k(b, summon)) - case _: FunDefn | _: ValDefn => ??? - - // TODO - // discards result of sub - def transformBegin(b: Begin)(using Context)(k: (Path, Context) => Block): Block = - transformBlock(b.sub): (sub, ctx) => - transformBlock(b.rest)(using ctx): (rest, ctx) => - fnConcat(sub, rest): block => - k(block, ctx) - - def transformScoped(s: Scoped)(using ctx: Context)(k: (Path, Context) => Block): Block = - val Scoped(syms, body) = s - blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undef => - val newCtx = ctx.clone() ++ syms.map(_.asPath -> undef) - transformBlock(body)(using newCtx): (p, ctx) => - k(p, ctx) - - // ruleBlk? - def transformBlock(b: Block)(using Context)(k: Path => Block): Block = - transformBlock(b)((p, _) => k(p)) - - def transformBlock(b: Block)(using Context)(k: (Path, Context) => Block): Block = - b match - case r: Return => ruleReturn(r)(k) - case a: Assign => ruleAssign(a)(k) - case d: Define => transformDefine(d)(k) - case End(_) => ruleEnd()(k(_, summon)) - case m: Match => ruleMatch(m)(k) - // temporary measure to accept returning an array - // use BlockTransformer here? - case b: Begin => ??? // transformBegin(b)(k) - // case Begin(b1, b2) => transformBlock(concat(b1, b2))(k) - case s: Scoped => transformScoped(s)(k) - case _ => ??? // not supported - // TODO: rename as InstrumentationTransformer? class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): val impl = new InstrumentationImpl @@ -341,20 +280,17 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): } override def applyBlock(b: Block): Block = super.applyBlock(b) match - case d @ Define(defn, rest) => - defn match - // find modules with staged annotation - case c: ClsLikeDefn if c.companion.exists(_.isym.defn.exists(_.hasStagedModifier.isDefined)) => - val sym = c.sym.subst - val companion = c.companion.get - val (stagedMethods, debugPrintCode) = companion.methods - .map(impl.transformFunDefn(sym, _)) - .unzip - val newCtor = impl.transformBlock(companion.ctor)(using new HashMap())(_ => End()) - val newCompanion = companion.copy(methods = companion.methods ++ stagedMethods, ctor = newCtor) - val newModule = c.copy(sym = sym, companion = S(newCompanion)) - // debug is printed after definition - val debugBlock = debugPrintCode.foldRight(rest)(concat) - Define(newModule, debugBlock) - case _ => d + // find modules with staged annotation + case Define(c: ClsLikeDefn, rest) if c.companion.exists(_.isym.defn.exists(_.hasStagedModifier.isDefined)) => + val sym = c.sym.subst + val companion = c.companion.get + val (stagedMethods, debugPrintCode) = companion.methods + .map(impl.transformFunDefn(sym, _)) + .unzip + val newCtor = impl.transformBlock(companion.ctor)(using new HashMap())(_ => End()) + val newCompanion = companion.copy(methods = companion.methods ++ stagedMethods, ctor = newCtor) + val newModule = c.copy(sym = sym, companion = S(newCompanion)) + // debug is printed after definition + val debugBlock = debugPrintCode.foldRight(rest)(concat) + Define(newModule, debugBlock) case b => b From e40a1e6ecba141d031769931ed42c16676986fed Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 23 Dec 2025 00:09:04 +0800 Subject: [PATCH 218/268] formatting use no ident after match, like in Lowering.scala --- .../scala/hkmc2/codegen/Instrumentation.scala | 194 +++++++++--------- 1 file changed, 98 insertions(+), 96 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 29c42ad81a..5eb74dd29b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -24,16 +24,16 @@ class InstrumentationImpl(using State): def asArg(x: ArgWrappable): Arg = x match - case p: Path => p.asArg - case l: Symbol => l.asPath.asArg + case p: Path => p.asArg + case l: Symbol => l.asPath.asArg // null and undefined are missing def toValue(lit: Str | Int | BigDecimal | Bool): Value = val l = lit match - case i: Int => Tree.IntLit(i) - case b: Bool => Tree.BoolLit(b) - case s: Str => Tree.StrLit(s) - case n: BigDecimal => Tree.DecLit(n) + case i: Int => Tree.IntLit(i) + case b: Bool => Tree.BoolLit(b) + case s: Str => Tree.StrLit(s) + case n: BigDecimal => Tree.DecLit(n) Value.Lit(l) extension [A, B](ls: Ls[(A => B) => B]) @@ -91,17 +91,17 @@ class InstrumentationImpl(using State): def transformSymbol(sym: Symbol, symName: Str = "sym")(k: Path => Block): Block = sym match - case clsSym: ClassSymbol => - transformParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => - blockCtor("ClassSymbol", Ls(toValue(sym.nme), paramsOpt), symName)(k) - case t: TermSymbol if t.defn.exists(_.sym.asCls.isDefined) => - transformSymbol(t.defn.get.sym.asCls.get, symName)(k) - case _ => blockCtor("Symbol", Ls(toValue(sym.nme)), symName)(k) + case clsSym: ClassSymbol => + transformParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => + blockCtor("ClassSymbol", Ls(toValue(sym.nme), paramsOpt), symName)(k) + case t: TermSymbol if t.defn.exists(_.sym.asCls.isDefined) => + transformSymbol(t.defn.get.sym.asCls.get, symName)(k) + case _ => blockCtor("Symbol", Ls(toValue(sym.nme)), symName)(k) def transformOption[A](xOpt: Opt[A], f: A => (Path => Block) => Block)(k: Path => Block): Block = xOpt match - case S(x) => f(x)(optionSome(_)(k)) - case N => optionNone()(k) + case S(x) => f(x)(optionSome(_)(k)) + case N => optionNone()(k) // instrumentation rules @@ -121,7 +121,8 @@ class InstrumentationImpl(using State): tuple(arms): arms => ruleEnd(): e => // TODO: use transformOption here - def dfltStaged(k: (Path, Context) => Block) = dflt match + def dfltStaged(k: (Path, Context) => Block) = + dflt match case S(dflt) => transformBlock(dflt)(using ctx.clone() += p -> x): (dflt, ctx) => optionSome(dflt)(k(_, ctx.clone() -= p)) @@ -135,42 +136,42 @@ class InstrumentationImpl(using State): // rulePath ctx.get(p).map(k).getOrElse: p match - case Value.Ref(l, disamb) => - // not in formalization - transformSymbol(disamb.getOrElse(l)): sym => - blockCtor("ValueRef", Ls(sym), "var")(k) - case l: Value.Lit => - blockCtor("ValueLit", Ls(l), "lit")(k) - case Select(p, i @ Tree.Ident(name)) => - transformPath(p): x => - blockCtor("Symbol", Ls(toValue(name))): name => - blockCtor("Select", Ls(x, name), "sel")(k) - case DynSelect(qual, fld, arrayIdx) => - transformPath(qual): x => - transformPath(fld): y => - blockCtor("DynSelect", Ls(x, y, toValue(arrayIdx)), "dynsel")(k) - case _ => ??? // not supported + case Value.Ref(l, disamb) => + // not in formalization + transformSymbol(disamb.getOrElse(l)): sym => + blockCtor("ValueRef", Ls(sym), "var")(k) + case l: Value.Lit => + blockCtor("ValueLit", Ls(l), "lit")(k) + case Select(p, i @ Tree.Ident(name)) => + transformPath(p): x => + blockCtor("Symbol", Ls(toValue(name))): name => + blockCtor("Select", Ls(x, name), "sel")(k) + case DynSelect(qual, fld, arrayIdx) => + transformPath(qual): x => + transformPath(fld): y => + blockCtor("DynSelect", Ls(x, y, toValue(arrayIdx)), "dynsel")(k) + case _ => ??? // not supported def transformResult(r: Result)(using Context)(k: Path => Block): Block = r match - case p: Path => transformPath(p)(k) - case Tuple(mut, elems) => - assert(!mut, "mutable tuple not supported") - transformArgs(elems): xs => + case p: Path => transformPath(p)(k) + case Tuple(mut, elems) => + assert(!mut, "mutable tuple not supported") + transformArgs(elems): xs => + tuple(xs.map(_._1)): codes => + blockCtor("Tuple", Ls(codes), "tup")(k) + case Instantiate(mut, cls, args) => + assert(!mut, "mutable instantiation not supported") + transformArgs(args): xs => + transformPath(cls): cls => tuple(xs.map(_._1)): codes => - blockCtor("Tuple", Ls(codes), "tup")(k) - case Instantiate(mut, cls, args) => - assert(!mut, "mutable instantiation not supported") - transformArgs(args): xs => - transformPath(cls): cls => - tuple(xs.map(_._1)): codes => - blockCtor("Instantiate", Ls(cls, codes), "inst")(k) - case Call(fun, args) => - transformPath(fun): fun => - transformArgs(args): args => - tuple(args.map(_._1)): tup => - blockCtor("Call", Ls(fun, tup), "app")(k) - case _ => ??? // not supported + blockCtor("Instantiate", Ls(cls, codes), "inst")(k) + case Call(fun, args) => + transformPath(fun): fun => + transformArgs(args): args => + tuple(args.map(_._1)): tup => + blockCtor("Call", Ls(fun, tup), "app")(k) + case _ => ??? // not supported def transformArg(a: Arg)(using Context)(k: ((Path, Bool)) => Block): Block = val Arg(spread, value) = a @@ -190,13 +191,13 @@ class InstrumentationImpl(using State): def transformCase(cse: Case)(using Context)(k: Path => Block): Block = cse match - case Case.Lit(lit) => blockCtor("Lit", Ls(Value.Lit(lit)))(k) - case Case.Cls(cls, path) => - transformSymbol(cls): cls => - transformPath(path): path => - blockCtor("Cls", Ls(cls, path))(k) - case Case.Tup(len, inf) => blockCtor("Tup", Ls(len, inf).map(toValue))(k) - case Case.Field(name, safe) => ??? // not supported + case Case.Lit(lit) => blockCtor("Lit", Ls(Value.Lit(lit)))(k) + case Case.Cls(cls, path) => + transformSymbol(cls): cls => + transformPath(path): path => + blockCtor("Cls", Ls(cls, path))(k) + case Case.Tup(len, inf) => blockCtor("Tup", Ls(len, inf).map(toValue))(k) + case Case.Field(name, safe) => ??? // not supported // ruleBlk? def transformBlock(b: Block)(using Context)(k: Path => Block): Block = @@ -204,47 +205,47 @@ class InstrumentationImpl(using State): def transformBlock(b: Block)(using ctx: Context)(k: (Path, Context) => Block): Block = b match - case Return(res, implct) => - transformResult(res): x => - blockCtor("Return", Ls(x, toValue(implct)), "return")(k(_, ctx)) - case Assign(x, r, b) => - transformResult(r): y => - transformSymbol(x): xSym => - blockCtor("ValueRef", Ls(xSym)): xStaged => - // x should always be defined, either as an argument to the function or in a Scope Block - assert(ctx.get(x.asPath).isDefined) - (Assign(x, xStaged, _)): - given Context = ctx.clone() += x.asPath -> xStaged - transformBlock(b): (z, ctx) => - blockCtor("Assign", Ls(xSym, y, z), "assign")(k(_, ctx)) - case Define(cls: ClsLikeDefn, rest) => - assert(cls.companion.isEmpty, "nested module not supported") - (Define(cls, _)): - transformBlock(rest): p => - transformParamsOpt(cls.paramsOpt): paramsOpt => - transformSymbol(cls.isym): c => - optionNone(): none => // TODO: handle companion object - blockCtor("ClsLikeDefn", Ls(c, none)): cls => - blockCtor("Define", Ls(cls, p)): p => - ruleEnd(): end => - fnPrintCode(p)(k(end, summon)) - case End(_) => ruleEnd()(k(_, summon)) - case Match(p, ks, dflt, rest) => - transformPath(p): x => - ruleBranches(x, p, ks, dflt): (stagedMatch, ctx1) => - transformBlock(rest)(using ctx1): (z, ctx2) => - fnConcat(stagedMatch, z, "match"): cde => - k(cde, ctx2) - case Begin(sub, rest) => - // TODO: This is untested as there is no test case that generates the Begin block yet - transformBlock(sub): (sub, ctx) => - transformBlock(rest)(using ctx): (rest, ctx) => - fnConcat(sub, rest)(k(_, ctx)) - case Scoped(syms, body) => - blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undef => - val newCtx = ctx.clone() ++ syms.map(_.asPath -> undef) - transformBlock(body)(using newCtx)(k) - case _ => ??? // not supported + case Return(res, implct) => + transformResult(res): x => + blockCtor("Return", Ls(x, toValue(implct)), "return")(k(_, ctx)) + case Assign(x, r, b) => + transformResult(r): y => + transformSymbol(x): xSym => + blockCtor("ValueRef", Ls(xSym)): xStaged => + // x should always be defined, either as an argument to the function or in a Scope Block + assert(ctx.get(x.asPath).isDefined) + (Assign(x, xStaged, _)): + given Context = ctx.clone() += x.asPath -> xStaged + transformBlock(b): (z, ctx) => + blockCtor("Assign", Ls(xSym, y, z), "assign")(k(_, ctx)) + case Define(cls: ClsLikeDefn, rest) => + assert(cls.companion.isEmpty, "nested module not supported") + (Define(cls, _)): + transformBlock(rest): p => + transformParamsOpt(cls.paramsOpt): paramsOpt => + transformSymbol(cls.isym): c => + optionNone(): none => // TODO: handle companion object + blockCtor("ClsLikeDefn", Ls(c, none)): cls => + blockCtor("Define", Ls(cls, p)): p => + ruleEnd(): end => + fnPrintCode(p)(k(end, summon)) + case End(_) => ruleEnd()(k(_, summon)) + case Match(p, ks, dflt, rest) => + transformPath(p): x => + ruleBranches(x, p, ks, dflt): (stagedMatch, ctx1) => + transformBlock(rest)(using ctx1): (z, ctx2) => + fnConcat(stagedMatch, z, "match"): cde => + k(cde, ctx2) + case Begin(sub, rest) => + // TODO: This is untested as there is no test case that generates the Begin block yet + transformBlock(sub): (sub, ctx) => + transformBlock(rest)(using ctx): (rest, ctx) => + fnConcat(sub, rest)(k(_, ctx)) + case Scoped(syms, body) => + blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undef => + val newCtx = ctx.clone() ++ syms.map(_.asPath -> undef) + transformBlock(body)(using newCtx)(k) + case _ => ??? // not supported // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function // so we pass modSym instead @@ -279,7 +280,8 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): case _ => ??? } - override def applyBlock(b: Block): Block = super.applyBlock(b) match + override def applyBlock(b: Block): Block = + super.applyBlock(b) match // find modules with staged annotation case Define(c: ClsLikeDefn, rest) if c.companion.exists(_.isym.defn.exists(_.hasStagedModifier.isDefined)) => val sym = c.sym.subst From 69a142fb143a77283d247fca3f890388c730f6a2 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 23 Dec 2025 00:27:17 +0800 Subject: [PATCH 219/268] formatting --- hkmc2/shared/src/test/mlscript/staging/Functions.mls | 6 +++--- hkmc2/shared/src/test/mlscript/staging/Syntax.mls | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index 509fa8423f..f4ed7210d5 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -4,7 +4,7 @@ val x = [1, 2, 3] staged module Expressions with fun lit() = 1 - fun assign() = + fun assign() = let x = 42 let y = x y @@ -37,8 +37,8 @@ staged module Expressions with :staging :fixme staged module OtherBlocks with - fun breakAndLabel() = - if 1 is + fun breakAndLabel() = + if 1 is 2 then 0 3 then 0 else 0 diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls index e5c4b86216..0eaa38428e 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Syntax.mls @@ -1,7 +1,5 @@ :pt -:js -// :lot staged module A //│ Parsed tree: //│ Modified: @@ -22,4 +20,4 @@ staged fun f() = 0 :slot staged module A //│ Pretty Lowered: -//│ define staged class A in set block$res1 = undefined in end +//│ define staged class A in set block$res = undefined in end From 6b012b2afdf4db5b06b228a69012b6dccec1ba1a Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 23 Dec 2025 00:15:46 +0800 Subject: [PATCH 220/268] remove Shape{Map, Set} definitions the definitions should utilize CachedHash before getting merged --- .../scala/hkmc2/semantics/Elaborator.scala | 1 - .../src/test/mlscript-compile/ShapeMap.mls | 19 ---- .../src/test/mlscript-compile/ShapeSet.mls | 89 ------------------- .../test/scala/hkmc2/JSBackendDiffMaker.scala | 2 - .../src/test/scala/hkmc2/MLsDiffMaker.scala | 5 +- 5 files changed, 1 insertion(+), 115 deletions(-) delete mode 100644 hkmc2/shared/src/test/mlscript-compile/ShapeMap.mls delete mode 100644 hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index aecf080a45..bc112f9e36 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -252,7 +252,6 @@ object Elaborator: val prettyPrintSymbol = TempSymbol(N, "prettyPrint") val termSymbol = TempSymbol(N, "Term") val blockSymbol = TempSymbol(N, "Block") - val shapeSetSymbol = TempSymbol(N, "shapeSet") val optionSymbol = TempSymbol(N, "option") val wasmSymbol = TempSymbol(N, "wasm") val effectSigSymbol = ClassSymbol(DummyTypeDef(syntax.Cls), Ident("EffectSig")) diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeMap.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeMap.mls deleted file mode 100644 index 6b73d8f826..0000000000 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeMap.mls +++ /dev/null @@ -1,19 +0,0 @@ -import "./Option.mls" -import "./ShapeSet.mls" - -open Option { Some, None } -open ShapeSet - -type ShapeMap = ShapeMap.ShapeMap - -module ShapeMap with... - -fun hash(s: ShapeSet) = s.keys().join(", ") - -class ShapeMap(val underlying: Map) with - fun add(s: ShapeSet, code) = underlying.set(hash(s), code) - - fun get(s: ShapeSet) = - if underlying.get(hash(s)) - == () then None - is value then Some of value diff --git a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls b/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls deleted file mode 100644 index 89b0554d89..0000000000 --- a/hkmc2/shared/src/test/mlscript-compile/ShapeSet.mls +++ /dev/null @@ -1,89 +0,0 @@ -import "./Predef.mls" -import "./Block.mls" -import "./Shape.mls" - -open Predef -open Block { ClassSymbol } -open Shape { show } - -type ShapeSet = ShapeSet.ShapeSet - -module ShapeSet with... - -// FIXME: hash is based on uniqueness of pretty printing -fun hash(s: Shape) = show(s) - -fun printShapeSet(s: ShapeSet) = console.log([... s.keys()].join(", ")) - -class ShapeSet(val underlying: Map) with - fun keys() = [...underlying.keys()].toSorted() - - fun values() = underlying.values().toArray() - - fun isEmpty() = underlying.size == 0 - - fun contains(s: Shape) = underlying.has(hash(s)) - - fun flatMap(f) = liftMany(values().flatMap(f)) - -fun create() = ShapeSet(new Map) - -fun lift(s: Shape) = ShapeSet(new Map([[hash(s), s]])) - -fun liftMany(arr: Array[Shape]) = ShapeSet(new Map(arr.map(s => [hash(s), s]))) - -// combining ShapeSet - -fun union(s1: ShapeSet, s2: ShapeSet) = ShapeSet(new Map([...s1.underlying, ...s2.underlying])) - -fun flat(arr: Array[ShapeSet]) = ShapeSet(new Map(arr.map(_.underlying.entries().toArray()).flat())) - -// Cartesian product: https://stackoverflow.com/a/43053803 -fun prod(xs) = - if xs.length == - 0 then [[]] - 1 then xs - else xs.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat()))) - -open Shape { Dyn, Lit, Arr, Class } - -// lifted constructors - -fun mkBot() = create() - -fun mkDyn() = lift(Dyn()) - -fun mkLit(l) = lift(Lit(l)) - -fun mkArr(shapes: Array[ShapeSet], inf: Bool) = - shapes - .map(_.underlying.values().toArray()) - |> prod - .map(x => Arr(x, inf)) - |> liftMany - -fun mkClass(sym: ClassSymbol, params: Array[ShapeSet]) = - params.map(_.underlying.values().toArray()) - |> prod - .map(Class(sym, _)) - |> liftMany - -// helper functions - -fun filter(s: ShapeSet, p: Block.Case) = s.flatMap(Shape.filter(_, p)) - -fun rest(s: ShapeSet, p: Block.Case) = s.flatMap(Shape.rest(_, p)) - -fun sel(s1: ShapeSet, s2: ShapeSet) = - prod([s1.values(), s2.values()]) - .flatMap(pair => Shape.sel(pair.0, pair.1)) - |> liftMany - -fun mrg(s1: ShapeSet, s2: ShapeSet) = - mkDyn() // TODO - -open Block { Block } - -fun pruneBadArms(arms: Array[[ShapeSet, Block]]) = - val rem = arms.filter(arm => not (arm.0.isEmpty() and arm.1 is End)) - [flat(rem.map(_.0)), rem.map(_.1)] diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala index 1cc525c074..48ab073eec 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala @@ -34,7 +34,6 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: val termNme = baseScp.allocateName(Elaborator.State.termSymbol) val blockNme = baseScp.allocateName(Elaborator.State.blockSymbol) val optionNme = baseScp.allocateName(Elaborator.State.optionSymbol) - val shapeSetNme = baseScp.allocateName(Elaborator.State.shapeSetSymbol) val definitionMetadataNme = baseScp.allocateName(Elaborator.State.definitionMetadataSymbol) val prettyPrintNme = baseScp.allocateName(Elaborator.State.prettyPrintSymbol) @@ -63,7 +62,6 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: if stageCode.isSet then importRuntimeModule(blockNme, blockFile) importRuntimeModule(optionNme, optionFile) - importRuntimeModule(shapeSetNme, shapeSetFile) h private var hostCreated = false diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index c0c2719116..fabecacb6e 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -22,7 +22,6 @@ abstract class MLsDiffMaker extends DiffMaker: val termFile: io.Path = predefFile.up / "Term.mjs" // * Contains MLscript runtime term definitions val blockFile: io.Path = predefFile.up / "Block.mjs" // * Contains MLscript runtime block definitions val optionFile: io.Path = predefFile.up / "Option.mjs" // * Contains MLscipt runtime option definition - val shapeSetFile: io.Path = predefFile.up / "ShapeSet.mjs" // * Contains MLscript runtime shapeset definitions val wd = file.up @@ -168,9 +167,7 @@ abstract class MLsDiffMaker extends DiffMaker: if stageCode.isSet then given Config = mkConfig processTrees( - PrefixApp(Keywrd(`import`), StrLit(blockFile.toString)) - :: PrefixApp(Keywrd(`import`), StrLit(shapeSetFile.toString)) - :: Nil) + PrefixApp(Keywrd(`import`), StrLit(blockFile.toString)) :: Nil) super.init() From 51e5513cf847056854db066ac77980ac44b12f0d Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 23 Dec 2025 13:59:07 +0800 Subject: [PATCH 221/268] formatting --- .../scala/hkmc2/codegen/Instrumentation.scala | 28 ++++++++----------- .../src/test/mlscript/staging/Functions.mls | 22 +++++++-------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 5eb74dd29b..96929e354c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -137,7 +137,6 @@ class InstrumentationImpl(using State): ctx.get(p).map(k).getOrElse: p match case Value.Ref(l, disamb) => - // not in formalization transformSymbol(disamb.getOrElse(l)): sym => blockCtor("ValueRef", Ls(sym), "var")(k) case l: Value.Lit => @@ -212,8 +211,7 @@ class InstrumentationImpl(using State): transformResult(r): y => transformSymbol(x): xSym => blockCtor("ValueRef", Ls(xSym)): xStaged => - // x should always be defined, either as an argument to the function or in a Scope Block - assert(ctx.get(x.asPath).isDefined) + assert(ctx.get(x.asPath).isDefined, "x should always be defined, either as an argument to the function or in a Scope Block") (Assign(x, xStaged, _)): given Context = ctx.clone() += x.asPath -> xStaged transformBlock(b): (z, ctx) => @@ -228,14 +226,13 @@ class InstrumentationImpl(using State): blockCtor("ClsLikeDefn", Ls(c, none)): cls => blockCtor("Define", Ls(cls, p)): p => ruleEnd(): end => - fnPrintCode(p)(k(end, summon)) - case End(_) => ruleEnd()(k(_, summon)) + fnPrintCode(p)(k(end, ctx)) + case End(_) => ruleEnd()(k(_, ctx)) case Match(p, ks, dflt, rest) => transformPath(p): x => - ruleBranches(x, p, ks, dflt): (stagedMatch, ctx1) => - transformBlock(rest)(using ctx1): (z, ctx2) => - fnConcat(stagedMatch, z, "match"): cde => - k(cde, ctx2) + ruleBranches(x, p, ks, dflt): (stagedMatch, ctx) => + transformBlock(rest)(using ctx): (z, ctx) => + fnConcat(stagedMatch, z, "match")(k(_, ctx)) case Begin(sub, rest) => // TODO: This is untested as there is no test case that generates the Begin block yet transformBlock(sub): (sub, ctx) => @@ -255,18 +252,15 @@ class InstrumentationImpl(using State): // NOTE: this debug printing only works for top-level modules, nested modules don't work // TODO: remove it. only for test val debug = blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undef => - // TODO: put correct parameters instead of End - val argsList = f.params.map(ps => List.fill(ps.params.length)(undef)) - def makeCalls(k: Path => Block) = - argsList.foldRight(k)((args, cont) => res => call(res, args)(cont))(sym) - makeCalls(fnPrintCode(_)(End())) + // TODO: put correct parameters instead of undefined + f.params.map(ps => List.fill(ps.params.length)(undef)) + .foldRight((p: Path) => fnPrintCode(p)(End()))((args, cont) => call(_, args)(cont))(sym) val dSym = TermSymbol(f.dSym.k, f.dSym.owner, Tree.Ident(f.sym.nme + "_gen")) val args = f.params.flatMap(_.params).map(_.sym) val newBody = - ruleEnd(): end => - given Context = HashMap(args.map(s => Value.Ref(s, N) -> Value.Ref(s, N))*) - transformBlock(f.body)(p => Return(p, false)) + given Context = HashMap(args.map(s => Value.Ref(s, N) -> Value.Ref(s, N))*) + transformBlock(f.body)(Return(_, false)) val newFun = f.copy(sym = genSym, dSym = dSym, body = newBody)(false) (newFun, debug) diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index f4ed7210d5..ad6489669a 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -33,17 +33,6 @@ staged module Expressions with //│ > Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Return(Lit(1), false), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Return(Lit(3), false))))], Return(Lit(0), false), End)) //│ x = [1, 2, 3] -:js -:staging -:fixme -staged module OtherBlocks with - fun breakAndLabel() = - if 1 is - 2 then 0 - 3 then 0 - else 0 -//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing - :js :staging class Outside(a) @@ -71,6 +60,17 @@ staged module Arguments with //│ > Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)) //│ > Return(Lit(undefined), false) +:js +:staging +:fixme +staged module OtherBlocks with + fun breakAndLabel() = + if 1 is + 2 then 0 + 3 then 0 + else 0 +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + // debug printing fails, collision with class name? :js :staging From 0cc778e4e8202dcdcdf87089c26ab32deb69dba0 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 23 Dec 2025 13:59:42 +0800 Subject: [PATCH 222/268] imrpove symbol information for select --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 10 +++++++--- hkmc2/shared/src/test/mlscript/staging/Functions.mls | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 96929e354c..62eae97d3b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -141,10 +141,14 @@ class InstrumentationImpl(using State): blockCtor("ValueRef", Ls(sym), "var")(k) case l: Value.Lit => blockCtor("ValueLit", Ls(l), "lit")(k) - case Select(p, i @ Tree.Ident(name)) => + case s @ Select(p, i @ Tree.Ident(name)) => transformPath(p): x => - blockCtor("Symbol", Ls(toValue(name))): name => - blockCtor("Select", Ls(x, name), "sel")(k) + val sym = + if s.symbol.isDefined + then transformSymbol(s.symbol.get) + else blockCtor("Symbol", Ls(toValue(name))) + sym: sym => + blockCtor("Select", Ls(x, sym), "sel")(k) case DynSelect(qual, fld, arrayIdx) => transformPath(qual): x => transformPath(fld): y => diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/staging/Functions.mls index ad6489669a..09b8182eaa 100644 --- a/hkmc2/shared/src/test/mlscript/staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/staging/Functions.mls @@ -46,9 +46,9 @@ staged module ClassInstrumentation with //│ > Define(ClsLikeDefn(ClassSymbol("NoArg"), TODO), End) //│ > Define(ClsLikeDefn(ClassSymbol("Inside":[Symbol("a"), Symbol("b")]), TODO), End) //│ > Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) -//│ > Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), Symbol("NoArg")), []), false) +//│ > Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("NoArg")), []), false) //│ > Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) -//│ > Return(Call(Select(Ref(Symbol("ClassInstrumentation")), Symbol("Inside")), [Lit(1), Lit(2)]), false) +//│ > Return(Call(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("Inside":[Symbol("a"), Symbol("b")])), [Lit(1), Lit(2)]), false) :js :staging From e3f052ba8da050415111f7a075d7f430d0b1d24c Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 23 Dec 2025 14:19:37 +0800 Subject: [PATCH 223/268] simplify applyRuleBranch since the shape is not inferred, each branch can use the same x to compute its branch --- .../scala/hkmc2/codegen/Instrumentation.scala | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 62eae97d3b..874683bdc0 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -109,26 +109,26 @@ class InstrumentationImpl(using State): blockCtor("End", Ls(), symName)(k) def ruleBranches(x: Path, p: Path, arms: Ls[Case -> Block], dflt: Opt[Block], symName: String = "branches")(using Context)(k: (Path, Context) => Block): Block = - def applyRuleBranch(cse: Case, block: Block)(f: Path => (Context, Path) => Block)(ctx: Context, x: Path): Block = + def applyRuleBranch(cse: Case, block: Block)(f: Path => Context => Block)(ctx: Context): Block = transformCase(cse): cse => transformBlock(block)(using ctx.clone() += p -> x): (y, ctx) => // TODO: use Arm type instead of Tup tuple(Ls(cse, y), "branch"): cde => - f(cde)(ctx.clone() -= p, x) - - val a = arms.map(applyRuleBranch).collectApply - ((f: (Ls[Path], Context) => Block) => a(ys => (ctx, _) => f(ys, ctx))(summon, x)): (arms, ctx) => - tuple(arms): arms => - ruleEnd(): e => - // TODO: use transformOption here - def dfltStaged(k: (Path, Context) => Block) = - dflt match - case S(dflt) => - transformBlock(dflt)(using ctx.clone() += p -> x): (dflt, ctx) => - optionSome(dflt)(k(_, ctx.clone() -= p)) - case N => optionNone()(k(_, ctx)) - dfltStaged: (dflt, ctx) => - blockCtor("Match", Ls(x, arms, dflt, e), symName)(k(_, ctx)) + f(cde)(ctx.clone() -= p) + + (arms.map(applyRuleBranch).collectApply(_: Ls[Path] => Context => Block)(summon)): arms => + ctx => + tuple(arms): arms => + ruleEnd(): e => + // TODO: use transformOption here + def dfltStaged(k: (Path, Context) => Block) = + dflt match + case S(dflt) => + transformBlock(dflt)(using ctx.clone() += p -> x): (dflt, ctx) => + optionSome(dflt)(k(_, ctx.clone() -= p)) + case N => optionNone()(k(_, ctx)) + dfltStaged: (dflt, ctx) => + blockCtor("Match", Ls(x, arms, dflt, e), symName)(k(_, ctx)) // transformations of Block From ed36c03fa8045f38570de99e54a69ebb7280a2e6 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 23 Dec 2025 14:24:30 +0800 Subject: [PATCH 224/268] import option file during MLsDiffMaker init --- hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index fabecacb6e..f267de7a87 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -167,7 +167,9 @@ abstract class MLsDiffMaker extends DiffMaker: if stageCode.isSet then given Config = mkConfig processTrees( - PrefixApp(Keywrd(`import`), StrLit(blockFile.toString)) :: Nil) + PrefixApp(Keywrd(`import`), StrLit(blockFile.toString)) + :: PrefixApp(Keywrd(`import`), StrLit(optionFile.toString)) + :: Nil) super.init() From b18776f7144466b67398ec51be546bfdd55e8ba0 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 23 Dec 2025 20:40:46 +0800 Subject: [PATCH 225/268] remove import statement for option in MLsDiffMaker --- hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index f267de7a87..fabecacb6e 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -167,9 +167,7 @@ abstract class MLsDiffMaker extends DiffMaker: if stageCode.isSet then given Config = mkConfig processTrees( - PrefixApp(Keywrd(`import`), StrLit(blockFile.toString)) - :: PrefixApp(Keywrd(`import`), StrLit(optionFile.toString)) - :: Nil) + PrefixApp(Keywrd(`import`), StrLit(blockFile.toString)) :: Nil) super.init() From 3df66e254e70c35cdc5f15b95fcfb9e8e8f7b8b3 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 24 Dec 2025 15:40:26 +0800 Subject: [PATCH 226/268] fixup! remove import statement for option in MLsDiffMaker --- hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala index fabecacb6e..ecbf1e74d0 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/MLsDiffMaker.scala @@ -164,10 +164,6 @@ abstract class MLsDiffMaker extends DiffMaker: given Config = mkConfig processTrees( PrefixApp(Keywrd(`import`), StrLit(termFile.toString)) :: Nil) - if stageCode.isSet then - given Config = mkConfig - processTrees( - PrefixApp(Keywrd(`import`), StrLit(blockFile.toString)) :: Nil) super.init() From 9212c53da6b981c8d85435df132445a0b5ce4e11 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 24 Dec 2025 15:38:09 +0800 Subject: [PATCH 227/268] include staging tests in diff tests renaming mlsript/staging to mlscript/block-staging avoids DiffTestRunner excluding the test files using the filter intended to exlude ucs/staging --- .../{staging => block-staging}/Functions.mls | 0 .../test/mlscript/block-staging/PrintCode.mls | 8 ++++ .../{staging => block-staging}/Syntax.mls | 0 .../src/test/mlscript/staging/PrintCode.mls | 38 ------------------- 4 files changed, 8 insertions(+), 38 deletions(-) rename hkmc2/shared/src/test/mlscript/{staging => block-staging}/Functions.mls (100%) create mode 100644 hkmc2/shared/src/test/mlscript/block-staging/PrintCode.mls rename hkmc2/shared/src/test/mlscript/{staging => block-staging}/Syntax.mls (100%) delete mode 100644 hkmc2/shared/src/test/mlscript/staging/PrintCode.mls diff --git a/hkmc2/shared/src/test/mlscript/staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls similarity index 100% rename from hkmc2/shared/src/test/mlscript/staging/Functions.mls rename to hkmc2/shared/src/test/mlscript/block-staging/Functions.mls diff --git a/hkmc2/shared/src/test/mlscript/block-staging/PrintCode.mls b/hkmc2/shared/src/test/mlscript/block-staging/PrintCode.mls new file mode 100644 index 0000000000..bff7052850 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/block-staging/PrintCode.mls @@ -0,0 +1,8 @@ +:staging +:js + +import "../../mlscript-compile/Block.mls" + +Block.printCode(Block.FunDefn(Block.Symbol("f"), [[Block.Symbol("x")]], Block.Return(Block.ValueLit(1), false), false)) +//│ > FunDefn(Symbol("f"), ([Symbol("x")]), Return(Lit(1), false), false) + diff --git a/hkmc2/shared/src/test/mlscript/staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls similarity index 100% rename from hkmc2/shared/src/test/mlscript/staging/Syntax.mls rename to hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls diff --git a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls b/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls deleted file mode 100644 index aac4722e59..0000000000 --- a/hkmc2/shared/src/test/mlscript/staging/PrintCode.mls +++ /dev/null @@ -1,38 +0,0 @@ -:staging -:js - -//│ Block = class Block { -//│ Symbol: fun Symbol { class: class Symbol }, -//│ ClassSymbol: fun ClassSymbol { class: class ClassSymbol }, -//│ Arg: fun Arg { class: class Arg }, -//│ Case: class Case, -//│ Lit: fun Lit { class: class Lit }, -//│ Cls: fun Cls { class: class Cls }, -//│ Tup: fun Tup { class: class Tup }, -//│ Result: class Result, -//│ Call: fun Call { class: class Call }, -//│ Instantiate: fun Instantiate { class: class Instantiate }, -//│ Tuple: fun Tuple { class: class Tuple }, -//│ Path: class Path, -//│ Select: fun Select { class: class Select }, -//│ DynSelect: fun DynSelect { class: class DynSelect }, -//│ ValueRef: fun ValueRef { class: class ValueRef }, -//│ ValueLit: fun ValueLit { class: class ValueLit }, -//│ Defn: class Defn, -//│ ValDefn: fun ValDefn { class: class ValDefn }, -//│ ClsLikeDefn: fun ClsLikeDefn { class: class ClsLikeDefn }, -//│ FunDefn: fun FunDefn { class: class FunDefn }, -//│ ClsLikeBody: fun ClsLikeBody { class: class ClsLikeBody }, -//│ Block: class Block, -//│ Match: fun Match { class: class Match }, -//│ Return: fun Return { class: class Return }, -//│ Assign: fun Assign { class: class Assign }, -//│ Define: fun Define { class: class Define }, -//│ End: fun End { class: class End } -//│ } -//│ ShapeSet = class ShapeSet { ShapeSet: fun ShapeSet { class: class ShapeSet } } - -Block.printCode(Block.FunDefn(Block.Symbol("f"), [[Block.Symbol("x")]], Block.Return(Block.ValueLit(1), false))) -//│ > [ Symbol { name: 'x' } ] -//│ > FunDefn(Symbol("f"), ([Symbol("x")]), Return(Lit(1), false), undefined) - From 9f2ca5039bb6de6edb1d8057e38cf7e76bbf62dc Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 24 Dec 2025 16:00:37 +0800 Subject: [PATCH 228/268] remove redundant codegen --- .../main/scala/hkmc2/codegen/Instrumentation.scala | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 874683bdc0..9f9d19e638 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -224,13 +224,12 @@ class InstrumentationImpl(using State): assert(cls.companion.isEmpty, "nested module not supported") (Define(cls, _)): transformBlock(rest): p => - transformParamsOpt(cls.paramsOpt): paramsOpt => - transformSymbol(cls.isym): c => - optionNone(): none => // TODO: handle companion object - blockCtor("ClsLikeDefn", Ls(c, none)): cls => - blockCtor("Define", Ls(cls, p)): p => - ruleEnd(): end => - fnPrintCode(p)(k(end, ctx)) + transformSymbol(cls.isym): c => + optionNone(): none => // TODO: handle companion object + blockCtor("ClsLikeDefn", Ls(c, none)): cls => + blockCtor("Define", Ls(cls, p)): p => + ruleEnd(): end => + fnPrintCode(p)(k(end, ctx)) case End(_) => ruleEnd()(k(_, ctx)) case Match(p, ks, dflt, rest) => transformPath(p): x => From 7da3eeafec78701a76def081d43c04eb4a1ba287 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 8 Jan 2026 22:33:16 +0800 Subject: [PATCH 229/268] add Block symbol following pr #375 --- hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index 7b827fdbb1..4329b17945 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -310,6 +310,7 @@ object Elaborator: def init(using State): Ctx = Ctx.empty.copy(env = Map( "globalThis" -> globalThisSymbol, "Term" -> termSymbol, + "Block" -> blockSymbol, )) def dbg: Bool = false def dbgRefNum(num: Int): Str = From 7e115d7a48938a52a760025cb4c695e380eb5808 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 8 Jan 2026 22:37:02 +0800 Subject: [PATCH 230/268] formatting --- .../test/mlscript/block-staging/Functions.mls | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 09b8182eaa..bf108a1224 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -1,6 +1,6 @@ - :js :staging + val x = [1, 2, 3] staged module Expressions with fun lit() = 1 @@ -33,8 +33,6 @@ staged module Expressions with //│ > Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Return(Lit(1), false), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Return(Lit(3), false))))], Return(Lit(0), false), End)) //│ x = [1, 2, 3] -:js -:staging class Outside(a) staged module ClassInstrumentation with class Inside(a, b) @@ -50,8 +48,6 @@ staged module ClassInstrumentation with //│ > Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) //│ > Return(Call(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("Inside":[Symbol("a"), Symbol("b")])), [Lit(1), Lit(2)]), false) -:js -:staging staged module Arguments with fun f(x) = x = 1 @@ -60,8 +56,6 @@ staged module Arguments with //│ > Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)) //│ > Return(Lit(undefined), false) -:js -:staging :fixme staged module OtherBlocks with fun breakAndLabel() = @@ -72,8 +66,6 @@ staged module OtherBlocks with //│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing // debug printing fails, collision with class name? -:js -:staging :fixme class A() staged module A with @@ -81,16 +73,14 @@ staged module A with //│ ═══[RUNTIME ERROR] TypeError: A1.f_gen is not a function // debug printing fails, unable to reference the class when calling the instrumented function -:js -:staging :fixme module A with staged module B with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.88: staged module B with +//│ ║ l.78: staged module B with //│ ║ ^^^^^^ -//│ ║ l.89: fun f() = 1 +//│ ║ l.79: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From 9bcdf991eab6e118c6bdc27e21e09fbcfd4b44c9 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 8 Jan 2026 23:50:55 +0800 Subject: [PATCH 231/268] add Scoped, Loop, Break nodes to Block IR this removes the check in L218 because evaluation of Scope is now deferred:wq --- .../scala/hkmc2/codegen/Instrumentation.scala | 16 +++++++++---- .../src/test/mlscript-compile/Block.mls | 13 +++++++++++ .../test/mlscript/block-staging/Functions.mls | 23 +++++++++++-------- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 9f9d19e638..5b6c699d9b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -215,7 +215,6 @@ class InstrumentationImpl(using State): transformResult(r): y => transformSymbol(x): xSym => blockCtor("ValueRef", Ls(xSym)): xStaged => - assert(ctx.get(x.asPath).isDefined, "x should always be defined, either as an argument to the function or in a Scope Block") (Assign(x, xStaged, _)): given Context = ctx.clone() += x.asPath -> xStaged transformBlock(b): (z, ctx) => @@ -242,9 +241,18 @@ class InstrumentationImpl(using State): transformBlock(rest)(using ctx): (rest, ctx) => fnConcat(sub, rest)(k(_, ctx)) case Scoped(syms, body) => - blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undef => - val newCtx = ctx.clone() ++ syms.map(_.asPath -> undef) - transformBlock(body)(using newCtx)(k) + syms.toList.map(transformSymbol(_)).collectApply: symsStaged => + tuple(symsStaged): tup => + transformBlock(body): (body, ctx) => + blockCtor("Scoped", Ls(tup, body))(k(_, ctx)) + case Label(labelSymbol, loop, body, rest) => + transformSymbol(labelSymbol): labelSymbol => + transformBlock(body): (body, ctx) => + transformBlock(rest)(using ctx): (rest, ctx) => + blockCtor("Label", Ls(labelSymbol, toValue(loop), body, rest))(k(_, ctx)) + case Break(labelSymbol) => + transformSymbol(labelSymbol): labelSymbol => + blockCtor("Break", Ls(labelSymbol))(k(_, ctx)) case _ => ??? // not supported // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index d8ec8b1b3f..360f4723c9 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -56,6 +56,10 @@ class Block with Return(val res: Result, val implct: Bool) Assign(val lhs: Symbol, val rhs: Result, val rest: Block) Define(val defn: Defn, val rest: Block) + // TODO: [fyp] handle Scoped, Label, Break nodes + Scoped(val symbols: Array[Symbol], val rest: Block) + Label(val labelSymbol: Symbol, val loop: Bool, val body: Block, val rest: Block) + Break(val labelSymbol: Symbol) End() fun concat(b1: Block, b2: Block) = if b1 is @@ -63,6 +67,9 @@ fun concat(b1: Block, b2: Block) = if b1 is Return(res, implct) then b2 // discard return? Assign(lhs, rhs, rest) then Assign(lhs, rhs, concat(rest, b2)) Define(defn, rest) then Define(defn, concat(rest, b2)) + Scoped(symbols, rest) then Scoped(symbols, concat(rest, b2)) + Label(labelSymbol, loop, body, rest) then Label(labelSymbol, loop, body, concat(rest, b2)) + Break then ??? // unreachable End() then b2 fun showBool(b: Bool) = if b then "true" else "false" @@ -158,6 +165,12 @@ fun showBlock(b: Block): Str = "Assign(" + showSymbol(lhs) + ", " + showResult(rhs) + ", " + showBlock(rest) + ")" Define(defn, rest) then "Define(" + showDefn(defn) + ", " + showBlock(rest) + ")" + Scoped(symbols, rest) then + "Scoped([" + symbols.map(showSymbol).join(", ") + "], " + showBlock(rest) + ")" + Label(labelSymbol, loop, body, rest) then + "Label(" + showSymbol(labelSymbol) + ", " + showBool(loop) + ", " + showBlock(body) + ", " + showBlock(rest) + + ")" + Break(labelSymbol) then + "Break(" + showSymbol(labelSymbol) + ")" End() then "End" fun show(x) = diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index bf108a1224..37d277bf6f 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -21,16 +21,16 @@ staged module Expressions with fun match2() = if [...x] is [] then 1 - // [1, 2] then 2 // TODO: needs handling for Label, Break + [1, 2] then 2 [a, ...] then 3 else 0 //│ > Return(Lit(1), false) -//│ > Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false))) +//│ > Scoped([Symbol("x"), Symbol("y")], Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false)))) //│ > Return(Tuple([Lit(1), Lit(2)]), false) //│ > Return(Tuple([Lit(1), ..Ref(Symbol("x"))]), false) -//│ > Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false)) -//│ > Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End)) -//│ > Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Return(Lit(1), false), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Return(Lit(3), false))))], Return(Lit(0), false), End)) +//│ > Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false))) +//│ > Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))) +//│ > Scoped([Symbol("element0$"), Symbol("element1$"), Symbol("scrut"), Symbol("a"), Symbol("tmp"), Symbol("middleElements")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Label(Symbol("split_2$"), false, Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Assign(Symbol("tmp"), Lit(1), Break(Symbol("split_root$"))), Tup(2, false) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp"), Lit(2), Break(Symbol("split_root$")))], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End)], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End))), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$")))))], Break(Symbol("split_2$")), End)), Assign(Symbol("tmp"), Lit(0), Break(Symbol("split_root$")))NaN, Assign(Symbol("tmp"), Lit(3), End)NaN, Return(Ref(Symbol("tmp")), false)NaN) //│ x = [1, 2, 3] class Outside(a) @@ -56,14 +56,19 @@ staged module Arguments with //│ > Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)) //│ > Return(Lit(undefined), false) -:fixme staged module OtherBlocks with + fun scope() = + scope.locally of ( + let a = 1 + a + ) fun breakAndLabel() = if 1 is 2 then 0 3 then 0 else 0 -//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing +//│ > Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))) +//│ > Scoped([Symbol("scrut"), Symbol("tmp")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN) // debug printing fails, collision with class name? :fixme @@ -79,8 +84,8 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.78: staged module B with +//│ ║ l.83: staged module B with //│ ║ ^^^^^^ -//│ ║ l.79: fun f() = 1 +//│ ║ l.84: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From b16fdf488bbef3af20d919adf5ad36f154a72292 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 14 Jan 2026 15:51:31 +0800 Subject: [PATCH 232/268] replace parameters of functions with its symbol instead of undefined --- .../scala/hkmc2/codegen/Instrumentation.scala | 18 ++++++++++++++---- .../test/mlscript/block-staging/Functions.mls | 4 ++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 5b6c699d9b..caa305454f 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -262,10 +262,20 @@ class InstrumentationImpl(using State): val sym = modSym.asPath.selSN(genSym.nme) // NOTE: this debug printing only works for top-level modules, nested modules don't work // TODO: remove it. only for test - val debug = blockCtor("ValueLit", Ls(Value.Lit(Tree.UnitLit(false)))): undef => - // TODO: put correct parameters instead of undefined - f.params.map(ps => List.fill(ps.params.length)(undef)) - .foldRight((p: Path) => fnPrintCode(p)(End()))((args, cont) => call(_, args)(cont))(sym) + // maintain parameter names for debugging + val debug = + f.params.map(ps => + ps.params.map(p => + (k: Path => Block) => + blockCtor("Symbol", Ls(toValue(p.sym.nme))): sym => + blockCtor("ValueRef", Ls(sym))(k) + ).collectApply + ) + .foldRight((p: Path) => fnPrintCode(p)(End()))((argsCont, cont) => + path => + argsCont: args => + call(path, args)(cont) + )(sym) val dSym = TermSymbol(f.dSym.k, f.dSym.owner, Tree.Ident(f.sym.nme + "_gen")) val args = f.params.flatMap(_.params).map(_.sym) diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 37d277bf6f..7f0ce0dec4 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -54,7 +54,7 @@ staged module Arguments with x fun g(x)(y, z)() = z //│ > Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)) -//│ > Return(Lit(undefined), false) +//│ > Return(Ref(Symbol("z")), false) staged module OtherBlocks with fun scope() = @@ -68,7 +68,7 @@ staged module OtherBlocks with 3 then 0 else 0 //│ > Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))) -//│ > Scoped([Symbol("scrut"), Symbol("tmp")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN) +//│ > Scoped([Symbol("tmp"), Symbol("scrut")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN) // debug printing fails, collision with class name? :fixme From b516237c8ebb945385515eb02dbbabc194179129 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 21 Jan 2026 17:05:10 +0800 Subject: [PATCH 233/268] retain scoped symbols after instrumentation --- .../shared/src/main/scala/hkmc2/codegen/Instrumentation.scala | 4 ++-- hkmc2/shared/src/test/mlscript/block-staging/Functions.mls | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index caa305454f..b86bc560b1 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -51,7 +51,7 @@ class InstrumentationImpl(using State): def assign(res: Result, symName: Str = "tmp")(k: Path => Block): Block = // TODO: skip assignment if res: Path? val sym = new TempSymbol(N, symName) - Assign(sym, res, k(sym.asPath)) + Scoped(Set(sym), Assign(sym, res, k(sym.asPath))) def tuple(elems: Ls[ArgWrappable], symName: Str = "tmp")(k: Path => Block): Block = assign(Tuple(false, elems.map(asArg)), symName)(k) @@ -244,7 +244,7 @@ class InstrumentationImpl(using State): syms.toList.map(transformSymbol(_)).collectApply: symsStaged => tuple(symsStaged): tup => transformBlock(body): (body, ctx) => - blockCtor("Scoped", Ls(tup, body))(k(_, ctx)) + blockCtor("Scoped", Ls(tup, body))(b => Scoped(syms, k(b, ctx))) case Label(labelSymbol, loop, body, rest) => transformSymbol(labelSymbol): labelSymbol => transformBlock(body): (body, ctx) => diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 7f0ce0dec4..2c13f6ef0d 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -30,7 +30,7 @@ staged module Expressions with //│ > Return(Tuple([Lit(1), ..Ref(Symbol("x"))]), false) //│ > Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false))) //│ > Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))) -//│ > Scoped([Symbol("element0$"), Symbol("element1$"), Symbol("scrut"), Symbol("a"), Symbol("tmp"), Symbol("middleElements")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Label(Symbol("split_2$"), false, Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Assign(Symbol("tmp"), Lit(1), Break(Symbol("split_root$"))), Tup(2, false) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp"), Lit(2), Break(Symbol("split_root$")))], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End)], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End))), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$")))))], Break(Symbol("split_2$")), End)), Assign(Symbol("tmp"), Lit(0), Break(Symbol("split_root$")))NaN, Assign(Symbol("tmp"), Lit(3), End)NaN, Return(Ref(Symbol("tmp")), false)NaN) +//│ > Scoped([Symbol("element1$"), Symbol("scrut"), Symbol("a"), Symbol("tmp"), Symbol("middleElements"), Symbol("element0$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Label(Symbol("split_2$"), false, Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Assign(Symbol("tmp"), Lit(1), Break(Symbol("split_root$"))), Tup(2, false) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp"), Lit(2), Break(Symbol("split_root$")))], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End)], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End))), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$")))))], Break(Symbol("split_2$")), End)), Assign(Symbol("tmp"), Lit(0), Break(Symbol("split_root$")))NaN, Assign(Symbol("tmp"), Lit(3), End)NaN, Return(Ref(Symbol("tmp")), false)NaN) //│ x = [1, 2, 3] class Outside(a) From 0b968edbfa199cbf6155ab0da94d2ac9684c1f57 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 21 Jan 2026 17:05:16 +0800 Subject: [PATCH 234/268] update test --- hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls index 0eaa38428e..6b18ffef62 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls @@ -20,4 +20,4 @@ staged fun f() = 0 :slot staged module A //│ Pretty Lowered: -//│ define staged class A in set block$res = undefined in end +//│ define staged class A with staged module A in set block$res = undefined in end From 78e754f5b0c23b25846d50703b8d34b9f52d0a7f Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 23 Jan 2026 23:44:05 +0800 Subject: [PATCH 235/268] replace calls to staged functions --- .../scala/hkmc2/codegen/Instrumentation.scala | 16 +++++++++++++++- .../test/mlscript/block-staging/Functions.mls | 16 +++++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index b86bc560b1..bb42e03754 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -170,7 +170,21 @@ class InstrumentationImpl(using State): tuple(xs.map(_._1)): codes => blockCtor("Instantiate", Ls(cls, codes), "inst")(k) case Call(fun, args) => - transformPath(fun): fun => + val stagedFunPath = + fun match + case s @ Select(qual, Tree.Ident(name)) => s.symbol.flatMap({ + case t: TermSymbol => t.owner.flatMap({ + case sym: DefinitionSymbol[?] => + sym.defn.get.hasStagedModifier.map(_ => + Select(qual, Tree.Ident(name + "_gen"))(N) + ) + }) + case _ => N + }) + case _ => N + + val newFun = stagedFunPath.getOrElse(fun) + transformPath(newFun): fun => transformArgs(args): args => tuple(args.map(_._1)): tup => blockCtor("Call", Ls(fun, tup), "app")(k) diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 2c13f6ef0d..053c79c780 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -48,6 +48,16 @@ staged module ClassInstrumentation with //│ > Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) //│ > Return(Call(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("Inside":[Symbol("a"), Symbol("b")])), [Lit(1), Lit(2)]), false) +module Nonstaged with + fun f() = 1 +staged module Staged with + fun f() = 1 +staged module CallSubst with + fun call() = + Nonstaged.f() + Staged.f() +//│ > Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Call(Select(Ref(Symbol("Nonstaged")), Symbol("f")), []), Return(Call(Select(Ref(Symbol("Staged")), Symbol("f_gen")), []), false))) + staged module Arguments with fun f(x) = x = 1 @@ -68,7 +78,7 @@ staged module OtherBlocks with 3 then 0 else 0 //│ > Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))) -//│ > Scoped([Symbol("tmp"), Symbol("scrut")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN) +//│ > Scoped([Symbol("scrut"), Symbol("tmp")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN) // debug printing fails, collision with class name? :fixme @@ -84,8 +94,8 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.83: staged module B with +//│ ║ l.93: staged module B with //│ ║ ^^^^^^ -//│ ║ l.84: fun f() = 1 +//│ ║ l.94: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ ═══[RUNTIME ERROR] ReferenceError: B is not defined From fe08c3bcfccffd7f959ad24f9c214a2787c08f97 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 24 Jan 2026 00:44:02 +0800 Subject: [PATCH 236/268] Wrap function body --- .../scala/hkmc2/codegen/Instrumentation.scala | 37 ++++++++++-------- .../test/mlscript/block-staging/Functions.mls | 39 ++++++++++--------- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index bb42e03754..28a76df783 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -272,25 +272,30 @@ class InstrumentationImpl(using State): // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function // so we pass modSym instead def transformFunDefn(modSym: BlockMemberSymbol, f: FunDefn): (FunDefn, Block) = - val genSym = BlockMemberSymbol(f.sym.nme + "_gen", Nil, true) - val sym = modSym.asPath.selSN(genSym.nme) + val genSymName = f.sym.nme + "_gen" + val genSym = BlockMemberSymbol(genSymName, Nil, false) + val sym = modSym.asPath.selSN(genSymName) // NOTE: this debug printing only works for top-level modules, nested modules don't work - // TODO: remove it. only for test // maintain parameter names for debugging val debug = - f.params.map(ps => - ps.params.map(p => - (k: Path => Block) => - blockCtor("Symbol", Ls(toValue(p.sym.nme))): sym => - blockCtor("ValueRef", Ls(sym))(k) - ).collectApply - ) - .foldRight((p: Path) => fnPrintCode(p)(End()))((argsCont, cont) => - path => - argsCont: args => - call(path, args)(cont) - )(sym) - + f.params.map( + _.params.map(p => blockCtor("Symbol", Ls(toValue(p.sym.nme)))).collectApply + ).collectApply: paramListSyms => + def callCont(k: Path => Block) = + paramListSyms.foldRight(k)((syms, cont) => + path => + syms.map(sym => blockCtor("ValueRef", Ls(sym))).collectApply: args => + call(path, args)(cont) + )(sym) + callCont: body => + blockCtor("Symbol", Ls(toValue(genSymName))): sym => + paramListSyms.map(tuple(_)).collectApply: tups => + tuple(tups): tup => + blockCtor("FunDefn", Ls(sym, tup, body, toValue(true))): block => + // TODO: remove it. only for test + fnPrintCode(block)(End()) + + // turn intro fundefn val dSym = TermSymbol(f.dSym.k, f.dSym.owner, Tree.Ident(f.sym.nme + "_gen")) val args = f.params.flatMap(_.params).map(_.sym) val newBody = diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 053c79c780..30c064fe72 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -24,13 +24,13 @@ staged module Expressions with [1, 2] then 2 [a, ...] then 3 else 0 -//│ > Return(Lit(1), false) -//│ > Scoped([Symbol("x"), Symbol("y")], Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false)))) -//│ > Return(Tuple([Lit(1), Lit(2)]), false) -//│ > Return(Tuple([Lit(1), ..Ref(Symbol("x"))]), false) -//│ > Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false))) -//│ > Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))) -//│ > Scoped([Symbol("element1$"), Symbol("scrut"), Symbol("a"), Symbol("tmp"), Symbol("middleElements"), Symbol("element0$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Label(Symbol("split_2$"), false, Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Assign(Symbol("tmp"), Lit(1), Break(Symbol("split_root$"))), Tup(2, false) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp"), Lit(2), Break(Symbol("split_root$")))], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End)], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End))), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$")))))], Break(Symbol("split_2$")), End)), Assign(Symbol("tmp"), Lit(0), Break(Symbol("split_root$")))NaN, Assign(Symbol("tmp"), Lit(3), End)NaN, Return(Ref(Symbol("tmp")), false)NaN) +//│ > FunDefn(Symbol("lit_gen"), ([]), Return(Lit(1), false), true) +//│ > FunDefn(Symbol("assign_gen"), ([]), Scoped([Symbol("x"), Symbol("y")], Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false)))), true) +//│ > FunDefn(Symbol("tup1_gen"), ([]), Return(Tuple([Lit(1), Lit(2)]), false), true) +//│ > FunDefn(Symbol("tup2_gen"), ([]), Return(Tuple([Lit(1), ..Ref(Symbol("x"))]), false), true) +//│ > FunDefn(Symbol("dynsel_gen"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false))), true) +//│ > FunDefn(Symbol("match1_gen"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))), true) +//│ > FunDefn(Symbol("match2_gen"), ([]), Scoped([Symbol("element1$"), Symbol("scrut"), Symbol("a"), Symbol("tmp"), Symbol("middleElements"), Symbol("element0$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Label(Symbol("split_2$"), false, Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Assign(Symbol("tmp"), Lit(1), Break(Symbol("split_root$"))), Tup(2, false) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp"), Lit(2), Break(Symbol("split_root$")))], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End)], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End))), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$")))))], Break(Symbol("split_2$")), End)), Assign(Symbol("tmp"), Lit(0), Break(Symbol("split_root$")))NaN, Assign(Symbol("tmp"), Lit(3), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) //│ x = [1, 2, 3] class Outside(a) @@ -43,10 +43,10 @@ staged module ClassInstrumentation with fun app2() = Inside(1, 2) //│ > Define(ClsLikeDefn(ClassSymbol("NoArg"), TODO), End) //│ > Define(ClsLikeDefn(ClassSymbol("Inside":[Symbol("a"), Symbol("b")]), TODO), End) -//│ > Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) -//│ > Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("NoArg")), []), false) -//│ > Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false) -//│ > Return(Call(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("Inside":[Symbol("a"), Symbol("b")])), [Lit(1), Lit(2)]), false) +//│ > FunDefn(Symbol("inst1_gen"), ([]), Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) +//│ > FunDefn(Symbol("inst2_gen"), ([]), Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("NoArg")), []), false), true) +//│ > FunDefn(Symbol("app1_gen"), ([]), Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) +//│ > FunDefn(Symbol("app2_gen"), ([]), Return(Call(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("Inside":[Symbol("a"), Symbol("b")])), [Lit(1), Lit(2)]), false), true) module Nonstaged with fun f() = 1 @@ -56,15 +56,16 @@ staged module CallSubst with fun call() = Nonstaged.f() Staged.f() -//│ > Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Call(Select(Ref(Symbol("Nonstaged")), Symbol("f")), []), Return(Call(Select(Ref(Symbol("Staged")), Symbol("f_gen")), []), false))) +//│ > FunDefn(Symbol("f_gen"), ([]), Return(Lit(1), false), true) +//│ > FunDefn(Symbol("call_gen"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Call(Select(Ref(Symbol("Nonstaged")), Symbol("f")), []), Return(Call(Select(Ref(Symbol("Staged")), Symbol("f_gen")), []), false))), true) staged module Arguments with fun f(x) = x = 1 x fun g(x)(y, z)() = z -//│ > Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)) -//│ > Return(Ref(Symbol("z")), false) +//│ > FunDefn(Symbol("f_gen"), ([Symbol("x")]), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)), true) +//│ > FunDefn(Symbol("g_gen"), ([Symbol("x")],[Symbol("y"), Symbol("z")],[]), Return(Ref(Symbol("z")), false), true) staged module OtherBlocks with fun scope() = @@ -77,8 +78,8 @@ staged module OtherBlocks with 2 then 0 3 then 0 else 0 -//│ > Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))) -//│ > Scoped([Symbol("scrut"), Symbol("tmp")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN) +//│ > FunDefn(Symbol("scope_gen"), ([]), Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))), true) +//│ > FunDefn(Symbol("breakAndLabel_gen"), ([]), Scoped([Symbol("tmp"), Symbol("scrut")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) // debug printing fails, collision with class name? :fixme @@ -94,8 +95,8 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.93: staged module B with +//│ ║ l.94: staged module B with //│ ║ ^^^^^^ -//│ ║ l.94: fun f() = 1 +//│ ║ l.95: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ -//│ ═══[RUNTIME ERROR] ReferenceError: B is not defined +//│ > FunDefn(Symbol("f_gen"), ([]), Return(Lit(1), false), true) From efb6ae86c6cff94395dbf8b7a12509198d9b8f74 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 24 Jan 2026 00:44:12 +0800 Subject: [PATCH 237/268] move printing into constructor --- .../main/scala/hkmc2/codegen/Instrumentation.scala | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 28a76df783..1833a11fe5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -323,10 +323,13 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): val (stagedMethods, debugPrintCode) = companion.methods .map(impl.transformFunDefn(sym, _)) .unzip - val newCtor = impl.transformBlock(companion.ctor)(using new HashMap())(_ => End()) + + val unit = Select(Value.Ref(State.runtimeSymbol), Tree.Ident("Unit"))(N) + val debugBlock = debugPrintCode.foldRight(Return(unit, true))(concat) + def debugCont(rest: Block) = + Begin(debugBlock, rest) + val newCtor = impl.transformBlock(companion.ctor)(using new HashMap())(_ => debugCont(End())) val newCompanion = companion.copy(methods = companion.methods ++ stagedMethods, ctor = newCtor) val newModule = c.copy(sym = sym, companion = S(newCompanion)) - // debug is printed after definition - val debugBlock = debugPrintCode.foldRight(rest)(concat) - Define(newModule, debugBlock) + Define(newModule, rest) case b => b From 245da6d8b5c617c7542b9c4c707f887f247c153b Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 28 Jan 2026 00:11:25 +0800 Subject: [PATCH 238/268] remove _gen suffix from instrumented block we check if a function is staged through defCtx, so we can substitute the symbol there --- .../scala/hkmc2/codegen/Instrumentation.scala | 2 +- .../test/mlscript/block-staging/Functions.mls | 34 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 1833a11fe5..2735bad2c7 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -288,7 +288,7 @@ class InstrumentationImpl(using State): call(path, args)(cont) )(sym) callCont: body => - blockCtor("Symbol", Ls(toValue(genSymName))): sym => + blockCtor("Symbol", Ls(toValue(f.sym.nme))): sym => paramListSyms.map(tuple(_)).collectApply: tups => tuple(tups): tup => blockCtor("FunDefn", Ls(sym, tup, body, toValue(true))): block => diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 30c064fe72..e2376aa987 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -24,13 +24,13 @@ staged module Expressions with [1, 2] then 2 [a, ...] then 3 else 0 -//│ > FunDefn(Symbol("lit_gen"), ([]), Return(Lit(1), false), true) -//│ > FunDefn(Symbol("assign_gen"), ([]), Scoped([Symbol("x"), Symbol("y")], Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false)))), true) -//│ > FunDefn(Symbol("tup1_gen"), ([]), Return(Tuple([Lit(1), Lit(2)]), false), true) -//│ > FunDefn(Symbol("tup2_gen"), ([]), Return(Tuple([Lit(1), ..Ref(Symbol("x"))]), false), true) -//│ > FunDefn(Symbol("dynsel_gen"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false))), true) -//│ > FunDefn(Symbol("match1_gen"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))), true) -//│ > FunDefn(Symbol("match2_gen"), ([]), Scoped([Symbol("element1$"), Symbol("scrut"), Symbol("a"), Symbol("tmp"), Symbol("middleElements"), Symbol("element0$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Label(Symbol("split_2$"), false, Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Assign(Symbol("tmp"), Lit(1), Break(Symbol("split_root$"))), Tup(2, false) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp"), Lit(2), Break(Symbol("split_root$")))], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End)], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End))), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$")))))], Break(Symbol("split_2$")), End)), Assign(Symbol("tmp"), Lit(0), Break(Symbol("split_root$")))NaN, Assign(Symbol("tmp"), Lit(3), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) +//│ > FunDefn(Symbol("lit"), ([]), Return(Lit(1), false), true) +//│ > FunDefn(Symbol("assign"), ([]), Scoped([Symbol("x"), Symbol("y")], Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false)))), true) +//│ > FunDefn(Symbol("tup1"), ([]), Return(Tuple([Lit(1), Lit(2)]), false), true) +//│ > FunDefn(Symbol("tup2"), ([]), Return(Tuple([Lit(1), ..Ref(Symbol("x"))]), false), true) +//│ > FunDefn(Symbol("dynsel"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false))), true) +//│ > FunDefn(Symbol("match1"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))), true) +//│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("element1$"), Symbol("scrut"), Symbol("a"), Symbol("tmp"), Symbol("middleElements"), Symbol("element0$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Label(Symbol("split_2$"), false, Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Assign(Symbol("tmp"), Lit(1), Break(Symbol("split_root$"))), Tup(2, false) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp"), Lit(2), Break(Symbol("split_root$")))], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End)], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End))), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$")))))], Break(Symbol("split_2$")), End)), Assign(Symbol("tmp"), Lit(0), Break(Symbol("split_root$")))NaN, Assign(Symbol("tmp"), Lit(3), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) //│ x = [1, 2, 3] class Outside(a) @@ -43,10 +43,10 @@ staged module ClassInstrumentation with fun app2() = Inside(1, 2) //│ > Define(ClsLikeDefn(ClassSymbol("NoArg"), TODO), End) //│ > Define(ClsLikeDefn(ClassSymbol("Inside":[Symbol("a"), Symbol("b")]), TODO), End) -//│ > FunDefn(Symbol("inst1_gen"), ([]), Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) -//│ > FunDefn(Symbol("inst2_gen"), ([]), Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("NoArg")), []), false), true) -//│ > FunDefn(Symbol("app1_gen"), ([]), Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) -//│ > FunDefn(Symbol("app2_gen"), ([]), Return(Call(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("Inside":[Symbol("a"), Symbol("b")])), [Lit(1), Lit(2)]), false), true) +//│ > FunDefn(Symbol("inst1"), ([]), Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) +//│ > FunDefn(Symbol("inst2"), ([]), Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("NoArg")), []), false), true) +//│ > FunDefn(Symbol("app1"), ([]), Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) +//│ > FunDefn(Symbol("app2"), ([]), Return(Call(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("Inside":[Symbol("a"), Symbol("b")])), [Lit(1), Lit(2)]), false), true) module Nonstaged with fun f() = 1 @@ -56,16 +56,16 @@ staged module CallSubst with fun call() = Nonstaged.f() Staged.f() -//│ > FunDefn(Symbol("f_gen"), ([]), Return(Lit(1), false), true) -//│ > FunDefn(Symbol("call_gen"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Call(Select(Ref(Symbol("Nonstaged")), Symbol("f")), []), Return(Call(Select(Ref(Symbol("Staged")), Symbol("f_gen")), []), false))), true) +//│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) +//│ > FunDefn(Symbol("call"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Call(Select(Ref(Symbol("Nonstaged")), Symbol("f")), []), Return(Call(Select(Ref(Symbol("Staged")), Symbol("f_gen")), []), false))), true) staged module Arguments with fun f(x) = x = 1 x fun g(x)(y, z)() = z -//│ > FunDefn(Symbol("f_gen"), ([Symbol("x")]), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)), true) -//│ > FunDefn(Symbol("g_gen"), ([Symbol("x")],[Symbol("y"), Symbol("z")],[]), Return(Ref(Symbol("z")), false), true) +//│ > FunDefn(Symbol("f"), ([Symbol("x")]), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)), true) +//│ > FunDefn(Symbol("g"), ([Symbol("x")],[Symbol("y"), Symbol("z")],[]), Return(Ref(Symbol("z")), false), true) staged module OtherBlocks with fun scope() = @@ -78,8 +78,8 @@ staged module OtherBlocks with 2 then 0 3 then 0 else 0 -//│ > FunDefn(Symbol("scope_gen"), ([]), Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))), true) -//│ > FunDefn(Symbol("breakAndLabel_gen"), ([]), Scoped([Symbol("tmp"), Symbol("scrut")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) +//│ > FunDefn(Symbol("scope"), ([]), Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))), true) +//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("tmp"), Symbol("scrut")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) // debug printing fails, collision with class name? :fixme From 1c86af0660eec18f63b14a7c71351d7bffade6f6 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 28 Jan 2026 00:46:16 +0800 Subject: [PATCH 239/268] remove parameters from instrumentation function _instr function only returns the block IR, whereas _gen functions will include the shape propagation --- .../scala/hkmc2/codegen/Instrumentation.scala | 38 ++++++++----------- .../test/mlscript/block-staging/Functions.mls | 6 +-- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 2735bad2c7..b596558f61 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -272,36 +272,30 @@ class InstrumentationImpl(using State): // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function // so we pass modSym instead def transformFunDefn(modSym: BlockMemberSymbol, f: FunDefn): (FunDefn, Block) = - val genSymName = f.sym.nme + "_gen" + val genSymName = f.sym.nme + "_instr" val genSym = BlockMemberSymbol(genSymName, Nil, false) val sym = modSym.asPath.selSN(genSymName) // NOTE: this debug printing only works for top-level modules, nested modules don't work - // maintain parameter names for debugging - val debug = - f.params.map( - _.params.map(p => blockCtor("Symbol", Ls(toValue(p.sym.nme)))).collectApply - ).collectApply: paramListSyms => - def callCont(k: Path => Block) = - paramListSyms.foldRight(k)((syms, cont) => - path => - syms.map(sym => blockCtor("ValueRef", Ls(sym))).collectApply: args => - call(path, args)(cont) - )(sym) - callCont: body => + + // turn into fundefn + val dSym = TermSymbol(f.dSym.k, f.dSym.owner, Tree.Ident(f.sym.nme + "_instr")) + val argSyms = f.params.flatMap(_.params).map(_.sym) + val newBody = + val rest = transformBlock(f.body)(using new HashMap): body => + // maintain parameter names in instrumented code + f.params.map( + _.params.map(p => blockCtor("Symbol", Ls(toValue(p.sym.nme)))).collectApply + ).collectApply: paramListSyms => blockCtor("Symbol", Ls(toValue(f.sym.nme))): sym => paramListSyms.map(tuple(_)).collectApply: tups => tuple(tups): tup => blockCtor("FunDefn", Ls(sym, tup, body, toValue(true))): block => - // TODO: remove it. only for test - fnPrintCode(block)(End()) + Return(block, false) + Scoped(Set(argSyms*), rest) - // turn intro fundefn - val dSym = TermSymbol(f.dSym.k, f.dSym.owner, Tree.Ident(f.sym.nme + "_gen")) - val args = f.params.flatMap(_.params).map(_.sym) - val newBody = - given Context = HashMap(args.map(s => Value.Ref(s, N) -> Value.Ref(s, N))*) - transformBlock(f.body)(Return(_, false)) - val newFun = f.copy(sym = genSym, dSym = dSym, body = newBody)(false) + // TODO: remove it. only for test + val debug = call(sym, Nil)(fnPrintCode(_)(End())) + val newFun = f.copy(sym = genSym, dSym = dSym, params = Ls(PlainParamList(Nil)), body = newBody)(false) (newFun, debug) // TODO: rename as InstrumentationTransformer? diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index e2376aa987..a44e994b1d 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -79,14 +79,14 @@ staged module OtherBlocks with 3 then 0 else 0 //│ > FunDefn(Symbol("scope"), ([]), Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))), true) -//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("tmp"), Symbol("scrut")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) +//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("scrut"), Symbol("tmp")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) // debug printing fails, collision with class name? :fixme class A() staged module A with fun f() = 1 -//│ ═══[RUNTIME ERROR] TypeError: A1.f_gen is not a function +//│ ═══[RUNTIME ERROR] TypeError: A1.f_instr is not a function // debug printing fails, unable to reference the class when calling the instrumented function :fixme @@ -99,4 +99,4 @@ module A with //│ ║ ^^^^^^ //│ ║ l.95: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ -//│ > FunDefn(Symbol("f_gen"), ([]), Return(Lit(1), false), true) +//│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) From f5459ac32675ff364edfa642a253345606ac0aac Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 7 Feb 2026 00:25:40 +0800 Subject: [PATCH 240/268] minor nit --- .../shared/src/main/scala/hkmc2/codegen/Instrumentation.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index b596558f61..9bc66a2f96 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -216,7 +216,6 @@ class InstrumentationImpl(using State): case Case.Tup(len, inf) => blockCtor("Tup", Ls(len, inf).map(toValue))(k) case Case.Field(name, safe) => ??? // not supported - // ruleBlk? def transformBlock(b: Block)(using Context)(k: Path => Block): Block = transformBlock(b)((p, _) => k(p)) @@ -318,7 +317,7 @@ class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): .map(impl.transformFunDefn(sym, _)) .unzip - val unit = Select(Value.Ref(State.runtimeSymbol), Tree.Ident("Unit"))(N) + val unit = State.runtimeSymbol.asPath.selSN("Unit") val debugBlock = debugPrintCode.foldRight(Return(unit, true))(concat) def debugCont(rest: Block) = Begin(debugBlock, rest) From dbe58e7ce15da5e3cd45934fcbbe5f20b16ecaf3 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 10 Feb 2026 17:04:09 +0800 Subject: [PATCH 241/268] rename TempSymbol when staging --- .../scala/hkmc2/codegen/Instrumentation.scala | 12 ++++++++++-- .../src/test/mlscript/block-staging/Functions.mls | 15 ++++++++------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 9bc66a2f96..aaa9c4f33e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -21,6 +21,7 @@ import syntax.{Literal, Tree} class InstrumentationImpl(using State): type ArgWrappable = Path | Symbol type Context = HashMap[Path, Path] + var scope = Scope.empty def asArg(x: ArgWrappable): Arg = x match @@ -92,11 +93,18 @@ class InstrumentationImpl(using State): def transformSymbol(sym: Symbol, symName: Str = "sym")(k: Path => Block): Block = sym match case clsSym: ClassSymbol => + val name = scope.allocateOrGetName(sym) transformParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => - blockCtor("ClassSymbol", Ls(toValue(sym.nme), paramsOpt), symName)(k) + blockCtor("ClassSymbol", Ls(toValue(name), paramsOpt), symName)(k) case t: TermSymbol if t.defn.exists(_.sym.asCls.isDefined) => + val name = scope.allocateOrGetName(sym) transformSymbol(t.defn.get.sym.asCls.get, symName)(k) - case _ => blockCtor("Symbol", Ls(toValue(sym.nme)), symName)(k) + case t: BuiltinSymbol => + // retain names to built-in functions + blockCtor("Symbol", Ls(toValue(sym.nme)), symName)(k) + case _ => + val name = scope.allocateOrGetName(sym) + blockCtor("Symbol", Ls(toValue(name)), symName)(k) def transformOption[A](xOpt: Opt[A], f: A => (Path => Block) => Block)(k: Path => Block): Block = xOpt match diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index a44e994b1d..599c839281 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -27,10 +27,10 @@ staged module Expressions with //│ > FunDefn(Symbol("lit"), ([]), Return(Lit(1), false), true) //│ > FunDefn(Symbol("assign"), ([]), Scoped([Symbol("x"), Symbol("y")], Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false)))), true) //│ > FunDefn(Symbol("tup1"), ([]), Return(Tuple([Lit(1), Lit(2)]), false), true) -//│ > FunDefn(Symbol("tup2"), ([]), Return(Tuple([Lit(1), ..Ref(Symbol("x"))]), false), true) +//│ > FunDefn(Symbol("tup2"), ([]), Return(Tuple([Lit(1), ..Ref(Symbol("x1"))]), false), true) //│ > FunDefn(Symbol("dynsel"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false))), true) //│ > FunDefn(Symbol("match1"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))), true) -//│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("element1$"), Symbol("scrut"), Symbol("a"), Symbol("tmp"), Symbol("middleElements"), Symbol("element0$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Label(Symbol("split_2$"), false, Assign(Symbol("scrut"), Tuple([...Ref(Symbol("x"))]), Match(Ref(Symbol("scrut")), [Tup(0, false) -> Assign(Symbol("tmp"), Lit(1), Break(Symbol("split_root$"))), Tup(2, false) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp"), Lit(2), Break(Symbol("split_root$")))], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End)], Match(Ref(Symbol("scrut")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End))), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$")))))], Break(Symbol("split_2$")), End)), Assign(Symbol("tmp"), Lit(0), Break(Symbol("split_root$")))NaN, Assign(Symbol("tmp"), Lit(3), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) +//│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("element1$"), Symbol("scrut1"), Symbol("a"), Symbol("tmp1"), Symbol("middleElements"), Symbol("element0$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Label(Symbol("split_2$"), false, Assign(Symbol("scrut1"), Tuple([...Ref(Symbol("x1"))]), Match(Ref(Symbol("scrut1")), [Tup(0, false) -> Assign(Symbol("tmp1"), Lit(1), Break(Symbol("split_root$"))), Tup(2, false) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp1"), Lit(2), Break(Symbol("split_root$")))], Match(Ref(Symbol("scrut1")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End)], Match(Ref(Symbol("scrut1")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End))), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$")))))], Break(Symbol("split_2$")), End)), Assign(Symbol("tmp1"), Lit(0), Break(Symbol("split_root$")))NaN, Assign(Symbol("tmp1"), Lit(3), End)NaN, Return(Ref(Symbol("tmp1")), false)NaN), true) //│ x = [1, 2, 3] class Outside(a) @@ -42,11 +42,11 @@ staged module ClassInstrumentation with fun app1() = Outside(1) fun app2() = Inside(1, 2) //│ > Define(ClsLikeDefn(ClassSymbol("NoArg"), TODO), End) -//│ > Define(ClsLikeDefn(ClassSymbol("Inside":[Symbol("a"), Symbol("b")]), TODO), End) +//│ > Define(ClsLikeDefn(ClassSymbol("Inside1":[Symbol("a1"), Symbol("b")]), TODO), End) //│ > FunDefn(Symbol("inst1"), ([]), Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) //│ > FunDefn(Symbol("inst2"), ([]), Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("NoArg")), []), false), true) //│ > FunDefn(Symbol("app1"), ([]), Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) -//│ > FunDefn(Symbol("app2"), ([]), Return(Call(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("Inside":[Symbol("a"), Symbol("b")])), [Lit(1), Lit(2)]), false), true) +//│ > FunDefn(Symbol("app2"), ([]), Return(Call(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("Inside1":[Symbol("a1"), Symbol("b")])), [Lit(1), Lit(2)]), false), true) module Nonstaged with fun f() = 1 @@ -54,10 +54,11 @@ staged module Staged with fun f() = 1 staged module CallSubst with fun call() = + 1 + 1 Nonstaged.f() Staged.f() //│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) -//│ > FunDefn(Symbol("call"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Call(Select(Ref(Symbol("Nonstaged")), Symbol("f")), []), Return(Call(Select(Ref(Symbol("Staged")), Symbol("f_gen")), []), false))), true) +//│ > FunDefn(Symbol("call"), ([]), Scoped([Symbol("tmp"), Symbol("tmp1")], Assign(Symbol("tmp"), Call(Ref(Symbol("+")), [Lit(1), Lit(1)]), Assign(Symbol("tmp1"), Call(Select(Ref(Symbol("Nonstaged")), Symbol("f")), []), Return(Call(Select(Ref(Symbol("Staged")), Symbol("f_gen")), []), false)))), true) staged module Arguments with fun f(x) = @@ -95,8 +96,8 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.94: staged module B with +//│ ║ l.95: staged module B with //│ ║ ^^^^^^ -//│ ║ l.95: fun f() = 1 +//│ ║ l.96: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) From 71677120923fb04ba7164a976c30b4d5a8887db1 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 10 Feb 2026 17:04:18 +0800 Subject: [PATCH 242/268] fix concat logic --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 360f4723c9..425005973c 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -64,7 +64,7 @@ class Block with fun concat(b1: Block, b2: Block) = if b1 is Match(scrut, arms, dflt, rest) then Match(scrut, arms, dflt, concat(rest, b2)) - Return(res, implct) then b2 // discard return? + Return(res, implct) then b1 Assign(lhs, rhs, rest) then Assign(lhs, rhs, concat(rest, b2)) Define(defn, rest) then Define(defn, concat(rest, b2)) Scoped(symbols, rest) then Scoped(symbols, concat(rest, b2)) From cd16d6f2a2e525b45e78c33ec1f8d208a338ea42 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 10 Feb 2026 17:24:38 +0800 Subject: [PATCH 243/268] warn shape propogation doesn't cover multiple parameter lists --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 6 ++++-- .../src/test/mlscript/block-staging/Functions.mls | 10 +++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index aaa9c4f33e..20929d8f0e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -18,7 +18,7 @@ import syntax.{Literal, Tree} // this avoids having to rebuild the same shapes everytime they are needed // transform Block to Block IR so that it can be instrumented in mlscript -class InstrumentationImpl(using State): +class InstrumentationImpl(using State, Raise): type ArgWrappable = Path | Symbol type Context = HashMap[Path, Path] var scope = Scope.empty @@ -289,6 +289,8 @@ class InstrumentationImpl(using State): val argSyms = f.params.flatMap(_.params).map(_.sym) val newBody = val rest = transformBlock(f.body)(using new HashMap): body => + if f.params.length != 1 then + raise(WarningReport(msg"Multiple parameter lists are not supported in shape propagation yet." -> f.sym.toLoc :: Nil)) // maintain parameter names in instrumented code f.params.map( _.params.map(p => blockCtor("Symbol", Ls(toValue(p.sym.nme)))).collectApply @@ -306,7 +308,7 @@ class InstrumentationImpl(using State): (newFun, debug) // TODO: rename as InstrumentationTransformer? -class Instrumentation(using State) extends BlockTransformer(new SymbolSubst()): +class Instrumentation(using State, Raise) extends BlockTransformer(new SymbolSubst()): val impl = new InstrumentationImpl def concat(b1: Block, b2: Block): Block = diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 599c839281..e0ca906ce4 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -60,11 +60,15 @@ staged module CallSubst with //│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) //│ > FunDefn(Symbol("call"), ([]), Scoped([Symbol("tmp"), Symbol("tmp1")], Assign(Symbol("tmp"), Call(Ref(Symbol("+")), [Lit(1), Lit(1)]), Assign(Symbol("tmp1"), Call(Select(Ref(Symbol("Nonstaged")), Symbol("f")), []), Return(Call(Select(Ref(Symbol("Staged")), Symbol("f_gen")), []), false)))), true) +:w staged module Arguments with fun f(x) = x = 1 x fun g(x)(y, z)() = z +//│ ╔══[WARNING] Multiple parameter lists are not supported in shape propagation yet. +//│ ║ l.68: fun g(x)(y, z)() = z +//│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ > FunDefn(Symbol("f"), ([Symbol("x")]), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)), true) //│ > FunDefn(Symbol("g"), ([Symbol("x")],[Symbol("y"), Symbol("z")],[]), Return(Ref(Symbol("z")), false), true) @@ -96,8 +100,8 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.95: staged module B with +//│ ║ l.99: staged module B with //│ ║ ^^^^^^ -//│ ║ l.96: fun f() = 1 -//│ ╙── ^^^^^^^^^^^^^^^ +//│ ║ l.100: fun f() = 1 +//│ ╙── ^^^^^^^^^^^^^^^ //│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) From 9d9d449d64b9c23975bdfd5355883ac7777fa890 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 11 Feb 2026 22:13:06 +0800 Subject: [PATCH 244/268] move ctor staging to a function --- .../scala/hkmc2/codegen/Instrumentation.scala | 26 ++++++++------- .../test/mlscript/block-staging/Functions.mls | 32 +++++++++++++++---- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 20929d8f0e..e2005c4209 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -21,6 +21,7 @@ import syntax.{Literal, Tree} class InstrumentationImpl(using State, Raise): type ArgWrappable = Path | Symbol type Context = HashMap[Path, Path] + // TODO: there could be a fresh scope per function body, instead of a single one for the entire program var scope = Scope.empty def asArg(x: ArgWrappable): Arg = @@ -99,7 +100,7 @@ class InstrumentationImpl(using State, Raise): case t: TermSymbol if t.defn.exists(_.sym.asCls.isDefined) => val name = scope.allocateOrGetName(sym) transformSymbol(t.defn.get.sym.asCls.get, symName)(k) - case t: BuiltinSymbol => + case _: BuiltinSymbol => // retain names to built-in functions blockCtor("Symbol", Ls(toValue(sym.nme)), symName)(k) case _ => @@ -242,14 +243,13 @@ class InstrumentationImpl(using State, Raise): blockCtor("Assign", Ls(xSym, y, z), "assign")(k(_, ctx)) case Define(cls: ClsLikeDefn, rest) => assert(cls.companion.isEmpty, "nested module not supported") - (Define(cls, _)): - transformBlock(rest): p => - transformSymbol(cls.isym): c => - optionNone(): none => // TODO: handle companion object - blockCtor("ClsLikeDefn", Ls(c, none)): cls => - blockCtor("Define", Ls(cls, p)): p => - ruleEnd(): end => - fnPrintCode(p)(k(end, ctx)) + transformBlock(rest): p => + transformSymbol(cls.isym): c => + optionNone(): none => // TODO: handle companion object + blockCtor("ClsLikeDefn", Ls(c, none)): cls => + blockCtor("Define", Ls(cls, p)): p => + ruleEnd(): end => + fnPrintCode(p)(k(end, ctx)) case End(_) => ruleEnd()(k(_, ctx)) case Match(p, ks, dflt, rest) => transformPath(p): x => @@ -326,13 +326,15 @@ class Instrumentation(using State, Raise) extends BlockTransformer(new SymbolSub val (stagedMethods, debugPrintCode) = companion.methods .map(impl.transformFunDefn(sym, _)) .unzip + val ctor = FunDefn.withFreshSymbol(S(companion.isym), BlockMemberSymbol("ctor$", Nil), Ls(PlainParamList(Nil)), companion.ctor)(false) + val (stagedCtor, ctorPrint) = impl.transformFunDefn(sym, ctor) val unit = State.runtimeSymbol.asPath.selSN("Unit") - val debugBlock = debugPrintCode.foldRight(Return(unit, true))(concat) + val debugBlock = (ctorPrint :: debugPrintCode).foldRight(Return(unit, true))(concat) def debugCont(rest: Block) = Begin(debugBlock, rest) - val newCtor = impl.transformBlock(companion.ctor)(using new HashMap())(_ => debugCont(End())) - val newCompanion = companion.copy(methods = companion.methods ++ stagedMethods, ctor = newCtor) + // stage the constructor + val newCompanion = companion.copy(methods = stagedCtor :: companion.methods ++ stagedMethods, ctor = companion.ctor.mapTail(debugCont)) val newModule = c.copy(sym = sym, companion = S(newCompanion)) Define(newModule, rest) case b => b diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index e0ca906ce4..a87675de55 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -24,6 +24,7 @@ staged module Expressions with [1, 2] then 2 [a, ...] then 3 else 0 +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("lit"), ([]), Return(Lit(1), false), true) //│ > FunDefn(Symbol("assign"), ([]), Scoped([Symbol("x"), Symbol("y")], Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false)))), true) //│ > FunDefn(Symbol("tup1"), ([]), Return(Tuple([Lit(1), Lit(2)]), false), true) @@ -43,6 +44,7 @@ staged module ClassInstrumentation with fun app2() = Inside(1, 2) //│ > Define(ClsLikeDefn(ClassSymbol("NoArg"), TODO), End) //│ > Define(ClsLikeDefn(ClassSymbol("Inside1":[Symbol("a1"), Symbol("b")]), TODO), End) +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("inst1"), ([]), Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) //│ > FunDefn(Symbol("inst2"), ([]), Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("NoArg")), []), false), true) //│ > FunDefn(Symbol("app1"), ([]), Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) @@ -52,12 +54,14 @@ module Nonstaged with fun f() = 1 staged module Staged with fun f() = 1 +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) +//│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) staged module CallSubst with fun call() = 1 + 1 Nonstaged.f() Staged.f() -//│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("call"), ([]), Scoped([Symbol("tmp"), Symbol("tmp1")], Assign(Symbol("tmp"), Call(Ref(Symbol("+")), [Lit(1), Lit(1)]), Assign(Symbol("tmp1"), Call(Select(Ref(Symbol("Nonstaged")), Symbol("f")), []), Return(Call(Select(Ref(Symbol("Staged")), Symbol("f_gen")), []), false)))), true) :w @@ -67,8 +71,9 @@ staged module Arguments with x fun g(x)(y, z)() = z //│ ╔══[WARNING] Multiple parameter lists are not supported in shape propagation yet. -//│ ║ l.68: fun g(x)(y, z)() = z +//│ ║ l.72: fun g(x)(y, z)() = z //│ ╙── ^^^^^^^^^^^^^^^^^^^^ +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("f"), ([Symbol("x")]), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)), true) //│ > FunDefn(Symbol("g"), ([Symbol("x")],[Symbol("y"), Symbol("z")],[]), Return(Ref(Symbol("z")), false), true) @@ -83,15 +88,21 @@ staged module OtherBlocks with 2 then 0 3 then 0 else 0 +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("scope"), ([]), Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))), true) -//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("scrut"), Symbol("tmp")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) +//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("tmp"), Symbol("scrut")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) + +staged module ClassDefs with + class A +//│ > Define(ClsLikeDefn(ClassSymbol("A"), TODO), End) +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) // debug printing fails, collision with class name? :fixme class A() staged module A with fun f() = 1 -//│ ═══[RUNTIME ERROR] TypeError: A1.f_instr is not a function +//│ ═══[RUNTIME ERROR] TypeError: A2.ctor$_instr is not a function // debug printing fails, unable to reference the class when calling the instrumented function :fixme @@ -100,8 +111,15 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.99: staged module B with -//│ ║ ^^^^^^ -//│ ║ l.100: fun f() = 1 +//│ ║ l.110: staged module B with +//│ ║ ^^^^^^ +//│ ║ l.111: fun f() = 1 +//│ ╙── ^^^^^^^^^^^^^^^ +//│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' +//│ ╟── which references the symbol introduced here +//│ ║ l.110: staged module B with +//│ ║ ^^^^^^ +//│ ║ l.111: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) From 0a61576a8c794dbef5953ab25d8499334b8c6e34 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 27 Feb 2026 23:38:25 +0800 Subject: [PATCH 245/268] WIP: add class staging test --- .../test/mlscript/block-staging/Functions.mls | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index a87675de55..b78d88d38d 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -97,12 +97,18 @@ staged module ClassDefs with //│ > Define(ClsLikeDefn(ClassSymbol("A"), TODO), End) //│ > FunDefn(Symbol("ctor$"), ([]), End, true) +staged module ClassFunctions with + class A with + fun f() = 1 +//│ > Define(ClsLikeDefn(ClassSymbol("A"), TODO), End) +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) + // debug printing fails, collision with class name? :fixme class A() staged module A with fun f() = 1 -//│ ═══[RUNTIME ERROR] TypeError: A2.ctor$_instr is not a function +//│ ═══[RUNTIME ERROR] TypeError: A3.ctor$_instr is not a function // debug printing fails, unable to reference the class when calling the instrumented function :fixme @@ -111,15 +117,15 @@ module A with fun f() = 1 //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.110: staged module B with +//│ ║ l.116: staged module B with //│ ║ ^^^^^^ -//│ ║ l.111: fun f() = 1 +//│ ║ l.117: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' //│ ╟── which references the symbol introduced here -//│ ║ l.110: staged module B with +//│ ║ l.116: staged module B with //│ ║ ^^^^^^ -//│ ║ l.111: fun f() = 1 +//│ ║ l.117: fun f() = 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) From 546491a3ef598a836dabf02f5c7838e7f4de464f Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 28 Feb 2026 00:04:02 +0800 Subject: [PATCH 246/268] resolve fixmes --- .../scala/hkmc2/codegen/Instrumentation.scala | 10 +++--- .../test/mlscript/block-staging/Functions.mls | 34 +++++-------------- 2 files changed, 13 insertions(+), 31 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index e2005c4209..4cf3b94266 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -276,12 +276,10 @@ class InstrumentationImpl(using State, Raise): blockCtor("Break", Ls(labelSymbol))(k(_, ctx)) case _ => ??? // not supported - // f.owner returns an InnerSymbol, but we need BlockMemberSymbol of the module to call the function - // so we pass modSym instead - def transformFunDefn(modSym: BlockMemberSymbol, f: FunDefn): (FunDefn, Block) = + def transformFunDefn(f: FunDefn): (FunDefn, Block) = val genSymName = f.sym.nme + "_instr" val genSym = BlockMemberSymbol(genSymName, Nil, false) - val sym = modSym.asPath.selSN(genSymName) + val sym = f.owner.get.asPath.selSN(genSymName) // NOTE: this debug printing only works for top-level modules, nested modules don't work // turn into fundefn @@ -324,10 +322,10 @@ class Instrumentation(using State, Raise) extends BlockTransformer(new SymbolSub val sym = c.sym.subst val companion = c.companion.get val (stagedMethods, debugPrintCode) = companion.methods - .map(impl.transformFunDefn(sym, _)) + .map(impl.transformFunDefn) .unzip val ctor = FunDefn.withFreshSymbol(S(companion.isym), BlockMemberSymbol("ctor$", Nil), Ls(PlainParamList(Nil)), companion.ctor)(false) - val (stagedCtor, ctorPrint) = impl.transformFunDefn(sym, ctor) + val (stagedCtor, ctorPrint) = impl.transformFunDefn(ctor) val unit = State.runtimeSymbol.asPath.selSN("Unit") val debugBlock = (ctorPrint :: debugPrintCode).foldRight(Return(unit, true))(concat) diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index b78d88d38d..3893e109e1 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -42,9 +42,7 @@ staged module ClassInstrumentation with fun inst2() = new NoArg fun app1() = Outside(1) fun app2() = Inside(1, 2) -//│ > Define(ClsLikeDefn(ClassSymbol("NoArg"), TODO), End) -//│ > Define(ClsLikeDefn(ClassSymbol("Inside1":[Symbol("a1"), Symbol("b")]), TODO), End) -//│ > FunDefn(Symbol("ctor$"), ([]), End, true) +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("Inside1":[Symbol("a1"), Symbol("b")]), TODO), Define(ClsLikeDefn(ClassSymbol("NoArg"), TODO), End)), true) //│ > FunDefn(Symbol("inst1"), ([]), Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) //│ > FunDefn(Symbol("inst2"), ([]), Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("NoArg")), []), false), true) //│ > FunDefn(Symbol("app1"), ([]), Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) @@ -71,7 +69,7 @@ staged module Arguments with x fun g(x)(y, z)() = z //│ ╔══[WARNING] Multiple parameter lists are not supported in shape propagation yet. -//│ ║ l.72: fun g(x)(y, z)() = z +//│ ║ l.70: fun g(x)(y, z)() = z //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("f"), ([Symbol("x")]), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)), true) @@ -94,38 +92,24 @@ staged module OtherBlocks with staged module ClassDefs with class A -//│ > Define(ClsLikeDefn(ClassSymbol("A"), TODO), End) -//│ > FunDefn(Symbol("ctor$"), ([]), End, true) +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("A"), TODO), End), true) staged module ClassFunctions with class A with fun f() = 1 -//│ > Define(ClsLikeDefn(ClassSymbol("A"), TODO), End) -//│ > FunDefn(Symbol("ctor$"), ([]), End, true) +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("A"), TODO), End), true) -// debug printing fails, collision with class name? -:fixme + +// name collision class A() staged module A with fun f() = 1 -//│ ═══[RUNTIME ERROR] TypeError: A3.ctor$_instr is not a function +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) +//│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) -// debug printing fails, unable to reference the class when calling the instrumented function -:fixme +// nested module module A with staged module B with fun f() = 1 -//│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' -//│ ╟── which references the symbol introduced here -//│ ║ l.116: staged module B with -//│ ║ ^^^^^^ -//│ ║ l.117: fun f() = 1 -//│ ╙── ^^^^^^^^^^^^^^^ -//│ ╔══[COMPILATION ERROR] No definition found in scope for member 'B' -//│ ╟── which references the symbol introduced here -//│ ║ l.116: staged module B with -//│ ║ ^^^^^^ -//│ ║ l.117: fun f() = 1 -//│ ╙── ^^^^^^^^^^^^^^^ //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) From 0fb3e2e7bd75533034e1a869f19b65a90f94c9e0 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 28 Feb 2026 01:18:21 +0800 Subject: [PATCH 247/268] stage class functions --- .../scala/hkmc2/codegen/Instrumentation.scala | 53 +++++++++++-------- .../src/test/mlscript-compile/Block.mls | 6 +-- .../test/mlscript/block-staging/Functions.mls | 32 +++++++++-- 3 files changed, 63 insertions(+), 28 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 4cf3b94266..cf4d6feece 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -245,11 +245,12 @@ class InstrumentationImpl(using State, Raise): assert(cls.companion.isEmpty, "nested module not supported") transformBlock(rest): p => transformSymbol(cls.isym): c => - optionNone(): none => // TODO: handle companion object - blockCtor("ClsLikeDefn", Ls(c, none)): cls => - blockCtor("Define", Ls(cls, p)): p => - ruleEnd(): end => - fnPrintCode(p)(k(end, ctx)) + // staging the methods within the module + cls.methods.map(transformFunDefn2).collectApply: methods => + tuple(methods): methods => + optionNone(): none => // TODO: handle companion object + blockCtor("ClsLikeDefn", Ls(c, methods, none)): cls => + blockCtor("Define", Ls(cls, p))(k(_, ctx)) case End(_) => ruleEnd()(k(_, ctx)) case Match(p, ks, dflt, rest) => transformPath(p): x => @@ -276,6 +277,19 @@ class InstrumentationImpl(using State, Raise): blockCtor("Break", Ls(labelSymbol))(k(_, ctx)) case _ => ??? // not supported + def transformFunDefn2(f: FunDefn)(using Context)(k: Path => Block): Block = + transformBlock(f.body): body => + if f.params.length != 1 then + raise(WarningReport(msg"Multiple parameter lists are not supported in shape propagation yet." -> f.sym.toLoc :: Nil)) + // maintain parameter names in instrumented code + f.params.map( + _.params.map(p => blockCtor("Symbol", Ls(toValue(p.sym.nme)))).collectApply + ).collectApply: paramListSyms => + blockCtor("Symbol", Ls(toValue(f.sym.nme))): sym => + paramListSyms.map(tuple(_)).collectApply: tups => + tuple(tups): tup => + blockCtor("FunDefn", Ls(sym, tup, body, toValue(true)))(k) + def transformFunDefn(f: FunDefn): (FunDefn, Block) = val genSymName = f.sym.nme + "_instr" val genSym = BlockMemberSymbol(genSymName, Nil, false) @@ -285,20 +299,7 @@ class InstrumentationImpl(using State, Raise): // turn into fundefn val dSym = TermSymbol(f.dSym.k, f.dSym.owner, Tree.Ident(f.sym.nme + "_instr")) val argSyms = f.params.flatMap(_.params).map(_.sym) - val newBody = - val rest = transformBlock(f.body)(using new HashMap): body => - if f.params.length != 1 then - raise(WarningReport(msg"Multiple parameter lists are not supported in shape propagation yet." -> f.sym.toLoc :: Nil)) - // maintain parameter names in instrumented code - f.params.map( - _.params.map(p => blockCtor("Symbol", Ls(toValue(p.sym.nme)))).collectApply - ).collectApply: paramListSyms => - blockCtor("Symbol", Ls(toValue(f.sym.nme))): sym => - paramListSyms.map(tuple(_)).collectApply: tups => - tuple(tups): tup => - blockCtor("FunDefn", Ls(sym, tup, body, toValue(true))): block => - Return(block, false) - Scoped(Set(argSyms*), rest) + val newBody = Scoped(Set(argSyms*), transformFunDefn2(f)(using new HashMap)(Return(_, false))) // TODO: remove it. only for test val debug = call(sym, Nil)(fnPrintCode(_)(End())) @@ -331,8 +332,18 @@ class Instrumentation(using State, Raise) extends BlockTransformer(new SymbolSub val debugBlock = (ctorPrint :: debugPrintCode).foldRight(Return(unit, true))(concat) def debugCont(rest: Block) = Begin(debugBlock, rest) - // stage the constructor - val newCompanion = companion.copy(methods = stagedCtor :: companion.methods ++ stagedMethods, ctor = companion.ctor.mapTail(debugCont)) + // add generator functions for classes within the constructor + val genCls = new BlockTransformer(new SymbolSubst()): + override def applyBlock(b: Block): Block = super.applyBlock(b) match + case Define(c: ClsLikeDefn, rest) if c.companion.isEmpty => + val (stagedMethods, debugPrintCode) = c.methods + .map(impl.transformFunDefn) + .unzip + val newModule = c.copy(methods = c.methods ++ stagedMethods) + Define(newModule, rest) + case b => b + val newCtor = genCls.applyBlock(companion.ctor) + val newCompanion = companion.copy(methods = stagedCtor :: companion.methods ++ stagedMethods, ctor = newCtor.mapTail(debugCont)) val newModule = c.copy(sym = sym, companion = S(newCompanion)) Define(newModule, rest) case b => b diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 425005973c..a73e74384f 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -45,7 +45,7 @@ class Path extends Result with class Defn with constructor ValDefn(val sym: Symbol, val rhs: Path) - ClsLikeDefn(val sym: ClassSymbol, val companion: Opt[ClsLikeBody]) // companion unused + ClsLikeDefn(val sym: ClassSymbol, val methods: Array[FunDefn], val companion: Opt[ClsLikeBody]) // companion unused FunDefn(val sym: Symbol, val params: Array[ParamList], val body: Block, val stage: Bool) class ClsLikeBody(val isym: Symbol, val methods: Array[FunDefn], val publicFields: Array[[Symbol, Symbol]]) // unused @@ -141,9 +141,9 @@ fun showDefn(d: Defn): Str = "(" + params.map(showParamList) + "), " + showBlock(body) + ", " + stage + ")" - ClsLikeDefn(sym, companion) then + ClsLikeDefn(sym, methods, companion) then // TODO: print rest of the arguments - "ClsLikeDefn(" + showSymbol(sym) + ", " + "TODO" + ")" + "ClsLikeDefn(" + showSymbol(sym) + ", [" + methods.map(showDefn) + "], TODO" + ")" fun showOptBlock(ob: Opt[Block]) = if ob is Some(b) then showBlock(b) else "None" diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 3893e109e1..f18a78625f 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -42,7 +42,7 @@ staged module ClassInstrumentation with fun inst2() = new NoArg fun app1() = Outside(1) fun app2() = Inside(1, 2) -//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("Inside1":[Symbol("a1"), Symbol("b")]), TODO), Define(ClsLikeDefn(ClassSymbol("NoArg"), TODO), End)), true) +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("Inside1":[Symbol("a1"), Symbol("b")]), [], TODO), Define(ClsLikeDefn(ClassSymbol("NoArg"), [], TODO), End)), true) //│ > FunDefn(Symbol("inst1"), ([]), Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) //│ > FunDefn(Symbol("inst2"), ([]), Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("NoArg")), []), false), true) //│ > FunDefn(Symbol("app1"), ([]), Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) @@ -71,6 +71,31 @@ staged module Arguments with //│ ╔══[WARNING] Multiple parameter lists are not supported in shape propagation yet. //│ ║ l.70: fun g(x)(y, z)() = z //│ ╙── ^^^^^^^^^^^^^^^^^^^^ +//│ FAILURE: Unexpected compilation error +//│ FAILURE LOCATION: lookup_! (Scope.scala:114) +//│ FAILURE INFO: Tuple2: +//│ _1 = Tuple2: +//│ _1 = x +//│ _2 = class hkmc2.semantics.VarSymbol +//│ _2 = Scope: +//│ parent = S of Scope: +//│ parent = S of Scope: +//│ parent = S of Scope: +//│ parent = N +//│ curThis = S of S of globalThis:globalThis +//│ bindings = HashMap($block$res -> block$res3, class:Nonstaged -> Nonstaged, class:Staged -> Staged, $runtime -> runtime, $definitionMetadata -> definitionMetadata, $block$res -> block$res2, $prettyPrint -> prettyPrint, class:ClassInstrumentation -> ClassInstrumentation, $Term -> Term, $Block -> Block, $option -> option, member:Predef -> Predef, $block$res -> block$res1, $tmp -> tmp, class:Expressions -> Expressions, member:CallSubst -> CallSubst1, module:CallSubst -> CallSubst, member:Arguments -> Arguments1, module:Arguments -> Arguments, member:ClassInstrumentation -> ClassInstrumentation1, member:Outside -> Outside1, class:Outside -> Outside, $block$res -> block$res4, class:CallSubst -> CallSubst, $block$res -> block$res, module:ClassInstrumentation -> ClassInstrumentation, class:Inside -> Inside, $block$res -> block$res5, class:Arguments -> Arguments, member:x -> x, member:Expressions -> Expressions1, member:Staged -> Staged1, class:NoArg -> NoArg, member:Nonstaged -> Nonstaged1, module:Nonstaged -> Nonstaged, module:Expressions -> Expressions, module:Staged -> Staged) +//│ curThis = S of S of module:Arguments +//│ bindings = HashMap() +//│ curThis = N +//│ bindings = HashMap($args -> args) +//│ curThis = N +//│ bindings = HashMap($lit -> lit, $sym -> sym, $tmp -> tmp1, $return -> return1, $assign -> assign, $tmp -> tmp2, $tmp -> tmp3, $tmp -> tmp4, $tmp -> tmp5, $tmp -> tmp6) +//│ ╔══[COMPILATION ERROR] No definition found in scope for member 'x' +//│ ║ l.67: fun f(x) = +//│ ║ ^ +//│ ╟── which references the symbol introduced here +//│ ║ l.67: fun f(x) = +//│ ╙── ^ //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("f"), ([Symbol("x")]), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)), true) //│ > FunDefn(Symbol("g"), ([Symbol("x")],[Symbol("y"), Symbol("z")],[]), Return(Ref(Symbol("z")), false), true) @@ -92,13 +117,12 @@ staged module OtherBlocks with staged module ClassDefs with class A -//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("A"), TODO), End), true) +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("A"), [], TODO), End), true) staged module ClassFunctions with class A with fun f() = 1 -//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("A"), TODO), End), true) - +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("A"), [FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true)], TODO), End), true) // name collision class A() From f2a1ad13ae96acb79df03e1b1972464ee3cc8299 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Sat, 28 Feb 2026 17:19:46 +0800 Subject: [PATCH 248/268] update tests --- .../main/scala/hkmc2/codegen/Printer.scala | 3 +- .../test/mlscript/block-staging/Functions.mls | 31 ++----------------- .../test/mlscript/block-staging/Syntax.mls | 2 +- 3 files changed, 5 insertions(+), 31 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index 59ca5e756b..08bdf35a6c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -107,7 +107,6 @@ object Printer: val auxClsParams = auxParams.flatMap(_.paramSyms) val ctorParams = (clsParams ++ auxClsParams).map(p => summon[Scope].allocateName(p)) val docCtorParams = if clsParams.isEmpty then doc"" else doc"(${ctorParams.mkDocument(", ")})" - val docStaged = if isym.defn.forall(_.hasStagedModifier.isEmpty) then doc"" else doc"staged " val docBody = mkDocument(privateFields, publicFields, methods, S(preCtor), ctor) val docPreCtor = mkDocument(preCtor) val docCtor = mkDocument(ctor) @@ -116,7 +115,7 @@ object Printer: case Pat => "pattern" case Obj => "object" case Mod => "module" - val docCls = doc"${docStaged}${clsType} ${own.fold("")(_.toString+"::")}${sym.nme}${docCtorParams}${docBody}" + val docCls = doc"${clsType} ${own.fold("")(_.toString+"::")}${sym.nme}${docCtorParams}${docBody}" val docModule = mod match case Some(mod) => val docStaged = if mod.isym.defn.forall(_.hasStagedModifier.isEmpty) then doc"" else doc"staged " diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index f18a78625f..5e2a037dd2 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -31,7 +31,7 @@ staged module Expressions with //│ > FunDefn(Symbol("tup2"), ([]), Return(Tuple([Lit(1), ..Ref(Symbol("x1"))]), false), true) //│ > FunDefn(Symbol("dynsel"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false))), true) //│ > FunDefn(Symbol("match1"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))), true) -//│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("element1$"), Symbol("scrut1"), Symbol("a"), Symbol("tmp1"), Symbol("middleElements"), Symbol("element0$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Label(Symbol("split_2$"), false, Assign(Symbol("scrut1"), Tuple([...Ref(Symbol("x1"))]), Match(Ref(Symbol("scrut1")), [Tup(0, false) -> Assign(Symbol("tmp1"), Lit(1), Break(Symbol("split_root$"))), Tup(2, false) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp1"), Lit(2), Break(Symbol("split_root$")))], Match(Ref(Symbol("scrut1")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End)], Match(Ref(Symbol("scrut1")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End))), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$")))))], Break(Symbol("split_2$")), End)), Assign(Symbol("tmp1"), Lit(0), Break(Symbol("split_root$")))NaN, Assign(Symbol("tmp1"), Lit(3), End)NaN, Return(Ref(Symbol("tmp1")), false)NaN), true) +//│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("scrut1"), Symbol("a"), Symbol("tmp1"), Symbol("middleElements"), Symbol("element0$"), Symbol("element1$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Label(Symbol("split_2$"), false, Assign(Symbol("scrut1"), Tuple([...Ref(Symbol("x1"))]), Match(Ref(Symbol("scrut1")), [Tup(0, false) -> Assign(Symbol("tmp1"), Lit(1), Break(Symbol("split_root$"))), Tup(2, false) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp1"), Lit(2), Break(Symbol("split_root$")))], Match(Ref(Symbol("scrut1")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End)], Match(Ref(Symbol("scrut1")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End))), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$")))))], Break(Symbol("split_2$")), End)), Assign(Symbol("tmp1"), Lit(0), Break(Symbol("split_root$")))NaN, Assign(Symbol("tmp1"), Lit(3), End)NaN, Return(Ref(Symbol("tmp1")), false)NaN), true) //│ x = [1, 2, 3] class Outside(a) @@ -60,7 +60,7 @@ staged module CallSubst with Nonstaged.f() Staged.f() //│ > FunDefn(Symbol("ctor$"), ([]), End, true) -//│ > FunDefn(Symbol("call"), ([]), Scoped([Symbol("tmp"), Symbol("tmp1")], Assign(Symbol("tmp"), Call(Ref(Symbol("+")), [Lit(1), Lit(1)]), Assign(Symbol("tmp1"), Call(Select(Ref(Symbol("Nonstaged")), Symbol("f")), []), Return(Call(Select(Ref(Symbol("Staged")), Symbol("f_gen")), []), false)))), true) +//│ > FunDefn(Symbol("call"), ([]), Assign(Symbol("$_no$_symbol$_"), Call(Ref(Symbol("+")), [Lit(1), Lit(1)]), Assign(Symbol("$_no$_symbol$_"), Call(Select(Ref(Symbol("Nonstaged")), Symbol("f")), []), Return(Call(Select(Ref(Symbol("Staged")), Symbol("f_gen")), []), false))), true) :w staged module Arguments with @@ -71,31 +71,6 @@ staged module Arguments with //│ ╔══[WARNING] Multiple parameter lists are not supported in shape propagation yet. //│ ║ l.70: fun g(x)(y, z)() = z //│ ╙── ^^^^^^^^^^^^^^^^^^^^ -//│ FAILURE: Unexpected compilation error -//│ FAILURE LOCATION: lookup_! (Scope.scala:114) -//│ FAILURE INFO: Tuple2: -//│ _1 = Tuple2: -//│ _1 = x -//│ _2 = class hkmc2.semantics.VarSymbol -//│ _2 = Scope: -//│ parent = S of Scope: -//│ parent = S of Scope: -//│ parent = S of Scope: -//│ parent = N -//│ curThis = S of S of globalThis:globalThis -//│ bindings = HashMap($block$res -> block$res3, class:Nonstaged -> Nonstaged, class:Staged -> Staged, $runtime -> runtime, $definitionMetadata -> definitionMetadata, $block$res -> block$res2, $prettyPrint -> prettyPrint, class:ClassInstrumentation -> ClassInstrumentation, $Term -> Term, $Block -> Block, $option -> option, member:Predef -> Predef, $block$res -> block$res1, $tmp -> tmp, class:Expressions -> Expressions, member:CallSubst -> CallSubst1, module:CallSubst -> CallSubst, member:Arguments -> Arguments1, module:Arguments -> Arguments, member:ClassInstrumentation -> ClassInstrumentation1, member:Outside -> Outside1, class:Outside -> Outside, $block$res -> block$res4, class:CallSubst -> CallSubst, $block$res -> block$res, module:ClassInstrumentation -> ClassInstrumentation, class:Inside -> Inside, $block$res -> block$res5, class:Arguments -> Arguments, member:x -> x, member:Expressions -> Expressions1, member:Staged -> Staged1, class:NoArg -> NoArg, member:Nonstaged -> Nonstaged1, module:Nonstaged -> Nonstaged, module:Expressions -> Expressions, module:Staged -> Staged) -//│ curThis = S of S of module:Arguments -//│ bindings = HashMap() -//│ curThis = N -//│ bindings = HashMap($args -> args) -//│ curThis = N -//│ bindings = HashMap($lit -> lit, $sym -> sym, $tmp -> tmp1, $return -> return1, $assign -> assign, $tmp -> tmp2, $tmp -> tmp3, $tmp -> tmp4, $tmp -> tmp5, $tmp -> tmp6) -//│ ╔══[COMPILATION ERROR] No definition found in scope for member 'x' -//│ ║ l.67: fun f(x) = -//│ ║ ^ -//│ ╟── which references the symbol introduced here -//│ ║ l.67: fun f(x) = -//│ ╙── ^ //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("f"), ([Symbol("x")]), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)), true) //│ > FunDefn(Symbol("g"), ([Symbol("x")],[Symbol("y"), Symbol("z")],[]), Return(Ref(Symbol("z")), false), true) @@ -113,7 +88,7 @@ staged module OtherBlocks with else 0 //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("scope"), ([]), Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))), true) -//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("tmp"), Symbol("scrut")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) +//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("scrut"), Symbol("tmp")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) staged module ClassDefs with class A diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls index 6b18ffef62..0de1d16765 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls @@ -20,4 +20,4 @@ staged fun f() = 0 :slot staged module A //│ Pretty Lowered: -//│ define staged class A with staged module A in set block$res = undefined in end +//│ define class A with staged module A in set block$res = undefined in end From 01dd129ed1bc4a611ed6549d81a3b443096e296c Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Wed, 4 Mar 2026 23:44:55 +0800 Subject: [PATCH 249/268] always enable staging --- .../main/scala/hkmc2/codegen/Lowering.scala | 4 +--- .../test/mlscript/block-staging/Functions.mls | 4 ++-- .../test/mlscript/block-staging/Syntax.mls | 24 ++++++++++++++++++- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index bef1a63f5c..2162c63bf0 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -1096,9 +1096,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): if config.funcToCls then Lifter(FirstClassFunctionTransformer().transform(merged)).transform else merged - val staged = - if config.stageCode then Instrumentation(using summon).applyBlock(funcToCls) - else funcToCls + val staged = Instrumentation(using summon).applyBlock(funcToCls) val res = if config.tailRecOpt then TailRecOpt().transform(staged) diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 5e2a037dd2..78b16cd31e 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -31,7 +31,7 @@ staged module Expressions with //│ > FunDefn(Symbol("tup2"), ([]), Return(Tuple([Lit(1), ..Ref(Symbol("x1"))]), false), true) //│ > FunDefn(Symbol("dynsel"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false))), true) //│ > FunDefn(Symbol("match1"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))), true) -//│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("scrut1"), Symbol("a"), Symbol("tmp1"), Symbol("middleElements"), Symbol("element0$"), Symbol("element1$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Label(Symbol("split_2$"), false, Assign(Symbol("scrut1"), Tuple([...Ref(Symbol("x1"))]), Match(Ref(Symbol("scrut1")), [Tup(0, false) -> Assign(Symbol("tmp1"), Lit(1), Break(Symbol("split_root$"))), Tup(2, false) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp1"), Lit(2), Break(Symbol("split_root$")))], Match(Ref(Symbol("scrut1")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End)], Match(Ref(Symbol("scrut1")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End))), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$")))))], Break(Symbol("split_2$")), End)), Assign(Symbol("tmp1"), Lit(0), Break(Symbol("split_root$")))NaN, Assign(Symbol("tmp1"), Lit(3), End)NaN, Return(Ref(Symbol("tmp1")), false)NaN), true) +//│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("tmp1"), Symbol("middleElements"), Symbol("element0$"), Symbol("element1$"), Symbol("scrut1"), Symbol("a")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Label(Symbol("split_2$"), false, Assign(Symbol("scrut1"), Tuple([...Ref(Symbol("x1"))]), Match(Ref(Symbol("scrut1")), [Tup(0, false) -> Assign(Symbol("tmp1"), Lit(1), Break(Symbol("split_root$"))), Tup(2, false) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp1"), Lit(2), Break(Symbol("split_root$")))], Match(Ref(Symbol("scrut1")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End)], Match(Ref(Symbol("scrut1")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End))), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$")))))], Break(Symbol("split_2$")), End)), Assign(Symbol("tmp1"), Lit(0), Break(Symbol("split_root$")))NaN, Assign(Symbol("tmp1"), Lit(3), End)NaN, Return(Ref(Symbol("tmp1")), false)NaN), true) //│ x = [1, 2, 3] class Outside(a) @@ -88,7 +88,7 @@ staged module OtherBlocks with else 0 //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("scope"), ([]), Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))), true) -//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("scrut"), Symbol("tmp")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) +//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("tmp"), Symbol("scrut")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) staged module ClassDefs with class A diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls b/hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls index 0de1d16765..f4fa9c3ba3 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Syntax.mls @@ -18,6 +18,28 @@ staged fun f() = 0 :js :slot +:staging staged module A //│ Pretty Lowered: -//│ define class A with staged module A in set block$res = undefined in end +//│ +//│ define class A with +//│ staged module A { +//│ ctor { +//│ begin +//│ set tmp = A.ctor$_instr(); +//│ set tmp1 = ‹not in scope: $Block›.printCode(tmp); +//│ return ‹not in scope: $runtime›.Unit; +//│ end +//│ } +//│ fun module:A::ctor$_instr() { +//│ set end = new ‹not in scope: $Block›.End(); +//│ set tmp2 = new ‹not in scope: $Block›.Symbol("ctor$"); +//│ set tmp3 = []; +//│ set tmp4 = [tmp3]; +//│ set tmp5 = new ‹not in scope: $Block›.FunDefn(tmp2, tmp4, end, true); +//│ return tmp5 +//│ } +//│ }; +//│ set block$res = undefined; +//│ end +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) From cd235684e8e53047ce5d1f9900901db5135d63cb Mon Sep 17 00:00:00 2001 From: Ching Long Tin <26105652+ChingLongTin@users.noreply.github.com> Date: Fri, 6 Mar 2026 10:28:13 +0800 Subject: [PATCH 250/268] Update hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala Co-authored-by: Fa1sePRoMiSe --- hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index cf4d6feece..5dafd7d56e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -22,7 +22,7 @@ class InstrumentationImpl(using State, Raise): type ArgWrappable = Path | Symbol type Context = HashMap[Path, Path] // TODO: there could be a fresh scope per function body, instead of a single one for the entire program - var scope = Scope.empty + val scope = Scope.empty def asArg(x: ArgWrappable): Arg = x match From 628218e8adbbac6e597d2b705e61b449673a5532 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:18:13 +0800 Subject: [PATCH 251/268] replace ??? with ErrorReport --- .../scala/hkmc2/codegen/Instrumentation.scala | 28 ++++++++++--------- .../test/mlscript/block-staging/Functions.mls | 14 ++++++++++ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index cf4d6feece..8a8cc7df50 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -162,7 +162,9 @@ class InstrumentationImpl(using State, Raise): transformPath(qual): x => transformPath(fld): y => blockCtor("DynSelect", Ls(x, y, toValue(arrayIdx)), "dynsel")(k) - case _ => ??? // not supported + case _: Value.This => + raise(ErrorReport(msg"Value.This not supported in staged module." -> p.toLoc :: Nil)) + End() def transformResult(r: Result)(using Context)(k: Path => Block): Block = r match @@ -197,7 +199,9 @@ class InstrumentationImpl(using State, Raise): transformArgs(args): args => tuple(args.map(_._1)): tup => blockCtor("Call", Ls(fun, tup), "app")(k) - case _ => ??? // not supported + case _ => + raise(ErrorReport(msg"Other Results not supported in staged module: ${r.toString()}" -> r.toLoc :: Nil)) + End() def transformArg(a: Arg)(using Context)(k: ((Path, Bool)) => Block): Block = val Arg(spread, value) = a @@ -223,7 +227,9 @@ class InstrumentationImpl(using State, Raise): transformPath(path): path => blockCtor("Cls", Ls(cls, path))(k) case Case.Tup(len, inf) => blockCtor("Tup", Ls(len, inf).map(toValue))(k) - case Case.Field(name, safe) => ??? // not supported + case Case.Field(name, safe) => + raise(ErrorReport(msg"Case.Field not supported in staged module." -> name.toLoc :: Nil)) + End() def transformBlock(b: Block)(using Context)(k: Path => Block): Block = transformBlock(b)((p, _) => k(p)) @@ -275,7 +281,9 @@ class InstrumentationImpl(using State, Raise): case Break(labelSymbol) => transformSymbol(labelSymbol): labelSymbol => blockCtor("Break", Ls(labelSymbol))(k(_, ctx)) - case _ => ??? // not supported + case _ => + raise(ErrorReport(msg"Other Blocks not supprted in staged module: ${b.toString()}" -> N :: Nil)) + End() def transformFunDefn2(f: FunDefn)(using Context)(k: Path => Block): Block = transformBlock(f.body): body => @@ -290,7 +298,7 @@ class InstrumentationImpl(using State, Raise): tuple(tups): tup => blockCtor("FunDefn", Ls(sym, tup, body, toValue(true)))(k) - def transformFunDefn(f: FunDefn): (FunDefn, Block) = + def transformFunDefn(f: FunDefn): (FunDefn, Block => Block) = val genSymName = f.sym.nme + "_instr" val genSym = BlockMemberSymbol(genSymName, Nil, false) val sym = f.owner.get.asPath.selSN(genSymName) @@ -302,7 +310,7 @@ class InstrumentationImpl(using State, Raise): val newBody = Scoped(Set(argSyms*), transformFunDefn2(f)(using new HashMap)(Return(_, false))) // TODO: remove it. only for test - val debug = call(sym, Nil)(fnPrintCode(_)(End())) + val debug = (k: Block) => call(sym, Nil)(fnPrintCode(_)(k)) val newFun = f.copy(sym = genSym, dSym = dSym, params = Ls(PlainParamList(Nil)), body = newBody)(false) (newFun, debug) @@ -310,12 +318,6 @@ class InstrumentationImpl(using State, Raise): class Instrumentation(using State, Raise) extends BlockTransformer(new SymbolSubst()): val impl = new InstrumentationImpl - def concat(b1: Block, b2: Block): Block = - b1.mapTail { - case _: End => b2 - case _ => ??? - } - override def applyBlock(b: Block): Block = super.applyBlock(b) match // find modules with staged annotation @@ -329,7 +331,7 @@ class Instrumentation(using State, Raise) extends BlockTransformer(new SymbolSub val (stagedCtor, ctorPrint) = impl.transformFunDefn(ctor) val unit = State.runtimeSymbol.asPath.selSN("Unit") - val debugBlock = (ctorPrint :: debugPrintCode).foldRight(Return(unit, true))(concat) + val debugBlock = (ctorPrint :: debugPrintCode).foldRight((Return(unit, true): Block))(_(_)) def debugCont(rest: Block) = Begin(debugBlock, rest) // add generator functions for classes within the constructor diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 78b16cd31e..a1ab0546b4 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -112,3 +112,17 @@ module A with fun f() = 1 //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) + +:e +class C(val a) +staged module A with + let x = C(1) + fun f() = set x.a = 0 + fun g() = {1 : 2} +//│ ═══[COMPILATION ERROR] Other Blocks not supprted in staged module: AssignField(Ref(term:module:A.x,None),Ident(a),Lit(IntLit(0)),Return(Select(Ref($runtime,None),Ident(Unit)),false)) +//│ ╔══[COMPILATION ERROR] Other Results not supported in staged module: Record(false,List(RcdArg(Some(Lit(IntLit(1))),Lit(IntLit(2))))) +//│ ║ l.121: fun g() = {1 : 2} +//│ ╙── ^ +//│ > FunDefn(Symbol("ctor$"), ([]), Assign(Symbol("x"), Call(Ref(ClassSymbol("C1":[Symbol("a")])), [Lit(1)]), End), true) +//│ ═══[RUNTIME ERROR] Error: MLscript call unexpectedly returned `undefined`, the forbidden value. + From cd94b6e00bc3d2b11c67f4f1710b5cb863df7603 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:21:19 +0800 Subject: [PATCH 252/268] cleanup --- .../main/scala/hkmc2/codegen/Lowering.scala | 11 ---------- .../src/test/mlscript-compile/Shape.mls | 21 ------------------- 2 files changed, 32 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index 2162c63bf0..86a72aff8d 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -273,17 +273,6 @@ class Lowering()(using Config, TL, Raise, State, Ctx): val stagedAnnots = mod.annotations.collect { case Annot.Modifier(Keyword.`staged`) => Annot.Modifier(Keyword.`staged`) } - // val newDefn = ClassDef.Plain(mod.owner, syntax.Cls, clsSymb, - // mod.bsym, - // Nil, - // N, - // ObjBody(Blk(Nil, UnitVal())), - // S(mod.sym), - // stagedAnnots - // ) - // clsSymb.defn = S(newDefn) - // newDefn - ClassDef.Plain(mod.owner, syntax.Cls, new ClassSymbol(Tree.DummyTypeDef(syntax.Cls), mod.sym.id), mod.bsym, Nil, diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index 0b724cfcd7..531ebc2914 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -38,27 +38,6 @@ fun show(s: Shape) = Arr(shapes, inf) then "Arr([" + shapes.map(show).join(", ") + "], " + inf + ")" Class(sym, params) then "Class(" + showSymbol(sym) + ", [" + params.map(show).join(", ") + "])" -fun zipMrg[A](a: Array[A], b: Array[A]): Array[A] = - a.map((a, i, _) => mrg2(a, b.at(i))) - -// TODO: remove, this is no longer in use -fun mrg2(s1: Shape, s2: Shape) = - if s1 == s2 then s1 - else if [s1, s2] is - [Lit(l), Class(sym, params)] - and isPrimitiveTypeOf(sym, l) - then Class(sym, params) - [Class(sym1, ps), Class(sym2, s2)] - and sym1.name == sym2.name - then Class(sym1, ps.map(p => [p.0, zipMrg(p.1, s2)])) - [Arr(s1, false), Arr(s2, false)] - and s1.length == s2.length - then Arr(zipMrg(s1, s2), false) - else Dyn() - -fun mrg(s1: Array[Shape]) = - s1.reduceRight((acc, s, _, _) => mrg2(s, acc)) - fun sel(s1: Shape, s2: Shape): Array[Shape] = if [s1, s2] is [Class(sym, params), Lit(n)] and n is Str From 5170e25efe8c5a4af563cf1773781a13a3e996a5 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:43:39 +0800 Subject: [PATCH 253/268] remove some crashes from .get --- .../scala/hkmc2/codegen/Instrumentation.scala | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 06fb3f89a9..7154b18d3e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -94,9 +94,14 @@ class InstrumentationImpl(using State, Raise): def transformSymbol(sym: Symbol, symName: Str = "sym")(k: Path => Block): Block = sym match case clsSym: ClassSymbol => - val name = scope.allocateOrGetName(sym) - transformParamsOpt(clsSym.defn.get.paramsOpt): paramsOpt => - blockCtor("ClassSymbol", Ls(toValue(name), paramsOpt), symName)(k) + clsSym.defn match + case S(defn) => + val name = scope.allocateOrGetName(sym) + transformParamsOpt(defn.paramsOpt): paramsOpt => + blockCtor("ClassSymbol", Ls(toValue(name), paramsOpt), symName)(k) + case N => + raise(ErrorReport(msg"Unable to infer parameters from ClassSymbol in staged module, which are necessary to reconstruct class instances." -> sym.toLoc :: Nil)) + End() case t: TermSymbol if t.defn.exists(_.sym.asCls.isDefined) => val name = scope.allocateOrGetName(sym) transformSymbol(t.defn.get.sym.asCls.get, symName)(k) @@ -150,12 +155,10 @@ class InstrumentationImpl(using State, Raise): blockCtor("ValueRef", Ls(sym), "var")(k) case l: Value.Lit => blockCtor("ValueLit", Ls(l), "lit")(k) - case s @ Select(p, i @ Tree.Ident(name)) => + case s @ Select(p, Tree.Ident(name)) => transformPath(p): x => - val sym = - if s.symbol.isDefined - then transformSymbol(s.symbol.get) - else blockCtor("Symbol", Ls(toValue(name))) + val sym = s.symbol.map(transformSymbol(_)) + .getOrElse(blockCtor("Symbol", Ls(toValue(name)))) sym: sym => blockCtor("Select", Ls(x, sym), "sel")(k) case DynSelect(qual, fld, arrayIdx) => @@ -184,11 +187,10 @@ class InstrumentationImpl(using State, Raise): val stagedFunPath = fun match case s @ Select(qual, Tree.Ident(name)) => s.symbol.flatMap({ - case t: TermSymbol => t.owner.flatMap({ - case sym: DefinitionSymbol[?] => - sym.defn.get.hasStagedModifier.map(_ => - Select(qual, Tree.Ident(name + "_gen"))(N) - ) + case t: TermSymbol => t.owner.flatMap({ case sym: DefinitionSymbol[?] => + sym.defn.flatMap(_.hasStagedModifier.map(_ => + Select(qual, Tree.Ident(name + "_gen"))(N) + )) }) case _ => N }) From 3cb2ebb889ee20b20a744b7570b3bdf650663b41 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:57:27 +0800 Subject: [PATCH 254/268] rename transformFunDefn --- .../scala/hkmc2/codegen/Instrumentation.scala | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 7154b18d3e..7d371a6373 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -254,7 +254,7 @@ class InstrumentationImpl(using State, Raise): transformBlock(rest): p => transformSymbol(cls.isym): c => // staging the methods within the module - cls.methods.map(transformFunDefn2).collectApply: methods => + cls.methods.map(transformFunDefn).collectApply: methods => tuple(methods): methods => optionNone(): none => // TODO: handle companion object blockCtor("ClsLikeDefn", Ls(c, methods, none)): cls => @@ -287,7 +287,7 @@ class InstrumentationImpl(using State, Raise): raise(ErrorReport(msg"Other Blocks not supprted in staged module: ${b.toString()}" -> N :: Nil)) End() - def transformFunDefn2(f: FunDefn)(using Context)(k: Path => Block): Block = + def transformFunDefn(f: FunDefn)(using Context)(k: Path => Block): Block = transformBlock(f.body): body => if f.params.length != 1 then raise(WarningReport(msg"Multiple parameter lists are not supported in shape propagation yet." -> f.sym.toLoc :: Nil)) @@ -300,16 +300,15 @@ class InstrumentationImpl(using State, Raise): tuple(tups): tup => blockCtor("FunDefn", Ls(sym, tup, body, toValue(true)))(k) - def transformFunDefn(f: FunDefn): (FunDefn, Block => Block) = + def applyFunDefn(f: FunDefn): (FunDefn, Block => Block) = val genSymName = f.sym.nme + "_instr" val genSym = BlockMemberSymbol(genSymName, Nil, false) val sym = f.owner.get.asPath.selSN(genSymName) - // NOTE: this debug printing only works for top-level modules, nested modules don't work // turn into fundefn val dSym = TermSymbol(f.dSym.k, f.dSym.owner, Tree.Ident(f.sym.nme + "_instr")) val argSyms = f.params.flatMap(_.params).map(_.sym) - val newBody = Scoped(Set(argSyms*), transformFunDefn2(f)(using new HashMap)(Return(_, false))) + val newBody = Scoped(Set(argSyms*), transformFunDefn(f)(using new HashMap)(Return(_, false))) // TODO: remove it. only for test val debug = (k: Block) => call(sym, Nil)(fnPrintCode(_)(k)) @@ -327,10 +326,10 @@ class Instrumentation(using State, Raise) extends BlockTransformer(new SymbolSub val sym = c.sym.subst val companion = c.companion.get val (stagedMethods, debugPrintCode) = companion.methods - .map(impl.transformFunDefn) + .map(impl.applyFunDefn) .unzip val ctor = FunDefn.withFreshSymbol(S(companion.isym), BlockMemberSymbol("ctor$", Nil), Ls(PlainParamList(Nil)), companion.ctor)(false) - val (stagedCtor, ctorPrint) = impl.transformFunDefn(ctor) + val (stagedCtor, ctorPrint) = impl.applyFunDefn(ctor) val unit = State.runtimeSymbol.asPath.selSN("Unit") val debugBlock = (ctorPrint :: debugPrintCode).foldRight((Return(unit, true): Block))(_(_)) @@ -341,7 +340,7 @@ class Instrumentation(using State, Raise) extends BlockTransformer(new SymbolSub override def applyBlock(b: Block): Block = super.applyBlock(b) match case Define(c: ClsLikeDefn, rest) if c.companion.isEmpty => val (stagedMethods, debugPrintCode) = c.methods - .map(impl.transformFunDefn) + .map(impl.applyFunDefn) .unzip val newModule = c.copy(methods = c.methods ++ stagedMethods) Define(newModule, rest) From 6acee7120bf1cc6cda2e455e25a6d21e04c8bdf1 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 6 Mar 2026 16:00:09 +0800 Subject: [PATCH 255/268] remove inf parameter form Shape.Arr and Block.Tup --- .../scala/hkmc2/codegen/Instrumentation.scala | 13 +++++++--- .../src/test/mlscript-compile/Block.mls | 12 +++------ .../src/test/mlscript-compile/Shape.mls | 22 ++++++---------- .../test/mlscript/block-staging/Functions.mls | 25 ++++++++++++------- 4 files changed, 38 insertions(+), 34 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 7d371a6373..f1639880ec 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -207,9 +207,12 @@ class InstrumentationImpl(using State, Raise): def transformArg(a: Arg)(using Context)(k: ((Path, Bool)) => Block): Block = val Arg(spread, value) = a - transformOption(spread, bool => assign(toValue(bool))): spreadStaged => + if spread.isDefined then + raise(ErrorReport(msg"Spread parameters are not supported in staged module: ${a.toString()}" -> N :: Nil)) + End() + else transformPath(value): value => - blockCtor("Arg", Ls(spreadStaged, value)): cde => + blockCtor("Arg", Ls(value)): cde => k(cde, spread.isDefined) def transformArgs(args: Ls[Arg])(using Context)(k: Ls[(Path, Bool)] => Block): Block = @@ -228,7 +231,11 @@ class InstrumentationImpl(using State, Raise): transformSymbol(cls): cls => transformPath(path): path => blockCtor("Cls", Ls(cls, path))(k) - case Case.Tup(len, inf) => blockCtor("Tup", Ls(len, inf).map(toValue))(k) + case Case.Tup(len, true) => + raise(ErrorReport(msg"Spread parameters are not supported in staged module: ${cse.toString()}" -> N :: Nil)) + End() + case Case.Tup(len, false) => + blockCtor("Tup", Ls(toValue(len)))(k) case Case.Field(name, safe) => raise(ErrorReport(msg"Case.Field not supported in staged module." -> name.toLoc :: Nil)) End() diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index a73e74384f..f643643cbd 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -21,13 +21,13 @@ type Ident = Symbol // this is so that we're able to retrieve information about the class from the symbol class ClassSymbol(val name: Str, val paramsOpt: Opt[ParamList]) extends Symbol(name) -class Arg(val spread: Opt[Bool], val value: Path) +class Arg(val value: Path) class Case with constructor Lit(val lit: Literal) Cls(val cls: Symbol, val path: Path) - Tup(val len: Int, val inf: Bool) + Tup(val len: Int) class Result with constructor @@ -106,11 +106,7 @@ fun showPath(p: Path): Str = "Lit(" + showLiteral(lit) + ")" fun showArg(arg: Arg) = - if arg.spread is - Some(true) then "..." - Some(false) then ".." - else "" - + showPath(arg.value) + showPath(arg.value) fun showArgs(args: Array[Arg]) = "[" + args.map(showArg).join(", ") + "]" @@ -120,7 +116,7 @@ fun showCase(c: Case): Str = if c is Lit(lit) then "Lit(" + showLiteral(lit) + ")" Cls(cls, path) then "Cls(" + showSymbol(cls) + ", " + showPath(path) + ")" - Tup(len, inf) then "Tup(" + len + ", " + inf + ")" + Tup(len) then "Tup(" + len + ")" fun showResult(r: Result): Str = if r is diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index 531ebc2914..70c935ec8f 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -28,14 +28,14 @@ class Shape with constructor Dyn() Lit(val l: Literal) - Arr(val shapes: Array[Shape], val inf: Bool) + Arr(val shapes: Array[Shape]) Class(val sym: ClassSymbol, val params: Array[Shape]) fun show(s: Shape) = if s is Dyn then "Dyn" Lit(lit) then "Lit(" + Block.showLiteral(lit) + ")" - Arr(shapes, inf) then "Arr([" + shapes.map(show).join(", ") + "], " + inf + ")" + Arr(shapes) then "Arr(" + shapes.map(show).join(", ") + ")" Class(sym, params) then "Class(" + showSymbol(sym) + ", [" + params.map(show).join(", ") + "])" fun sel(s1: Shape, s2: Shape): Array[Shape] = @@ -47,11 +47,10 @@ fun sel(s1: Shape, s2: Shape): Array[Shape] = is i then [params.(i)] [Dyn, Lit(n)] and n is Str then [Dyn()] - [Arr(shapes, false), Lit(n)] and n is Int + [Arr(shapes), Lit(n)] and n is Int then [shapes.(n)] - [Arr(shapes, false), Dyn] then + [Arr(shapes), Dyn] then shapes - [Arr(shapes, true), _] then [Dyn()] // TODO [Dyn, Lit(n)] and n is Int then [Dyn()] [Dyn, Dyn] @@ -63,8 +62,7 @@ fun static(s: Shape) = Dyn then false Lit(l) then not (l is Str and isPrimitiveType(l)) // redundant bracket? Class(_, params) then params.every(static) - Arr(shapes, false) then shapes.every(static) - Arr(shapes, true) then false // TODO + Arr(shapes) then shapes.every(static) open Block { Case } @@ -73,16 +71,14 @@ fun silh(p: Case): Shape = if p is Block.Cls(sym, path) then val size = if sym.args is Some(i) then i else 0 Class(sym, Array(size).fill(Dyn)) - Block.Tup(n, inf) then Arr(Array(n).fill(Dyn), inf) + Block.Tup(n) then Arr(Array(n).fill(Dyn)) // TODO: use Option instead, since all of them return at most one shape fun filter(s: Shape, p: Case): Array[Shape] = if [s, p] is [Lit(l1), Block.Lit(l2)] and l1 == l2 then [s] [Lit(l), Block.Cls(c, _)] and isPrimitiveTypeOf(c, l) then [s] - [Arr(ls, false), Block.Tup(n, false)] and ls.length == n then [s] - [Arr(ls, true), _] then [s] // TODO - [_, Block.Tup(ls, true)] then [s] // TODO + [Arr(ls), Block.Tup(n)] and ls.length == n then [s] [Class(c1, _), Block.Cls(c2, _)] and c1.name == c2.name then [s] [Dyn, _] then [silh(p)] else [] @@ -91,9 +87,7 @@ fun rest(s: Shape, p: Case): Array[Shape] = if [s, p] is [Lit(l1), Block.Lit(l2)] and l1 == l2 then [] [Lit(l), Block.Cls(c, _)] and isPrimitiveTypeOf(c, l) then [] - [Arr(ls, false), Block.Tup(n, false)] and ls.length == n then [] - [Arr(ls, true), _] then [s] // TODO - [_, Block.Tup(ls, true)] then [s] // TODO + [Arr(ls), Block.Tup(n)] and ls.length == n then [] [Class(c1, _), Block.Cls(c2, _)] and c1.name == c2.name then [] [Dyn, _] then [s] else [s] \ No newline at end of file diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index a1ab0546b4..8107100fb6 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -9,7 +9,7 @@ staged module Expressions with let y = x y fun tup1() = [1, 2] - fun tup2() = [1, ..x] + fun tup2() = [1, x] fun dynsel() = [1].(0) fun match1() = if 9 is @@ -19,19 +19,19 @@ staged module Expressions with 9 then 4 else 0 fun match2() = - if [...x] is + if x is [] then 1 [1, 2] then 2 - [a, ...] then 3 + [a, _] then 3 else 0 //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("lit"), ([]), Return(Lit(1), false), true) //│ > FunDefn(Symbol("assign"), ([]), Scoped([Symbol("x"), Symbol("y")], Assign(Symbol("x"), Lit(42), Assign(Symbol("y"), Ref(Symbol("x")), Return(Ref(Symbol("y")), false)))), true) //│ > FunDefn(Symbol("tup1"), ([]), Return(Tuple([Lit(1), Lit(2)]), false), true) -//│ > FunDefn(Symbol("tup2"), ([]), Return(Tuple([Lit(1), ..Ref(Symbol("x1"))]), false), true) +//│ > FunDefn(Symbol("tup2"), ([]), Return(Tuple([Lit(1), Ref(Symbol("x1"))]), false), true) //│ > FunDefn(Symbol("dynsel"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false))), true) //│ > FunDefn(Symbol("match1"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))), true) -//│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("tmp1"), Symbol("middleElements"), Symbol("element0$"), Symbol("element1$"), Symbol("scrut1"), Symbol("a")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Label(Symbol("split_2$"), false, Assign(Symbol("scrut1"), Tuple([...Ref(Symbol("x1"))]), Match(Ref(Symbol("scrut1")), [Tup(0, false) -> Assign(Symbol("tmp1"), Lit(1), Break(Symbol("split_root$"))), Tup(2, false) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp1"), Lit(2), Break(Symbol("split_root$")))], Match(Ref(Symbol("scrut1")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End)], Match(Ref(Symbol("scrut1")), [Tup(1, true) -> Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))))], Break(Symbol("split_2$")), End), End))), Tup(1, true) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("scrut1")), Lit(0)]), Assign(Symbol("middleElements"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("slice")), [Ref(Symbol("scrut1")), Lit(1), Lit(0)]), Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$")))))], Break(Symbol("split_2$")), End)), Assign(Symbol("tmp1"), Lit(0), Break(Symbol("split_root$")))NaN, Assign(Symbol("tmp1"), Lit(3), End)NaN, Return(Ref(Symbol("tmp1")), false)NaN), true) +//│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("element1$"), Symbol("element0$"), Symbol("a"), Symbol("tmp1")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Match(Ref(Symbol("x1")), [Tup(0) -> Assign(Symbol("tmp1"), Lit(1), Break(Symbol("split_root$"))), Tup(2) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("x1")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("x1")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp1"), Lit(2), Break(Symbol("split_root$")))], Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))), End)], Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))), End)))], Assign(Symbol("tmp1"), Lit(0), Break(Symbol("split_root$"))), End), Assign(Symbol("tmp1"), Lit(3), End)NaN, Return(Ref(Symbol("tmp1")), false)NaN), true) //│ x = [1, 2, 3] class Outside(a) @@ -42,11 +42,11 @@ staged module ClassInstrumentation with fun inst2() = new NoArg fun app1() = Outside(1) fun app2() = Inside(1, 2) -//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("Inside1":[Symbol("a1"), Symbol("b")]), [], TODO), Define(ClsLikeDefn(ClassSymbol("NoArg"), [], TODO), End)), true) +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("Inside":[Symbol("a1"), Symbol("b")]), [], TODO), Define(ClsLikeDefn(ClassSymbol("NoArg"), [], TODO), End)), true) //│ > FunDefn(Symbol("inst1"), ([]), Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) //│ > FunDefn(Symbol("inst2"), ([]), Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("NoArg")), []), false), true) //│ > FunDefn(Symbol("app1"), ([]), Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) -//│ > FunDefn(Symbol("app2"), ([]), Return(Call(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("Inside1":[Symbol("a1"), Symbol("b")])), [Lit(1), Lit(2)]), false), true) +//│ > FunDefn(Symbol("app2"), ([]), Return(Call(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("Inside":[Symbol("a1"), Symbol("b")])), [Lit(1), Lit(2)]), false), true) module Nonstaged with fun f() = 1 @@ -88,7 +88,7 @@ staged module OtherBlocks with else 0 //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("scope"), ([]), Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))), true) -//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("tmp"), Symbol("scrut")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) +//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("scrut"), Symbol("tmp")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) staged module ClassDefs with class A @@ -123,6 +123,13 @@ staged module A with //│ ╔══[COMPILATION ERROR] Other Results not supported in staged module: Record(false,List(RcdArg(Some(Lit(IntLit(1))),Lit(IntLit(2))))) //│ ║ l.121: fun g() = {1 : 2} //│ ╙── ^ -//│ > FunDefn(Symbol("ctor$"), ([]), Assign(Symbol("x"), Call(Ref(ClassSymbol("C1":[Symbol("a")])), [Lit(1)]), End), true) +//│ > FunDefn(Symbol("ctor$"), ([]), Assign(Symbol("x"), Call(Ref(ClassSymbol("C":[Symbol("a")])), [Lit(1)]), End), true) //│ ═══[RUNTIME ERROR] Error: MLscript call unexpectedly returned `undefined`, the forbidden value. +:e +staged module Spread with + fun f() = if [1, ..[1, 2]] is [1, ...x] then x else 0 +//│ ═══[COMPILATION ERROR] Spread parameters are not supported in staged module: Arg(Some(false),Ref($tmp,None)) +//│ ═══[COMPILATION ERROR] No definition found in scope for member 'tmp' +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) +//│ ═══[RUNTIME ERROR] Error: MLscript call unexpectedly returned `undefined`, the forbidden value. From 196b54438d355baaf744087b88e506366d63827e Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 6 Mar 2026 16:00:26 +0800 Subject: [PATCH 256/268] remove dead code --- hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index f1639880ec..7b609fafcf 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -103,7 +103,6 @@ class InstrumentationImpl(using State, Raise): raise(ErrorReport(msg"Unable to infer parameters from ClassSymbol in staged module, which are necessary to reconstruct class instances." -> sym.toLoc :: Nil)) End() case t: TermSymbol if t.defn.exists(_.sym.asCls.isDefined) => - val name = scope.allocateOrGetName(sym) transformSymbol(t.defn.get.sym.asCls.get, symName)(k) case _: BuiltinSymbol => // retain names to built-in functions From b3bc782f9083b8f9f91f19305e94377b923182c0 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Mon, 9 Mar 2026 00:06:11 +0800 Subject: [PATCH 257/268] use :todo for spread test case --- hkmc2/shared/src/test/mlscript/block-staging/Functions.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 9c08e63a8a..b9294f97d8 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -126,7 +126,7 @@ staged module A with //│ > FunDefn(Symbol("ctor$"), ([]), Assign(Symbol("x"), Call(Ref(ClassSymbol("C":[Symbol("a")])), [Lit(1)]), End), true) //│ ═══[RUNTIME ERROR] Error: MLscript call unexpectedly returned `undefined`, the forbidden value. -:e +:todo staged module Spread with fun f() = if [1, ..[1, 2]] is [1, ...x] then x else 0 //│ ═══[COMPILATION ERROR] Spread parameters are not supported in staged module: Arg(Some(Lazy),Ref(tmp:tmp⁰,None)) From befdc88bc756daebf59c92b5430fd8095092e800 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 10 Mar 2026 15:21:57 +0800 Subject: [PATCH 258/268] Update difftests --- .../shared/src/test/mlscript/block-staging/Functions.mls | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index b9294f97d8..e94fbcb115 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -31,7 +31,7 @@ staged module Expressions with //│ > FunDefn(Symbol("tup2"), ([]), Return(Tuple([Lit(1), Ref(Symbol("x1"))]), false), true) //│ > FunDefn(Symbol("dynsel"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false))), true) //│ > FunDefn(Symbol("match1"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))), true) -//│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("tmp1"), Symbol("element1$"), Symbol("element0$"), Symbol("a")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Match(Ref(Symbol("x1")), [Tup(0) -> Assign(Symbol("tmp1"), Lit(1), Break(Symbol("split_root$"))), Tup(2) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("x1")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("x1")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp1"), Lit(2), Break(Symbol("split_root$")))], Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))), End)], Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))), End)))], Assign(Symbol("tmp1"), Lit(0), Break(Symbol("split_root$"))), End), Assign(Symbol("tmp1"), Lit(3), End)NaN, Return(Ref(Symbol("tmp1")), false)NaN), true) +//│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("a"), Symbol("tmp1"), Symbol("element1$"), Symbol("element0$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Match(Ref(Symbol("x1")), [Tup(0) -> Assign(Symbol("tmp1"), Lit(1), Break(Symbol("split_root$"))), Tup(2) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("x1")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("x1")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp1"), Lit(2), Break(Symbol("split_root$")))], Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))), End)], Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))), End)))], Assign(Symbol("tmp1"), Lit(0), Break(Symbol("split_root$"))), End), Assign(Symbol("tmp1"), Lit(3), End)NaN, Return(Ref(Symbol("tmp1")), false)NaN), true) //│ x = [1, 2, 3] class Outside(a) @@ -88,7 +88,7 @@ staged module OtherBlocks with else 0 //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("scope"), ([]), Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))), true) -//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("tmp"), Symbol("scrut")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) +//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("scrut"), Symbol("tmp")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) staged module ClassDefs with class A @@ -119,7 +119,7 @@ staged module A with let x = C(1) fun f() = set x.a = 0 fun g() = {1 : 2} -//│ ═══[COMPILATION ERROR] Other Blocks not supprted in staged module: AssignField(Ref(term:A⁰.x¹,None),Ident(a),Lit(IntLit(0)),Return(Select(Ref(tmp:runtime⁰,None),Ident(Unit)),false)) +//│ ═══[COMPILATION ERROR] Other Blocks not supprted in staged module: AssignField(Ref(term:A⁰.x,None),Ident(a),Lit(IntLit(0)),Return(Select(Ref(tmp:runtime,None),Ident(Unit)),false)) //│ ╔══[COMPILATION ERROR] Other Results not supported in staged module: Record(false,List(RcdArg(Some(Lit(IntLit(1))),Lit(IntLit(2))))) //│ ║ l.121: fun g() = {1 : 2} //│ ╙── ^ @@ -129,7 +129,7 @@ staged module A with :todo staged module Spread with fun f() = if [1, ..[1, 2]] is [1, ...x] then x else 0 -//│ ═══[COMPILATION ERROR] Spread parameters are not supported in staged module: Arg(Some(Lazy),Ref(tmp:tmp⁰,None)) +//│ ═══[COMPILATION ERROR] Spread parameters are not supported in staged module: Arg(Some(Lazy),Ref(tmp:tmp,None)) //│ ═══[COMPILATION ERROR] No definition found in scope for member 'tmp' //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ ═══[RUNTIME ERROR] Error: MLscript call unexpectedly returned `undefined`, the forbidden value. From e9b2ae0c6b2c6585081c61a3abce8e186f289213 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Tue, 10 Mar 2026 16:03:16 +0800 Subject: [PATCH 259/268] fix printing bug --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 2 +- hkmc2/shared/src/test/mlscript/block-staging/Functions.mls | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index f643643cbd..7186b9de89 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -164,7 +164,7 @@ fun showBlock(b: Block): Str = Scoped(symbols, rest) then "Scoped([" + symbols.map(showSymbol).join(", ") + "], " + showBlock(rest) + ")" Label(labelSymbol, loop, body, rest) then - "Label(" + showSymbol(labelSymbol) + ", " + showBool(loop) + ", " + showBlock(body) + ", " + showBlock(rest) + + ")" + "Label(" + showSymbol(labelSymbol) + ", " + showBool(loop) + ", " + showBlock(body) + ", " + showBlock(rest) + ")" Break(labelSymbol) then "Break(" + showSymbol(labelSymbol) + ")" End() then "End" diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index e94fbcb115..2871fa4f18 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -31,7 +31,7 @@ staged module Expressions with //│ > FunDefn(Symbol("tup2"), ([]), Return(Tuple([Lit(1), Ref(Symbol("x1"))]), false), true) //│ > FunDefn(Symbol("dynsel"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false))), true) //│ > FunDefn(Symbol("match1"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))), true) -//│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("a"), Symbol("tmp1"), Symbol("element1$"), Symbol("element0$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Match(Ref(Symbol("x1")), [Tup(0) -> Assign(Symbol("tmp1"), Lit(1), Break(Symbol("split_root$"))), Tup(2) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("x1")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("x1")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp1"), Lit(2), Break(Symbol("split_root$")))], Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))), End)], Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))), End)))], Assign(Symbol("tmp1"), Lit(0), Break(Symbol("split_root$"))), End), Assign(Symbol("tmp1"), Lit(3), End)NaN, Return(Ref(Symbol("tmp1")), false)NaN), true) +//│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("a"), Symbol("tmp1"), Symbol("element1$"), Symbol("element0$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Match(Ref(Symbol("x1")), [Tup(0) -> Assign(Symbol("tmp1"), Lit(1), Break(Symbol("split_root$"))), Tup(2) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("x1")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("x1")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp1"), Lit(2), Break(Symbol("split_root$")))], Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))), End)], Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))), End)))], Assign(Symbol("tmp1"), Lit(0), Break(Symbol("split_root$"))), End), Assign(Symbol("tmp1"), Lit(3), End)), Return(Ref(Symbol("tmp1")), false))), true) //│ x = [1, 2, 3] class Outside(a) @@ -88,7 +88,7 @@ staged module OtherBlocks with else 0 //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("scope"), ([]), Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))), true) -//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("scrut"), Symbol("tmp")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)NaN, Return(Ref(Symbol("tmp")), false)NaN), true) +//│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("scrut"), Symbol("tmp")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)), Return(Ref(Symbol("tmp")), false))), true) staged module ClassDefs with class A From 28e7b982dad28b2727f4b372ff70b8d89873927d Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 12 Mar 2026 14:23:00 +0800 Subject: [PATCH 260/268] extend Block IR Symbol information --- .../scala/hkmc2/codegen/Instrumentation.scala | 79 +++++++++++++------ .../main/scala/hkmc2/codegen/Lowering.scala | 2 +- .../src/test/mlscript-compile/Block.mls | 37 ++++++--- .../test/mlscript/block-staging/Functions.mls | 47 +++++++---- .../mlscript/block-staging/StageSymbols.mls | 51 ++++++++++++ 5 files changed, 163 insertions(+), 53 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 5cced783bf..34019a9d8b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -10,7 +10,7 @@ import scala.util.chaining._ import mlscript.utils.*, shorthands.* import semantics.* -import semantics.Elaborator.State +import semantics.Elaborator.{State, Ctx, ctx} import syntax.{Literal, Tree} @@ -18,7 +18,9 @@ import syntax.{Literal, Tree} // this avoids having to rebuild the same shapes everytime they are needed // transform Block to Block IR so that it can be instrumented in mlscript -class InstrumentationImpl(using State, Raise): +class Instrumentation(using State, Raise, Ctx) extends BlockTransformer(new SymbolSubst()): + val defnMap = HashMap[Symbol, ClsLikeDefn]() + type ArgWrappable = Path | Symbol type Context = HashMap[Path, Path] // TODO: there could be a fresh scope per function body, instead of a single one for the entire program @@ -91,22 +93,40 @@ class InstrumentationImpl(using State, Raise): // transformation helpers - def transformSymbol(sym: Symbol, symName: Str = "sym")(k: Path => Block): Block = + // if sym is ClassSymbol, we may need pOpt to link to the path pointing the the value of the symbol + def transformSymbol(sym: Symbol, pOpt: Option[Path] = N, symName: Str = "sym")(k: Path => Block): Block = sym match - case clsSym: ClassSymbol => - clsSym.defn match - case S(defn) => - val name = scope.allocateOrGetName(sym) - transformParamsOpt(defn.paramsOpt): paramsOpt => - blockCtor("ClassSymbol", Ls(toValue(name), paramsOpt), symName)(k) - case N => - raise(ErrorReport(msg"Unable to infer parameters from ClassSymbol in staged module, which are necessary to reconstruct class instances." -> sym.toLoc :: Nil)) - End() - case t: TermSymbol if t.defn.exists(_.sym.asCls.isDefined) => - transformSymbol(t.defn.get.sym.asCls.get, symName)(k) + case t: TermSymbol if t.defn.exists(_.sym.asClsOrMod.isDefined) => + transformSymbol(t.defn.get.sym.asClsOrMod.get, pOpt, symName)(k) + // retain names to built-in functions or function definitions + case t: TermSymbol if t.defn.exists(_.k == syntax.Fun) => + blockCtor("Symbol", Ls(toValue(sym.nme)), symName)(k) case _: BuiltinSymbol => - // retain names to built-in functions blockCtor("Symbol", Ls(toValue(sym.nme)), symName)(k) + case clsSym: ClassSymbol if ctx.builtins.virtualClasses(clsSym) => + blockCtor("VirtualClassSymbol", Ls(toValue(sym.nme)), symName)(k) + case baseSym: BaseTypeSymbol => + val name = scope.allocateOrGetName(sym) + val (owner, bsym, paramsOpt, auxParams) = (baseSym.defn, defnMap.get(baseSym)) match + case (S(defn), _) => (defn.owner, defn.bsym, defn.paramsOpt, defn.auxParams) + case (_, S(defn: ClsLikeDefn)) => (defn.owner, defn.sym, defn.paramsOpt, defn.auxParams) + case _ => + raise(ErrorReport(msg"Unable to infer parameters from symbol in staged module, which are necessary to reconstruct class instances: ${sym.toString()}" -> sym.toLoc :: Nil)) + return End() + + val path: ArgWrappable = pOpt.getOrElse(owner match + case S(owner) => owner.asPath.selSN(sym.nme) + case N => bsym + ) + baseSym match + case _: ClassSymbol => + transformParamsOpt(paramsOpt): paramsOpt => + auxParams.map(ps => transformParamList(ps)).collectApply: auxParams => + tuple(auxParams): auxParams => + blockCtor("ClassSymbol", Ls(toValue(name), path, paramsOpt, auxParams), symName)(k) + case _: ModuleOrObjectSymbol => + blockCtor("ModuleSymbol", Ls(toValue(name), path), symName)(k) + case _ => val name = scope.allocateOrGetName(sym) blockCtor("Symbol", Ls(toValue(name)), symName)(k) @@ -156,7 +176,7 @@ class InstrumentationImpl(using State, Raise): blockCtor("ValueLit", Ls(l), "lit")(k) case s @ Select(p, Tree.Ident(name)) => transformPath(p): x => - val sym = s.symbol.map(transformSymbol(_)) + val sym = s.symbol.map(transformSymbol(_, S(s))) .getOrElse(blockCtor("Symbol", Ls(toValue(name)))) sym: sym => blockCtor("Select", Ls(x, sym), "sel")(k) @@ -306,7 +326,7 @@ class InstrumentationImpl(using State, Raise): tuple(tups): tup => blockCtor("FunDefn", Ls(sym, tup, body, toValue(true)))(k) - def applyFunDefn(f: FunDefn): (FunDefn, Block => Block) = + def applyFunDefnInner(f: FunDefn): (FunDefn, Block => Block) = val genSymName = f.sym.nme + "_instr" val genSym = BlockMemberSymbol(genSymName, Nil, false) val sym = f.owner.get.asPath.selSN(genSymName) @@ -321,10 +341,6 @@ class InstrumentationImpl(using State, Raise): val newFun = f.copy(sym = genSym, dSym = dSym, params = Ls(PlainParamList(Nil)), body = newBody)(false) (newFun, debug) -// TODO: rename as InstrumentationTransformer? -class Instrumentation(using State, Raise) extends BlockTransformer(new SymbolSubst()): - val impl = new InstrumentationImpl - override def applyBlock(b: Block): Block = super.applyBlock(b) match // find modules with staged annotation @@ -332,10 +348,10 @@ class Instrumentation(using State, Raise) extends BlockTransformer(new SymbolSub val sym = c.sym.subst val companion = c.companion.get val (stagedMethods, debugPrintCode) = companion.methods - .map(impl.applyFunDefn) + .map(applyFunDefnInner) .unzip val ctor = FunDefn.withFreshSymbol(S(companion.isym), BlockMemberSymbol("ctor$", Nil), Ls(PlainParamList(Nil)), companion.ctor)(false) - val (stagedCtor, ctorPrint) = impl.applyFunDefn(ctor) + val (stagedCtor, ctorPrint) = applyFunDefnInner(ctor) val unit = State.runtimeSymbol.asPath.selSN("Unit") val debugBlock = (ctorPrint :: debugPrintCode).foldRight((Return(unit, true): Block))(_(_)) @@ -346,7 +362,7 @@ class Instrumentation(using State, Raise) extends BlockTransformer(new SymbolSub override def applyBlock(b: Block): Block = super.applyBlock(b) match case Define(c: ClsLikeDefn, rest) if c.companion.isEmpty => val (stagedMethods, debugPrintCode) = c.methods - .map(impl.applyFunDefn) + .map(applyFunDefnInner) .unzip val newModule = c.copy(methods = c.methods ++ stagedMethods) Define(newModule, rest) @@ -356,3 +372,18 @@ class Instrumentation(using State, Raise) extends BlockTransformer(new SymbolSub val newModule = c.copy(sym = sym, companion = S(newCompanion)) Define(newModule, rest) case b => b + + // recover `defn` for when `sym.defn` is `None`, when the definition was generated by other compiler passes + def mkDefnMap(b: Block) = + val transformer = new BlockTransformer(new SymbolSubst()): + override def applyDefn(defn: Defn)(k: Defn => Block) = defn match + case c: ClsLikeDefn => + defnMap.addOne(c.isym, c) + // c.companion.map(defn => defnMap.addOne(defn.isym, defn)) + super.applyDefn(defn)(k) + case _ => super.applyDefn(defn)(k) + transformer.applyBlock(b) + + def applyBlockFinal(b: Block) = + mkDefnMap(b) + applyBlock(b) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index 395c2fab97..9d83f84b80 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -1088,7 +1088,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): if config.funcToCls then Lifter(FirstClassFunctionTransformer().transform(merged)).transform else merged - val staged = Instrumentation(using summon).applyBlock(funcToCls) + val staged = Instrumentation(using summon).applyBlockFinal(funcToCls) val res = if config.tailRecOpt then TailRecOpt().transform(staged) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 7186b9de89..33c519a3c8 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -18,8 +18,31 @@ type ParamList = Array[Symbol] class Symbol(val name: Str) type Ident = Symbol -// this is so that we're able to retrieve information about the class from the symbol -class ClassSymbol(val name: Str, val paramsOpt: Opt[ParamList]) extends Symbol(name) + +class VirtualClassSymbol(val name: Str) extends Symbol(name) +class ClassSymbol(val name: Str, val value, val paramsOpt: Option[ParamList], val auxParams: Array[ParamList]) extends Symbol(name) +class ModuleSymbol(val name: Str, val value) extends Symbol(name) +class Arm(val cse: Case, val body: Block) + +fun isPrimitiveType(sym: Symbol) = + if sym.name is + "Str" then true + "Int" then true + "Num" then true + "Bool" then true + "TypedArray" then true + else false + +fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = + if [sym.name, l] is + ["Str", l] and l is Str then true + ["Int", i] and i is Int then true + ["Num", n] and n is Num then true + ["Bool", b] and b is Bool then true + ["TypedArray", a] and a is TypedArray then true + else false + +// Classes defined in Block.scala class Arg(val value: Path) @@ -82,15 +105,7 @@ fun showLiteral(l: Literal) = else l.toString() fun showSymbol(s: Symbol) = - // console.log("printing " + s) - if s is - ClassSymbol(name, args) then - "ClassSymbol(" + "\"" + name + "\"" + - if args - is Some(args) then ":[" + args.map(showSymbol).join(", ") + "]" - is None then "" - + ")" - _ then "Symbol(" + "\"" + s.name + "\"" + ")" + s.toString() fun showIdent(i: Ident) = showSymbol(i) diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 2871fa4f18..126fd014d7 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -30,7 +30,7 @@ staged module Expressions with //│ > FunDefn(Symbol("tup1"), ([]), Return(Tuple([Lit(1), Lit(2)]), false), true) //│ > FunDefn(Symbol("tup2"), ([]), Return(Tuple([Lit(1), Ref(Symbol("x1"))]), false), true) //│ > FunDefn(Symbol("dynsel"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false))), true) -//│ > FunDefn(Symbol("match1"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))), true) +//│ > FunDefn(Symbol("match1"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool", None, undefined, undefined), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int", None, undefined, undefined), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))), true) //│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("a"), Symbol("tmp1"), Symbol("element1$"), Symbol("element0$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Match(Ref(Symbol("x1")), [Tup(0) -> Assign(Symbol("tmp1"), Lit(1), Break(Symbol("split_root$"))), Tup(2) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("x1")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("x1")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp1"), Lit(2), Break(Symbol("split_root$")))], Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))), End)], Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))), End)))], Assign(Symbol("tmp1"), Lit(0), Break(Symbol("split_root$"))), End), Assign(Symbol("tmp1"), Lit(3), End)), Return(Ref(Symbol("tmp1")), false))), true) //│ x = [1, 2, 3] @@ -42,11 +42,11 @@ staged module ClassInstrumentation with fun inst2() = new NoArg fun app1() = Outside(1) fun app2() = Inside(1, 2) -//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("Inside":[Symbol("a1"), Symbol("b")]), [], TODO), Define(ClsLikeDefn(ClassSymbol("NoArg"), [], TODO), End)), true) -//│ > FunDefn(Symbol("inst1"), ([]), Return(Instantiate(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) -//│ > FunDefn(Symbol("inst2"), ([]), Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("NoArg")), []), false), true) -//│ > FunDefn(Symbol("app1"), ([]), Return(Call(Ref(ClassSymbol("Outside":[Symbol("a")])), [Lit(1)]), false), true) -//│ > FunDefn(Symbol("app2"), ([]), Return(Call(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("Inside":[Symbol("a1"), Symbol("b")])), [Lit(1), Lit(2)]), false), true) +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("Inside", Some([Symbol("a1"), Symbol("b")]), undefined, undefined), [], TODO), Define(ClsLikeDefn(ClassSymbol("NoArg", None, undefined, undefined), [], TODO), End)), true) +//│ > FunDefn(Symbol("inst1"), ([]), Return(Instantiate(Ref(ClassSymbol("Outside", Some([Symbol("a")]), undefined, undefined)), [Lit(1)]), false), true) +//│ > FunDefn(Symbol("inst2"), ([]), Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("NoArg", None, undefined, undefined)), []), false), true) +//│ > FunDefn(Symbol("app1"), ([]), Return(Call(Ref(ClassSymbol("Outside", Some([Symbol("a")]), undefined, undefined)), [Lit(1)]), false), true) +//│ > FunDefn(Symbol("app2"), ([]), Return(Call(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("Inside", Some([Symbol("a1"), Symbol("b")]), undefined, undefined)), [Lit(1), Lit(2)]), false), true) module Nonstaged with fun f() = 1 @@ -62,18 +62,30 @@ staged module CallSubst with //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("call"), ([]), Assign(Symbol("$_no$_symbol$_"), Call(Ref(Symbol("+")), [Lit(1), Lit(1)]), Assign(Symbol("$_no$_symbol$_"), Call(Select(Ref(Symbol("Nonstaged")), Symbol("f")), []), Return(Call(Select(Ref(Symbol("Staged")), Symbol("f_gen")), []), false))), true) -:w +:ftc staged module Arguments with fun f(x) = x = 1 x fun g(x)(y, z)() = z -//│ ╔══[WARNING] Multiple parameter lists are not supported in shape propagation yet. -//│ ║ l.70: fun g(x)(y, z)() = z -//│ ╙── ^^^^^^^^^^^^^^^^^^^^ +//│ FAILURE: Unexpected compilation error +//│ FAILURE LOCATION: transformSymbol (Instrumentation.scala:103) +//│ ═══[COMPILATION ERROR] Unable to infer parameters from ClassSymbol in staged module, which are necessary to reconstruct class instances. //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("f"), ([Symbol("x")]), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)), true) -//│ > FunDefn(Symbol("g"), ([Symbol("x")],[Symbol("y"), Symbol("z")],[]), Return(Ref(Symbol("z")), false), true) +//│ FAILURE: Unexpected runtime error +//│ FAILURE LOCATION: mkQuery (JSBackendDiffMaker.scala:172) +//│ ═══[RUNTIME ERROR] Error: MLscript call unexpectedly returned `undefined`, the forbidden value. +//│ at Runtime.checkCall (file:///home/hillo/Downloads/uni/fyp/mlscript/hkmc2/shared/src/test/mlscript-compile/Runtime.mjs:621:41) +//│ at (REPL25:1:2009) +//│ at REPL25:1:3955 +//│ at ContextifyScript.runInThisContext (node:vm:137:12) +//│ at REPLServer.defaultEval (node:repl:600:22) +//│ at bound (node:domain:433:15) +//│ at REPLServer.runBound [as eval] (node:domain:444:12) +//│ at REPLServer.onLine (node:repl:935:10) +//│ at REPLServer.emit (node:events:508:28) +//│ at REPLServer.emit (node:domain:489:12) staged module OtherBlocks with fun scope() = @@ -92,12 +104,13 @@ staged module OtherBlocks with staged module ClassDefs with class A -//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("A"), [], TODO), End), true) +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("A", None, undefined, undefined), [], TODO), End), true) staged module ClassFunctions with - class A with - fun f() = 1 -//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("A"), [FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true)], TODO), End), true) + class InnerClass() with + fun f() = 1 + Arguments.f(1) + fun g() = f() // TODO +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("InnerClass", Some([]), undefined, undefined), [FunDefn(Symbol("f"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Call(Select(Ref(Symbol("Arguments")), Symbol("f_gen")), [Lit(1)]), Return(Call(Ref(Symbol("+")), [Lit(1), Ref(Symbol("tmp"))]), false))), true),FunDefn(Symbol("g"), ([]), Return(Call(Select(Ref(ClassSymbol("InnerClass", Some([]), undefined, undefined)), Symbol("f")), []), false), true)], TODO), End), true) // name collision class A() @@ -121,9 +134,9 @@ staged module A with fun g() = {1 : 2} //│ ═══[COMPILATION ERROR] Other Blocks not supprted in staged module: AssignField(Ref(term:A⁰.x,None),Ident(a),Lit(IntLit(0)),Return(Select(Ref(tmp:runtime,None),Ident(Unit)),false)) //│ ╔══[COMPILATION ERROR] Other Results not supported in staged module: Record(false,List(RcdArg(Some(Lit(IntLit(1))),Lit(IntLit(2))))) -//│ ║ l.121: fun g() = {1 : 2} +//│ ║ l.134: fun g() = {1 : 2} //│ ╙── ^ -//│ > FunDefn(Symbol("ctor$"), ([]), Assign(Symbol("x"), Call(Ref(ClassSymbol("C":[Symbol("a")])), [Lit(1)]), End), true) +//│ > FunDefn(Symbol("ctor$"), ([]), Assign(Symbol("x"), Call(Ref(ClassSymbol("C", Some([Symbol("a")]), undefined, undefined)), [Lit(1)]), End), true) //│ ═══[RUNTIME ERROR] Error: MLscript call unexpectedly returned `undefined`, the forbidden value. :todo diff --git a/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls b/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls new file mode 100644 index 0000000000..3127385a24 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls @@ -0,0 +1,51 @@ +:js +:staging + +staged module M with + class C with + fun f() = 1 + fun g() = f() +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("C", class C, None, []), [FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true),FunDefn(Symbol("g"), ([]), Return(Call(Select(Ref(ClassSymbol("C", class C, None, [])), Symbol("f")), []), false), true)], TODO), End), true) + +// :sir +staged module A with + fun f() = 1 +module B with + fun f() = 1 +class C +staged module D with + class E + fun f() = + A.f() + B.f() + 1 is C + fun builtin() = 1 is Int + fun inner() = D.E +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) +//│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("E", class E, None, []), [], TODO), End), true) +//│ > FunDefn(Symbol("f"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("$_no$_symbol$_"), Call(Select(Ref(ModuleSymbol("A", class A)), Symbol("f_gen")), []), Assign(Symbol("$_no$_symbol$_"), Call(Select(Ref(ModuleSymbol("B", class B)), Symbol("f")), []), Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("C", class C, None, []), Ref(ClassSymbol("C", class C, None, []))) -> Return(Lit(true), false)], Return(Lit(false), false), End))))), true) +//│ > FunDefn(Symbol("builtin"), ([]), Scoped([Symbol("scrut1")], Assign(Symbol("scrut1"), Lit(1), Match(Ref(Symbol("scrut1")), [Cls(VirtualClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(true), false)], Return(Lit(false), false), End))), true) +//│ > FunDefn(Symbol("inner"), ([]), Return(Select(Ref(ModuleSymbol("D", class D { E: class E })), ClassSymbol("E", class E, None, [])), false), true) + +// :sjs +// :lot +module A with + module B with + class C(a) +staged module M with + fun f() = D.f() + fun g() = D.E + fun h() = A.B.C(1) + fun i() = A.B.C +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) +//│ > FunDefn(Symbol("f"), ([]), Return(Call(Select(Ref(ModuleSymbol("D", class D { E: class E })), Symbol("f_gen")), []), false), true) +//│ > FunDefn(Symbol("g"), ([]), Return(Select(Ref(ModuleSymbol("D", class D { E: class E })), ClassSymbol("E", class E, None, [])), false), true) +//│ > FunDefn(Symbol("h"), ([]), Return(Call(Select(Select(Ref(ModuleSymbol("A", class A { B: class B { C: fun C { class: class C } } })), ModuleSymbol("B", class B { C: fun C { class: class C } })), ClassSymbol("C", fun C { class: class C }, Some([Symbol("a")]), [])), [Lit(1)]), false), true) +//│ > FunDefn(Symbol("i"), ([]), Return(Select(Select(Ref(ModuleSymbol("A", class A { B: class B { C: fun C { class: class C } } })), ModuleSymbol("B", class B { C: fun C { class: class C } })), ClassSymbol("C", fun C { class: class C }, Some([Symbol("a")]), [])), false), true) + +:ftc +staged module M with + fun f() = x => x +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) +//│ > FunDefn(Symbol("f"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Instantiate(Ref(ClassSymbol("Function$", class Function$, None, [])), []), Return(Ref(Symbol("tmp")), false))), true) From 6beb77c086bfe251cfec5e830f83f1a12055968e Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 12 Mar 2026 22:00:35 +0800 Subject: [PATCH 261/268] update tests --- .../scala/hkmc2/codegen/Instrumentation.scala | 2 +- .../test/mlscript/block-staging/Functions.mls | 50 ++++++++----------- .../mlscript/block-staging/StageSymbols.mls | 38 +++++++------- 3 files changed, 44 insertions(+), 46 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 34019a9d8b..8c6989c2ee 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -316,7 +316,7 @@ class Instrumentation(using State, Raise, Ctx) extends BlockTransformer(new Symb def transformFunDefn(f: FunDefn)(using Context)(k: Path => Block): Block = transformBlock(f.body): body => if f.params.length != 1 then - raise(WarningReport(msg"Multiple parameter lists are not supported in shape propagation yet." -> f.sym.toLoc :: Nil)) + raise(WarningReport(msg":ftc must be enabled for functions with multiple parameter lists." -> f.sym.toLoc :: Nil)) // maintain parameter names in instrumented code f.params.map( _.params.map(p => blockCtor("Symbol", Ls(toValue(p.sym.nme)))).collectApply diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 126fd014d7..660b330507 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -30,7 +30,7 @@ staged module Expressions with //│ > FunDefn(Symbol("tup1"), ([]), Return(Tuple([Lit(1), Lit(2)]), false), true) //│ > FunDefn(Symbol("tup2"), ([]), Return(Tuple([Lit(1), Ref(Symbol("x1"))]), false), true) //│ > FunDefn(Symbol("dynsel"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Tuple([Lit(1)]), Return(DynSelect(Ref(Symbol("tmp")), Lit(0), false), false))), true) -//│ > FunDefn(Symbol("match1"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("Bool", None, undefined, undefined), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(ClassSymbol("Int", None, undefined, undefined), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))), true) +//│ > FunDefn(Symbol("match1"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(9), Match(Ref(Symbol("scrut")), [Cls(VirtualClassSymbol("Bool"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(1), false), Lit(8) -> Return(Lit(2), false), Cls(VirtualClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(3), false)], Return(Lit(0), false), End))), true) //│ > FunDefn(Symbol("match2"), ([]), Scoped([Symbol("a"), Symbol("tmp1"), Symbol("element1$"), Symbol("element0$")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Match(Ref(Symbol("x1")), [Tup(0) -> Assign(Symbol("tmp1"), Lit(1), Break(Symbol("split_root$"))), Tup(2) -> Assign(Symbol("element0$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("x1")), Lit(0)]), Assign(Symbol("element1$"), Call(Select(Select(Ref(Symbol("runtime")), Symbol("Tuple")), Symbol("get")), [Ref(Symbol("x1")), Lit(1)]), Match(Ref(Symbol("element0$")), [Lit(1) -> Match(Ref(Symbol("element1$")), [Lit(2) -> Assign(Symbol("tmp1"), Lit(2), Break(Symbol("split_root$")))], Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))), End)], Assign(Symbol("a"), Ref(Symbol("element0$")), Break(Symbol("split_1$"))), End)))], Assign(Symbol("tmp1"), Lit(0), Break(Symbol("split_root$"))), End), Assign(Symbol("tmp1"), Lit(3), End)), Return(Ref(Symbol("tmp1")), false))), true) //│ x = [1, 2, 3] @@ -42,11 +42,11 @@ staged module ClassInstrumentation with fun inst2() = new NoArg fun app1() = Outside(1) fun app2() = Inside(1, 2) -//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("Inside", Some([Symbol("a1"), Symbol("b")]), undefined, undefined), [], TODO), Define(ClsLikeDefn(ClassSymbol("NoArg", None, undefined, undefined), [], TODO), End)), true) -//│ > FunDefn(Symbol("inst1"), ([]), Return(Instantiate(Ref(ClassSymbol("Outside", Some([Symbol("a")]), undefined, undefined)), [Lit(1)]), false), true) -//│ > FunDefn(Symbol("inst2"), ([]), Return(Instantiate(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("NoArg", None, undefined, undefined)), []), false), true) -//│ > FunDefn(Symbol("app1"), ([]), Return(Call(Ref(ClassSymbol("Outside", Some([Symbol("a")]), undefined, undefined)), [Lit(1)]), false), true) -//│ > FunDefn(Symbol("app2"), ([]), Return(Call(Select(Ref(Symbol("ClassInstrumentation")), ClassSymbol("Inside", Some([Symbol("a1"), Symbol("b")]), undefined, undefined)), [Lit(1), Lit(2)]), false), true) +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("Inside", fun Inside { class: class Inside }, Some([Symbol("a1"), Symbol("b")]), []), [], TODO), Define(ClsLikeDefn(ClassSymbol("NoArg", class NoArg, None, []), [], TODO), End)), true) +//│ > FunDefn(Symbol("inst1"), ([]), Return(Instantiate(Ref(ClassSymbol("Outside", fun Outside { class: class Outside }, Some([Symbol("a")]), [])), [Lit(1)]), false), true) +//│ > FunDefn(Symbol("inst2"), ([]), Return(Instantiate(Select(Ref(ModuleSymbol("ClassInstrumentation", class ClassInstrumentation { Inside: fun Inside { class: class Inside }, NoArg: class NoArg })), ClassSymbol("NoArg", class NoArg, None, [])), []), false), true) +//│ > FunDefn(Symbol("app1"), ([]), Return(Call(Ref(ClassSymbol("Outside", fun Outside { class: class Outside }, Some([Symbol("a")]), [])), [Lit(1)]), false), true) +//│ > FunDefn(Symbol("app2"), ([]), Return(Call(Select(Ref(ModuleSymbol("ClassInstrumentation", class ClassInstrumentation { Inside: fun Inside { class: class Inside }, NoArg: class NoArg })), ClassSymbol("Inside", fun Inside { class: class Inside }, Some([Symbol("a1"), Symbol("b")]), [])), [Lit(1), Lit(2)]), false), true) module Nonstaged with fun f() = 1 @@ -60,7 +60,7 @@ staged module CallSubst with Nonstaged.f() Staged.f() //│ > FunDefn(Symbol("ctor$"), ([]), End, true) -//│ > FunDefn(Symbol("call"), ([]), Assign(Symbol("$_no$_symbol$_"), Call(Ref(Symbol("+")), [Lit(1), Lit(1)]), Assign(Symbol("$_no$_symbol$_"), Call(Select(Ref(Symbol("Nonstaged")), Symbol("f")), []), Return(Call(Select(Ref(Symbol("Staged")), Symbol("f_gen")), []), false))), true) +//│ > FunDefn(Symbol("call"), ([]), Assign(Symbol("$_no$_symbol$_"), Call(Ref(Symbol("+")), [Lit(1), Lit(1)]), Assign(Symbol("$_no$_symbol$_"), Call(Select(Ref(ModuleSymbol("Nonstaged", class Nonstaged)), Symbol("f")), []), Return(Call(Select(Ref(ModuleSymbol("Staged", class Staged)), Symbol("f_gen")), []), false))), true) :ftc staged module Arguments with @@ -68,24 +68,9 @@ staged module Arguments with x = 1 x fun g(x)(y, z)() = z -//│ FAILURE: Unexpected compilation error -//│ FAILURE LOCATION: transformSymbol (Instrumentation.scala:103) -//│ ═══[COMPILATION ERROR] Unable to infer parameters from ClassSymbol in staged module, which are necessary to reconstruct class instances. //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("f"), ([Symbol("x")]), Assign(Symbol("x"), Lit(1), Return(Ref(Symbol("x")), false)), true) -//│ FAILURE: Unexpected runtime error -//│ FAILURE LOCATION: mkQuery (JSBackendDiffMaker.scala:172) -//│ ═══[RUNTIME ERROR] Error: MLscript call unexpectedly returned `undefined`, the forbidden value. -//│ at Runtime.checkCall (file:///home/hillo/Downloads/uni/fyp/mlscript/hkmc2/shared/src/test/mlscript-compile/Runtime.mjs:621:41) -//│ at (REPL25:1:2009) -//│ at REPL25:1:3955 -//│ at ContextifyScript.runInThisContext (node:vm:137:12) -//│ at REPLServer.defaultEval (node:repl:600:22) -//│ at bound (node:domain:433:15) -//│ at REPLServer.runBound [as eval] (node:domain:444:12) -//│ at REPLServer.onLine (node:repl:935:10) -//│ at REPLServer.emit (node:events:508:28) -//│ at REPLServer.emit (node:domain:489:12) +//│ > FunDefn(Symbol("g"), ([Symbol("x")]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Instantiate(Ref(ClassSymbol("Function$", class Function$, None, [])), []), Return(Ref(Symbol("tmp")), false))), true) staged module OtherBlocks with fun scope() = @@ -99,18 +84,18 @@ staged module OtherBlocks with 3 then 0 else 0 //│ > FunDefn(Symbol("ctor$"), ([]), End, true) -//│ > FunDefn(Symbol("scope"), ([]), Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(Symbol("OtherBlocks")), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))), true) +//│ > FunDefn(Symbol("scope"), ([]), Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(ModuleSymbol("OtherBlocks", class OtherBlocks)), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))), true) //│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("scrut"), Symbol("tmp")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Break(Symbol("split_1$")), Lit(3) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(0), End)), Return(Ref(Symbol("tmp")), false))), true) staged module ClassDefs with class A -//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("A", None, undefined, undefined), [], TODO), End), true) +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("A", class A, None, []), [], TODO), End), true) staged module ClassFunctions with class InnerClass() with fun f() = 1 + Arguments.f(1) fun g() = f() // TODO -//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("InnerClass", Some([]), undefined, undefined), [FunDefn(Symbol("f"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Call(Select(Ref(Symbol("Arguments")), Symbol("f_gen")), [Lit(1)]), Return(Call(Ref(Symbol("+")), [Lit(1), Ref(Symbol("tmp"))]), false))), true),FunDefn(Symbol("g"), ([]), Return(Call(Select(Ref(ClassSymbol("InnerClass", Some([]), undefined, undefined)), Symbol("f")), []), false), true)], TODO), End), true) +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("InnerClass", fun InnerClass { class: class InnerClass }, Some([]), []), [FunDefn(Symbol("f"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Call(Select(Ref(ModuleSymbol("Arguments", class Arguments)), Symbol("f_gen")), [Lit(1)]), Return(Call(Ref(Symbol("+")), [Lit(1), Ref(Symbol("tmp"))]), false))), true),FunDefn(Symbol("g"), ([]), Return(Call(Select(Ref(ClassSymbol("InnerClass", fun InnerClass { class: class InnerClass }, Some([]), [])), Symbol("f")), []), false), true)], TODO), End), true) // name collision class A() @@ -126,6 +111,15 @@ module A with //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) +// TODO: reject this after removing Label and Break from Block IR +staged module M with + fun f() = if 1 is + 0 then 2 + 1 then 2 + else 2 +//│ > FunDefn(Symbol("ctor$"), ([]), End, true) +//│ > FunDefn(Symbol("f"), ([]), Scoped([Symbol("tmp"), Symbol("scrut")], Label(Symbol("split_root$"), false, Label(Symbol("split_1$"), false, Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(0) -> Break(Symbol("split_1$")), Lit(1) -> Break(Symbol("split_1$"))], Break(Symbol("split_1$")), End)), Assign(Symbol("tmp"), Lit(2), End)), Return(Ref(Symbol("tmp")), false))), true) + :e class C(val a) staged module A with @@ -134,9 +128,9 @@ staged module A with fun g() = {1 : 2} //│ ═══[COMPILATION ERROR] Other Blocks not supprted in staged module: AssignField(Ref(term:A⁰.x,None),Ident(a),Lit(IntLit(0)),Return(Select(Ref(tmp:runtime,None),Ident(Unit)),false)) //│ ╔══[COMPILATION ERROR] Other Results not supported in staged module: Record(false,List(RcdArg(Some(Lit(IntLit(1))),Lit(IntLit(2))))) -//│ ║ l.134: fun g() = {1 : 2} +//│ ║ l.128: fun g() = {1 : 2} //│ ╙── ^ -//│ > FunDefn(Symbol("ctor$"), ([]), Assign(Symbol("x"), Call(Ref(ClassSymbol("C", Some([Symbol("a")]), undefined, undefined)), [Lit(1)]), End), true) +//│ > FunDefn(Symbol("ctor$"), ([]), Assign(Symbol("x"), Call(Ref(ClassSymbol("C", fun C { class: class C }, Some([Symbol("a")]), [])), [Lit(1)]), End), true) //│ ═══[RUNTIME ERROR] Error: MLscript call unexpectedly returned `undefined`, the forbidden value. :todo diff --git a/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls b/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls index 3127385a24..7b1088a2d7 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls @@ -7,42 +7,46 @@ staged module M with fun g() = f() //│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("C", class C, None, []), [FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true),FunDefn(Symbol("g"), ([]), Return(Call(Select(Ref(ClassSymbol("C", class C, None, [])), Symbol("f")), []), false), true)], TODO), End), true) -// :sir staged module A with fun f() = 1 module B with fun f() = 1 -class C +class C(val a, b)(c)(d) staged module D with class E fun f() = A.f() B.f() + fun matching() = + 1 is Int 1 is C - fun builtin() = 1 is Int - fun inner() = D.E //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) //│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("E", class E, None, []), [], TODO), End), true) -//│ > FunDefn(Symbol("f"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("$_no$_symbol$_"), Call(Select(Ref(ModuleSymbol("A", class A)), Symbol("f_gen")), []), Assign(Symbol("$_no$_symbol$_"), Call(Select(Ref(ModuleSymbol("B", class B)), Symbol("f")), []), Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Cls(ClassSymbol("C", class C, None, []), Ref(ClassSymbol("C", class C, None, []))) -> Return(Lit(true), false)], Return(Lit(false), false), End))))), true) -//│ > FunDefn(Symbol("builtin"), ([]), Scoped([Symbol("scrut1")], Assign(Symbol("scrut1"), Lit(1), Match(Ref(Symbol("scrut1")), [Cls(VirtualClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Return(Lit(true), false)], Return(Lit(false), false), End))), true) -//│ > FunDefn(Symbol("inner"), ([]), Return(Select(Ref(ModuleSymbol("D", class D { E: class E })), ClassSymbol("E", class E, None, [])), false), true) +//│ > FunDefn(Symbol("f"), ([]), Assign(Symbol("$_no$_symbol$_"), Call(Select(Ref(ModuleSymbol("A", class A)), Symbol("f_gen")), []), Return(Call(Select(Ref(ModuleSymbol("B", class B)), Symbol("f")), []), false)), true) +//│ > FunDefn(Symbol("matching"), ([]), Scoped([Symbol("tmp"), Symbol("scrut"), Symbol("scrut1")], Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Cls(VirtualClassSymbol("Int"), Select(Ref(Symbol("runtime")), Symbol("unreachable"))) -> Assign(Symbol("tmp"), Lit(true), End)], Assign(Symbol("tmp"), Lit(false), End), Assign(Symbol("scrut1"), Lit(1), Match(Ref(Symbol("scrut1")), [Cls(ClassSymbol("C", fun C { class: class C }, Some([Symbol("a"), Symbol("b")]), [[Symbol("c")], [Symbol("d")]]), Ref(ClassSymbol("C", fun C { class: class C }, Some([Symbol("a"), Symbol("b")]), [[Symbol("c")], [Symbol("d")]]))) -> Return(Lit(true), false)], Return(Lit(false), false), End))))), true) -// :sjs -// :lot module A with module B with class C(a) staged module M with - fun f() = D.f() - fun g() = D.E - fun h() = A.B.C(1) - fun i() = A.B.C + class E + fun f() = + D.E + A.B.C + A.B.C(1) + E +//│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("E", class E, None, []), [], TODO), End), true) +//│ > FunDefn(Symbol("f"), ([]), Assign(Symbol("$_no$_symbol$_"), Call(Select(Select(Ref(ModuleSymbol("A", class A { B: class B { C: fun C { class: class C } } })), ModuleSymbol("B", class B { C: fun C { class: class C } })), ClassSymbol("C", fun C { class: class C }, Some([Symbol("a")]), [])), [Lit(1)]), Return(Select(Ref(ModuleSymbol("M", class M2 { E: class E })), ClassSymbol("E", class E, None, [])), false)), true) + +:w +staged module M with + fun g()() = 1 +//│ ╔══[WARNING] :ftc must be enabled for functions with multiple parameter lists. +//│ ║ l.44: fun g()() = 1 +//│ ╙── ^^^^^^^^^^^^^ //│ > FunDefn(Symbol("ctor$"), ([]), End, true) -//│ > FunDefn(Symbol("f"), ([]), Return(Call(Select(Ref(ModuleSymbol("D", class D { E: class E })), Symbol("f_gen")), []), false), true) -//│ > FunDefn(Symbol("g"), ([]), Return(Select(Ref(ModuleSymbol("D", class D { E: class E })), ClassSymbol("E", class E, None, [])), false), true) -//│ > FunDefn(Symbol("h"), ([]), Return(Call(Select(Select(Ref(ModuleSymbol("A", class A { B: class B { C: fun C { class: class C } } })), ModuleSymbol("B", class B { C: fun C { class: class C } })), ClassSymbol("C", fun C { class: class C }, Some([Symbol("a")]), [])), [Lit(1)]), false), true) -//│ > FunDefn(Symbol("i"), ([]), Return(Select(Select(Ref(ModuleSymbol("A", class A { B: class B { C: fun C { class: class C } } })), ModuleSymbol("B", class B { C: fun C { class: class C } })), ClassSymbol("C", fun C { class: class C }, Some([Symbol("a")]), [])), false), true) +//│ > FunDefn(Symbol("g"), ([],[]), Return(Lit(1), false), true) :ftc staged module M with From d3d3305cead8569e164b3903873132cf255c8e80 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 12 Mar 2026 22:31:45 +0800 Subject: [PATCH 262/268] cleanup --- .../src/main/scala/hkmc2/codegen/Instrumentation.scala | 8 +++----- .../src/test/mlscript/block-staging/StageSymbols.mls | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 8c6989c2ee..e22a5f5354 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -19,6 +19,7 @@ import syntax.{Literal, Tree} // transform Block to Block IR so that it can be instrumented in mlscript class Instrumentation(using State, Raise, Ctx) extends BlockTransformer(new SymbolSubst()): + // recover `defn` for when `sym.defn` is `None`, when the definition was generated by other compiler passes val defnMap = HashMap[Symbol, ClsLikeDefn]() type ArgWrappable = Path | Symbol @@ -116,8 +117,7 @@ class Instrumentation(using State, Raise, Ctx) extends BlockTransformer(new Symb val path: ArgWrappable = pOpt.getOrElse(owner match case S(owner) => owner.asPath.selSN(sym.nme) - case N => bsym - ) + case N => bsym) baseSym match case _: ClassSymbol => transformParamsOpt(paramsOpt): paramsOpt => @@ -316,7 +316,7 @@ class Instrumentation(using State, Raise, Ctx) extends BlockTransformer(new Symb def transformFunDefn(f: FunDefn)(using Context)(k: Path => Block): Block = transformBlock(f.body): body => if f.params.length != 1 then - raise(WarningReport(msg":ftc must be enabled for functions with multiple parameter lists." -> f.sym.toLoc :: Nil)) + raise(ErrorReport(msg":ftc must be enabled to desugar functions with multiple parameter lists." -> f.sym.toLoc :: Nil)) // maintain parameter names in instrumented code f.params.map( _.params.map(p => blockCtor("Symbol", Ls(toValue(p.sym.nme)))).collectApply @@ -373,13 +373,11 @@ class Instrumentation(using State, Raise, Ctx) extends BlockTransformer(new Symb Define(newModule, rest) case b => b - // recover `defn` for when `sym.defn` is `None`, when the definition was generated by other compiler passes def mkDefnMap(b: Block) = val transformer = new BlockTransformer(new SymbolSubst()): override def applyDefn(defn: Defn)(k: Defn => Block) = defn match case c: ClsLikeDefn => defnMap.addOne(c.isym, c) - // c.companion.map(defn => defnMap.addOne(defn.isym, defn)) super.applyDefn(defn)(k) case _ => super.applyDefn(defn)(k) transformer.applyBlock(b) diff --git a/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls b/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls index 7b1088a2d7..f502c47fa8 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls @@ -39,10 +39,10 @@ staged module M with //│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("E", class E, None, []), [], TODO), End), true) //│ > FunDefn(Symbol("f"), ([]), Assign(Symbol("$_no$_symbol$_"), Call(Select(Select(Ref(ModuleSymbol("A", class A { B: class B { C: fun C { class: class C } } })), ModuleSymbol("B", class B { C: fun C { class: class C } })), ClassSymbol("C", fun C { class: class C }, Some([Symbol("a")]), [])), [Lit(1)]), Return(Select(Ref(ModuleSymbol("M", class M2 { E: class E })), ClassSymbol("E", class E, None, [])), false)), true) -:w +:e staged module M with fun g()() = 1 -//│ ╔══[WARNING] :ftc must be enabled for functions with multiple parameter lists. +//│ ╔══[COMPILATION ERROR] :ftc must be enabled to desugar functions with multiple parameter lists. //│ ║ l.44: fun g()() = 1 //│ ╙── ^^^^^^^^^^^^^ //│ > FunDefn(Symbol("ctor$"), ([]), End, true) From af3147722f562c84b1d63772ea326686e8d02604 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 12 Mar 2026 22:44:36 +0800 Subject: [PATCH 263/268] remove redundant Ident type --- hkmc2/shared/src/test/mlscript-compile/Block.mls | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 33c519a3c8..6be8d38c56 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -17,8 +17,6 @@ type Literal = null | undefined | Str | Int | Num | Bool type ParamList = Array[Symbol] class Symbol(val name: Str) -type Ident = Symbol - class VirtualClassSymbol(val name: Str) extends Symbol(name) class ClassSymbol(val name: Str, val value, val paramsOpt: Option[ParamList], val auxParams: Array[ParamList]) extends Symbol(name) class ModuleSymbol(val name: Str, val value) extends Symbol(name) @@ -60,7 +58,7 @@ class Result with class Path extends Result with constructor - Select(val qual: Path, val name: Ident) + Select(val qual: Path, val name: Symbol) DynSelect(val qual: Path, val fld: Path, val arrayIdx: Bool) // is arrayIdx used? ValueRef(val l: Symbol) ValueLit(val lit: Literal) @@ -107,12 +105,10 @@ fun showLiteral(l: Literal) = fun showSymbol(s: Symbol) = s.toString() -fun showIdent(i: Ident) = showSymbol(i) - fun showPath(p: Path): Str = if p is Select(qual, name) then - "Select(" + showPath(qual) + ", " + showIdent(name) + ")" + "Select(" + showPath(qual) + ", " + showSymbol(name) + ")" DynSelect(qual, fld, arrayIdx) then "DynSelect(" + showPath(qual) + ", " + showPath(fld) + ", " + showBool(arrayIdx) + ")" ValueRef(l) then From 0199444692e6e6972a12376e75e3907db7e44e32 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Thu, 12 Mar 2026 22:47:56 +0800 Subject: [PATCH 264/268] fixup! update tests --- hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls b/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls index f502c47fa8..6630944b28 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/StageSymbols.mls @@ -51,5 +51,7 @@ staged module M with :ftc staged module M with fun f() = x => x + fun g()() = 1 //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("f"), ([]), Scoped([Symbol("tmp")], Assign(Symbol("tmp"), Instantiate(Ref(ClassSymbol("Function$", class Function$, None, [])), []), Return(Ref(Symbol("tmp")), false))), true) +//│ > FunDefn(Symbol("g"), ([]), Scoped([Symbol("tmp1")], Assign(Symbol("tmp1"), Instantiate(Ref(ClassSymbol("Function$1", class Function$, None, [])), []), Return(Ref(Symbol("tmp1")), false))), true) From 79b42cd4cc798905a28e5b2265b1bbf84b4907be Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 13 Mar 2026 11:58:50 +0800 Subject: [PATCH 265/268] cleanup --- .../scala/hkmc2/codegen/Instrumentation.scala | 3 +-- .../src/test/mlscript-compile/Block.mls | 19 ------------------- .../src/test/mlscript-compile/Shape.mls | 2 ++ .../test/mlscript/block-staging/Functions.mls | 5 ++--- 4 files changed, 5 insertions(+), 24 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index e22a5f5354..96cbba39df 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -5,7 +5,7 @@ import utils.* import hkmc2.Message.MessageContext import scala.collection.mutable.HashMap -import scala.util.chaining._ +import scala.util.chaining.* import mlscript.utils.*, shorthands.* @@ -126,7 +126,6 @@ class Instrumentation(using State, Raise, Ctx) extends BlockTransformer(new Symb blockCtor("ClassSymbol", Ls(toValue(name), path, paramsOpt, auxParams), symName)(k) case _: ModuleOrObjectSymbol => blockCtor("ModuleSymbol", Ls(toValue(name), path), symName)(k) - case _ => val name = scope.allocateOrGetName(sym) blockCtor("Symbol", Ls(toValue(name)), symName)(k) diff --git a/hkmc2/shared/src/test/mlscript-compile/Block.mls b/hkmc2/shared/src/test/mlscript-compile/Block.mls index 6be8d38c56..55854af63c 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Block.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Block.mls @@ -20,25 +20,6 @@ class Symbol(val name: Str) class VirtualClassSymbol(val name: Str) extends Symbol(name) class ClassSymbol(val name: Str, val value, val paramsOpt: Option[ParamList], val auxParams: Array[ParamList]) extends Symbol(name) class ModuleSymbol(val name: Str, val value) extends Symbol(name) -class Arm(val cse: Case, val body: Block) - -fun isPrimitiveType(sym: Symbol) = - if sym.name is - "Str" then true - "Int" then true - "Num" then true - "Bool" then true - "TypedArray" then true - else false - -fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = - if [sym.name, l] is - ["Str", l] and l is Str then true - ["Int", i] and i is Int then true - ["Num", n] and n is Num then true - ["Bool", b] and b is Bool then true - ["TypedArray", a] and a is TypedArray then true - else false // Classes defined in Block.scala diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index 70c935ec8f..ef445557bd 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -12,6 +12,7 @@ fun isPrimitiveType(sym: Symbol) = "Int" then true "Num" then true "Bool" then true + "TypedArray" then true else false fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = @@ -20,6 +21,7 @@ fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = ["Int", i] and i is Int then true ["Num", n] and n is Num then true ["Bool", b] and b is Bool then true + ["TypedArray", a] and a is TypedArray then true else false module Shape with... diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 089f58858a..705a61fe97 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -87,7 +87,6 @@ staged module OtherBlocks with //│ > FunDefn(Symbol("scope"), ([]), Scoped([Symbol("a")], Assign(Symbol("a"), Lit(1), Return(Call(Select(Select(Ref(ModuleSymbol("OtherBlocks", class OtherBlocks)), Symbol("scope")), Symbol("locally")), [Ref(Symbol("a"))]), false))), true) //│ > FunDefn(Symbol("breakAndLabel"), ([]), Scoped([Symbol("scrut")], Assign(Symbol("scrut"), Lit(1), Match(Ref(Symbol("scrut")), [Lit(2) -> Return(Lit(0), false), Lit(3) -> Return(Lit(0), false)], Return(Lit(0), false), End))), true) - staged module ClassDefs with class A //│ > FunDefn(Symbol("ctor$"), ([]), Define(ClsLikeDefn(ClassSymbol("A", class A, None, []), [], TODO), End), true) @@ -112,7 +111,7 @@ module A with //│ > FunDefn(Symbol("ctor$"), ([]), End, true) //│ > FunDefn(Symbol("f"), ([]), Return(Lit(1), false), true) -// TODO: reject this after removing Label and Break from Block IR +// TODO: force enable :ftc to desugar Label and Break staged module M with fun f() = if 1 is 0 then 2 @@ -129,7 +128,7 @@ staged module A with fun g() = {1 : 2} //│ ═══[COMPILATION ERROR] Other Blocks not supprted in staged module: AssignField(Ref(term:A/x,None),Ident(a),Lit(IntLit(0)),Return(Select(Ref(tmp:runtime,None),Ident(Unit)),false)) //│ ╔══[COMPILATION ERROR] Other Results not supported in staged module: Record(false,List(RcdArg(Some(Lit(IntLit(1))),Lit(IntLit(2))))) -//│ ║ l.129: fun g() = {1 : 2} +//│ ║ l.128: fun g() = {1 : 2} //│ ╙── ^ //│ > FunDefn(Symbol("ctor$"), ([]), Assign(Symbol("x"), Call(Ref(ClassSymbol("C", fun C { class: class C }, Some([Symbol("a")]), [])), [Lit(1)]), End), true) //│ ═══[RUNTIME ERROR] Error: MLscript call unexpectedly returned `undefined`, the forbidden value. From 15949d074fdaf94c7828da13b50c53d6debaff3b Mon Sep 17 00:00:00 2001 From: Ching Long Tin <26105652+ChingLongTin@users.noreply.github.com> Date: Fri, 13 Mar 2026 13:19:19 +0800 Subject: [PATCH 266/268] fix typo Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 96cbba39df..9f5f49ba23 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -94,7 +94,7 @@ class Instrumentation(using State, Raise, Ctx) extends BlockTransformer(new Symb // transformation helpers - // if sym is ClassSymbol, we may need pOpt to link to the path pointing the the value of the symbol + // if sym is ClassSymbol, we may need pOpt to link to the path pointing to the value of the symbol def transformSymbol(sym: Symbol, pOpt: Option[Path] = N, symName: Str = "sym")(k: Path => Block): Block = sym match case t: TermSymbol if t.defn.exists(_.sym.asClsOrMod.isDefined) => From f62f6a8443ee2fdce4ece7fe15eeb23c3df3ddc1 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 13 Mar 2026 13:23:37 +0800 Subject: [PATCH 267/268] implement fixes --- .../shared/src/main/scala/hkmc2/codegen/Instrumentation.scala | 4 ++-- hkmc2/shared/src/test/mlscript/block-staging/Functions.mls | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala index 9f5f49ba23..c84834dcbf 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Instrumentation.scala @@ -309,7 +309,7 @@ class Instrumentation(using State, Raise, Ctx) extends BlockTransformer(new Symb transformSymbol(labelSymbol): labelSymbol => blockCtor("Break", Ls(labelSymbol))(k(_, ctx)) case _ => - raise(ErrorReport(msg"Other Blocks not supprted in staged module: ${b.toString()}" -> N :: Nil)) + raise(ErrorReport(msg"Other Blocks not supported in staged module: ${b.toString()}" -> N :: Nil)) End() def transformFunDefn(f: FunDefn)(using Context)(k: Path => Block): Block = @@ -372,7 +372,7 @@ class Instrumentation(using State, Raise, Ctx) extends BlockTransformer(new Symb Define(newModule, rest) case b => b - def mkDefnMap(b: Block) = + def mkDefnMap(b: Block): Unit = val transformer = new BlockTransformer(new SymbolSubst()): override def applyDefn(defn: Defn)(k: Defn => Block) = defn match case c: ClsLikeDefn => diff --git a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls index 705a61fe97..304094d79b 100644 --- a/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls +++ b/hkmc2/shared/src/test/mlscript/block-staging/Functions.mls @@ -126,7 +126,7 @@ staged module A with let x = C(1) fun f() = set x.a = 0 fun g() = {1 : 2} -//│ ═══[COMPILATION ERROR] Other Blocks not supprted in staged module: AssignField(Ref(term:A/x,None),Ident(a),Lit(IntLit(0)),Return(Select(Ref(tmp:runtime,None),Ident(Unit)),false)) +//│ ═══[COMPILATION ERROR] Other Blocks not supported in staged module: AssignField(Ref(term:A/x,None),Ident(a),Lit(IntLit(0)),Return(Select(Ref(tmp:runtime,None),Ident(Unit)),false)) //│ ╔══[COMPILATION ERROR] Other Results not supported in staged module: Record(false,List(RcdArg(Some(Lit(IntLit(1))),Lit(IntLit(2))))) //│ ║ l.128: fun g() = {1 : 2} //│ ╙── ^ From d861b58f5f954e8adea8c01d801a84698cdec300 Mon Sep 17 00:00:00 2001 From: ChingLongTin <26105652+Sunny-Ching@users.noreply.github.com> Date: Fri, 13 Mar 2026 13:29:17 +0800 Subject: [PATCH 268/268] remove TypedArray branch classes staged into VirtualSymbol and literals in Block IR are independent, and Literals do not have TypedArray --- hkmc2/shared/src/test/mlscript-compile/Shape.mls | 2 -- 1 file changed, 2 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript-compile/Shape.mls b/hkmc2/shared/src/test/mlscript-compile/Shape.mls index ef445557bd..70c935ec8f 100644 --- a/hkmc2/shared/src/test/mlscript-compile/Shape.mls +++ b/hkmc2/shared/src/test/mlscript-compile/Shape.mls @@ -12,7 +12,6 @@ fun isPrimitiveType(sym: Symbol) = "Int" then true "Num" then true "Bool" then true - "TypedArray" then true else false fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = @@ -21,7 +20,6 @@ fun isPrimitiveTypeOf(sym: Symbol, l: Literal) = ["Int", i] and i is Int then true ["Num", n] and n is Num then true ["Bool", b] and b is Bool then true - ["TypedArray", a] and a is TypedArray then true else false module Shape with...