Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,15 @@ class FirstClassFunctionTransformer(using Elaborator.State, Elaborator.Ctx, Rais
private def getParamList(ts: TermSymbol): Option[ParamList] = ts.defn.flatMap(_.params.headOption)

override def applyPath(p: Path)(k: Path => Block): Block = p match
case ref @ Value.Ref(l: BlockMemberSymbol, disamb) => l.tsym match
case ref @ Value.Ref(l: BlockMemberSymbol, disamb) => disamb match
case Some(s: TermSymbol) if s.k is syntax.Fun =>
val params = getParamList(l).getOrElse(lastWords(s"Cannot get ${l.nme}'s parameter list."))
val clsDef = generateFCFunctionClass(ref, params)
val tmp = new TempSymbol(None)
val cls = Value.Ref(clsDef.sym, Some(clsDef.isym))
Scoped(Set(clsDef.sym, tmp), Define(clsDef, Assign(tmp, Instantiate(false, cls, Nil), k(Value.Ref(tmp, None)))))
case Some(_) => k(p)
case None => disamb match
case Some(t: TermSymbol) if t.k is syntax.Fun =>
val params = getParamList(l).getOrElse(lastWords(s"Cannot get ${t.nme}'s parameter list."))
val clsDef = generateFCFunctionClass(ref, params)
val tmp = new TempSymbol(None)
val cls = Value.Ref(clsDef.sym, Some(clsDef.isym))
Scoped(Set(clsDef.sym, tmp), Define(clsDef, Assign(tmp, Instantiate(false, cls, Nil), k(Value.Ref(tmp, None)))))
case Some(_) => k(p)
case _ =>
raise(ErrorReport(msg"Cannot determine if ${l.nme} is a function." -> ref.toLoc :: Nil,
source = Diagnostic.Source.Compilation))
k(p)
case None => lastWords(s"${l.nme}'s disamb cannot be empty.")
case sel: Select => sel.symbol match
case Some(s: TermSymbol) if (s.k is syntax.Fun) =>
val params = getParamList(s).getOrElse(lastWords(s"Cannot get ${s.nme}'s parameter list."))
Expand All @@ -72,6 +61,12 @@ class FirstClassFunctionTransformer(using Elaborator.State, Elaborator.Ctx, Rais
k(p)
case _ => k(p)

private def pathStartsWith(p: Path, symbol: Local): Bool = p match
case Value.Ref(l, _) => l is symbol
case Select(p, _) => pathStartsWith(p, symbol)
case DynSelect(p, _, _) => pathStartsWith(p, symbol)
case _ => false

override def applyResult(r: Result)(k: Result => Block): Block = r match
case c @ Call(fun, args) => applyArgs(args): args2 =>
def call(f: Path) = Call(f, args2)(c.isMlsFun, c.mayRaiseEffects, c.explicitTailCall)
Expand All @@ -85,7 +80,7 @@ class FirstClassFunctionTransformer(using Elaborator.State, Elaborator.Ctx, Rais
else k(call(sel.selSN("call")))
case _ =>
raise(ErrorReport(msg"Cannot determine if ${sel.name.name} is a function object." -> fun.toLoc :: Nil,
source = Diagnostic.Source.Compilation))
source = Diagnostic.Source.Compilation))
k(call(fun))
case s: DynSelect =>
raise(ErrorReport(msg"Cannot determine if the dynamic selection is a function object." -> s.toLoc :: Nil,
Expand Down
2 changes: 1 addition & 1 deletion hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx):
)

lazy val unreachableFn =
Select(Value.Ref(State.runtimeSymbol), Tree.Ident("unreachable"))(N)
Select(Value.Ref(State.runtimeSymbol), Tree.Ident("unreachable"))(S(State.unreachableSymbol))

def unit: Path =
Select(Value.Ref(State.runtimeSymbol), Tree.Ident("Unit"))(S(State.unitSymbol))
Expand Down
19 changes: 19 additions & 0 deletions hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ object Elaborator:
val Str = assumeBuiltinCls("Str")
val BigInt = assumeBuiltinCls("BigInt")
val Function = assumeBuiltinCls("Function")
val Error = assumeBuiltinCls("Error")
val Bool = assumeBuiltinCls("Bool")
val Object = assumeBuiltinCls("Object")
val Array = assumeBuiltinCls("Array")
Expand Down Expand Up @@ -257,6 +258,8 @@ object Elaborator:
val globalThisSymbol = TopLevelSymbol("globalThis")
val unitSymbol = ModuleOrObjectSymbol(DummyTypeDef(syntax.Obj), Ident("Unit"))
val loopEndSymbol = ModuleOrObjectSymbol(DummyTypeDef(syntax.Obj), Ident("LoopEnd"))
val tupleSymbol = ModuleOrObjectSymbol(DummyTypeDef(syntax.Mod), Ident("Tuple"))
val strSymbol = ModuleOrObjectSymbol(DummyTypeDef(syntax.Mod), Ident("Str"))
// In JavaScript, `import` can be used for getting current file path, as `import.meta`
val importSymbol = new VarSymbol(Ident("import"))
val noSymbol = NoSymbol()
Expand All @@ -277,6 +280,14 @@ object Elaborator:
val nonLocalRet =
val id = new Ident("ret")
BlockMemberSymbol(id.name, Nil, true)
val unreachableSymbol = TermSymbol(syntax.ImmutVal, N, new Ident("unreachable"))
val tupleGetSymbol = createFunSymbolInMod("get", "xs" :: "i" :: Nil, tupleSymbol)
val tupleSliceSymbol = createFunSymbolInMod("slice", "xs" :: "i" :: "j" :: Nil, tupleSymbol)
val tupleLazySliceSymbol = createFunSymbolInMod("lazySlice", "xs" :: "i" :: "j" :: Nil, tupleSymbol)
val strStartsWithSymbol = createFunSymbolInMod("startsWith", "string" :: "prefix" :: Nil, strSymbol)
val strGetSymbol = createFunSymbolInMod("get", "string" :: "i" :: Nil, strSymbol)
val strTakeSymbol = createFunSymbolInMod("take", "string" :: "n" :: Nil, strSymbol)
val strLeaveSymbol = createFunSymbolInMod("leave", "string" :: "n" :: Nil, strSymbol)
val (matchSuccessClsSymbol, matchSuccessTrmSymbol) =
val id = new Ident("MatchSuccess")
val td = TypeDef(syntax.Cls, App(id, Tup(Ident("output") :: Ident("bindings") :: Nil)), N)
Expand Down Expand Up @@ -323,6 +334,14 @@ object Elaborator:
def dbgUid(uid: Uid[Symbol]): Str =
if dbg then s"‹$uid›" else ""
// ^ we do not display the uid by default to avoid polluting diff-test outputs
// Create a term symbol for a function defined in the given module
private def createFunSymbolInMod(name: Str, paramNames: List[Str], mod: ModuleOrObjectSymbol) =
val sym = TermSymbol(syntax.Fun, N, Ident(name))
val bsym = BlockMemberSymbol(name, Nil, true)
val ps = PlainParamList(paramNames.map(s => Param.simple(VarSymbol(Ident(s)))))
sym.defn = S(TermDefinition(syntax.Fun, bsym, sym, ps :: Nil, N, N, N,
TermDefFlags(true), Modulefulness(S(mod))(false), Nil, N))
sym
transparent inline def State(using state: State): State = state

end Elaborator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ class Normalization(lowering: Lowering)(using tl: TL)(using Raise, Ctx, State) e
* match failure in the future.
*/
private def throwMatchErrorBlock =
Throw(Instantiate(mut = false, Select(Value.Ref(State.globalThisSymbol), Tree.Ident("Error"))(N),
Throw(Instantiate(mut = false, Select(Value.Ref(State.globalThisSymbol), Tree.Ident("Error"))(S(ctx.builtins.Error)),
Value.Lit(syntax.Tree.StrLit("match error")).asArg :: Nil)) // TODO add failed-match scrutinee info

import syntax.Keyword.{`if`, `while`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ trait TermSynthesizer(using State):
val parameters = parametersOpt.map(_.map(_ -> N))
FlatPattern.ClassLike(matchFailureClass, State.matchFailureClsSymbol, parameters, false)(Tree.Dummy)

protected lazy val tupleSlice = sel(sel(runtimeRef, "Tuple"), "slice")
protected lazy val tupleLazySlice = sel(sel(runtimeRef, "Tuple"), "lazySlice")
protected lazy val tupleGet = sel(sel(runtimeRef, "Tuple"), "get")
protected lazy val stringStartsWith = sel(sel(runtimeRef, "Str"), "startsWith")
protected lazy val stringGet = sel(sel(runtimeRef, "Str"), "get")
protected lazy val stringTake = sel(sel(runtimeRef, "Str"), "take")
protected lazy val stringLeave = sel(sel(runtimeRef, "Str"), "leave")
protected lazy val tupleSlice = sel(sel(runtimeRef, "Tuple"), "slice", State.tupleSliceSymbol)
protected lazy val tupleLazySlice = sel(sel(runtimeRef, "Tuple"), "lazySlice", State.tupleLazySliceSymbol)
protected lazy val tupleGet = sel(sel(runtimeRef, "Tuple"), "get", State.tupleGetSymbol)
protected lazy val stringStartsWith = sel(sel(runtimeRef, "Str"), "startsWith", State.strStartsWithSymbol)
protected lazy val stringGet = sel(sel(runtimeRef, "Str"), "get", State.strGetSymbol)
protected lazy val stringTake = sel(sel(runtimeRef, "Str"), "take", State.strTakeSymbol)
protected lazy val stringLeave = sel(sel(runtimeRef, "Str"), "leave", State.strLeaveSymbol)

/** Make a term that looks like `runtime.Tuple.get(t, i)`. */
protected final def callTupleGet(t: Term, i: Int, label: Str): Term =
Expand Down
2 changes: 1 addition & 1 deletion hkmc2/shared/src/test/mlscript/basics/LazySpreads.mls
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ fun sum2 = case
//│ return 0
//│ } else if (runtime.Tuple.isArrayLike(caseScrut) && caseScrut.length >= 2) {
//│ element0$ = runtime.Tuple.get(caseScrut, 0);
//│ middleElements3 = runtime.safeCall(runtime.Tuple.slice(caseScrut, 1, 1));
//│ middleElements3 = runtime.Tuple.slice(caseScrut, 1, 1);
//│ lastElement0$3 = runtime.Tuple.get(caseScrut, -1);
//│ y = lastElement0$3;
//│ xs = middleElements3;
Expand Down
2 changes: 1 addition & 1 deletion hkmc2/shared/src/test/mlscript/bbml/bbCodeGen.mls
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ fun nott = case
//│ return true;
//│ break;
//│ default:
//│ throw globalThis.Object.freeze(new globalThis.Error("match error"));
//│ throw globalThis.Object.freeze(new globalThis.Error.class("match error"));
//│ break;
//│ }
//│ });
Expand Down
6 changes: 3 additions & 3 deletions hkmc2/shared/src/test/mlscript/codegen/BlockPrinter.mls
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@ case
//│ Array(0) =>
//│ return Predef.print⁰("empty")
//│ Array(1+) =>
//│ set element0$ = runtime⁰.Tuple﹖.get(caseScrut, 0);
//│ set middleElements = runtime⁰.Tuple﹖.slice(caseScrut, 1, 0);
//│ set element0$ = runtime⁰.Tuple﹖.get(caseScrut, 0);
//│ set middleElements = runtime⁰.Tuple﹖.slice(caseScrut, 1, 0);
//│ set xs = middleElements;
//│ set x = element0$;
//│ return Predef.print⁰("non-empty", x)
//│ else
//│ throw new globalThis⁰.Error("match error")
//│ throw new globalThis⁰.Error("match error")
//│ end
//│ };
//│ lambda⁰
Expand Down
2 changes: 1 addition & 1 deletion hkmc2/shared/src/test/mlscript/codegen/FieldSymbols.mls
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ case
//│ set a = arg$Foo$0$;
//│ return a
//│ else
//│ throw new globalThis⁰.Error("match error")
//│ throw new globalThis⁰.Error("match error")
//│ end
//│ };
//│ lambda⁰
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ fun f(x, y, b) =
//│ this.#b = b;
//│ }
//│ #Function$$cap;
//│ #b;
//│ #y;
//│ #b;
//│ call(z) {
//│ return lambda1(this.#y, this.#b, z)
//│ }
Expand Down Expand Up @@ -1105,3 +1105,41 @@ foo(print)
//│ tmp40 = globalThis.Object.freeze(new Function$77());
//│ foo14(tmp40)
//│ >


if true is true then print("true")
//│ > true


if 0 is
Bool then 1
Str then 1
0 then 0
else 2
//│ = 0


class Foo(val x)


if Foo(1) is
Foo(x) then x
else 0
//│ = 1


if [1, 2, 3] is
[x, y] then x + y
[x, y, z] then x + y + z
[x, ...y] then x
else 0
//│ = 6


class Foo(val x)

let foo = Foo(1) in foo.Foo#x
//│ = 1

let foo = new Foo(1) in foo.Foo#x
//│ = 1
2 changes: 1 addition & 1 deletion hkmc2/shared/src/test/mlscript/lifter/ClassInFun.mls
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ f().foo()
//│ }
//│ }
//│ #Good$cap;
//│ #x;
//│ #y;
//│ #x;
//│ #scope0$cap;
//│ foo() {
//│ let tmp6, tmp7;
Expand Down
2 changes: 1 addition & 1 deletion hkmc2/shared/src/test/mlscript/std/FingerTreeListTest.mls
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ if xs is
//│ let ls, a, middleElements, element0$;
//│ if (runtime.Tuple.isArrayLike(xs1) && xs1.length >= 1) {
//│ element0$ = runtime.Tuple.get(xs1, 0);
//│ middleElements = runtime.safeCall(runtime.Tuple.slice(xs1, 1, 0));
//│ middleElements = runtime.Tuple.slice(xs1, 1, 0);
//│ ls = middleElements;
//│ a = element0$;
//│ globalThis.Object.freeze([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,14 @@ if
//│ > x is true and
//│ > z is true then 1
//│ > y is []=1 and
//│ > let tmp:element0$ = ((tmp:runtime.)Tuple.)get(y, 0)
//│ > let tmp:element0$ = ((tmp:runtime.)Tuple.)get‹term:get›(y, 0)
//│ > let b = tmp:element0$
//│ > else
//│ > let x
//│ > x = 1
//│ > builtin:+(x, b)
//│ > y is []=1 and
//│ > let tmp:element0$ = ((tmp:runtime.)Tuple.)get(y, 0)
//│ > let tmp:element0$ = ((tmp:runtime.)Tuple.)get‹term:get›(y, 0)
//│ > let b = tmp:element0$
//│ > else
//│ > let x
Expand Down
6 changes: 3 additions & 3 deletions hkmc2/shared/src/test/mlscript/ucs/patterns/RestTuple.mls
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fun nonsense(xs) = if xs is
//│ nonsense = function nonsense(xs) {
//│ let ys, middleElements;
//│ if (runtime.Tuple.isArrayLike(xs) && xs.length >= 0) {
//│ middleElements = runtime.safeCall(runtime.Tuple.slice(xs, 0, 0));
//│ middleElements = runtime.Tuple.slice(xs, 0, 0);
//│ ys = middleElements;
//│ return ys
//│ } else { throw globalThis.Object.freeze(new globalThis.Error("match error")) }
Expand All @@ -32,7 +32,7 @@ fun lead_and_last(xs) = if xs is
//│ let x, ys, y, lastElement0$, middleElements, element0$;
//│ if (runtime.Tuple.isArrayLike(xs) && xs.length >= 2) {
//│ element0$ = runtime.Tuple.get(xs, 0);
//│ middleElements = runtime.safeCall(runtime.Tuple.slice(xs, 1, 1));
//│ middleElements = runtime.Tuple.slice(xs, 1, 1);
//│ lastElement0$ = runtime.Tuple.get(xs, -1);
//│ y = lastElement0$;
//│ ys = middleElements;
Expand Down Expand Up @@ -68,7 +68,7 @@ fun nested_tuple_patterns(xs) = if xs is
//│ split_default$: {
//│ if (runtime.Tuple.isArrayLike(xs) && xs.length >= 2) {
//│ element0$ = runtime.Tuple.get(xs, 0);
//│ middleElements = runtime.safeCall(runtime.Tuple.slice(xs, 1, 1));
//│ middleElements = runtime.Tuple.slice(xs, 1, 1);
//│ lastElement0$ = runtime.Tuple.get(xs, -1);
//│ if (runtime.Tuple.isArrayLike(middleElements) && middleElements.length === 2) {
//│ element0$1 = runtime.Tuple.get(middleElements, 0);
Expand Down
Loading