From c389926fa4ec63779bd0906c67a0ef1261baf4bf Mon Sep 17 00:00:00 2001 From: Waterlens Date: Thu, 3 Oct 2024 17:25:33 +0800 Subject: [PATCH] Sync IR changes (#225) --- .github/workflows/nix.yml | 23 + .github/workflows/scala.yml | 27 - build.sbt | 6 +- .../compiler/{optimizer => }/Document.scala | 4 +- .../mlscript/compiler/codegen/CppAst.scala | 210 + .../compiler/codegen/CppCodeGen.scala | 234 ++ .../compiler/codegen/CppCompilerHost.scala | 44 + .../scala/mlscript/compiler/ir/Builder.scala | 779 +++- .../compiler/ir/DefnRefResolver.scala | 33 - .../scala/mlscript/compiler/ir/Fresh.scala | 5 +- .../main/scala/mlscript/compiler/ir/IR.scala | 438 ++- .../scala/mlscript/compiler/ir/Interp.scala | 475 +-- .../mlscript/compiler/ir/RefResolver.scala | 55 + .../mlscript/compiler/ir/Validator.scala | 31 +- .../compiler/optimizer/Analysis.scala | 16 +- .../compiler/optimizer/TailRecOpt.scala | 85 +- .../compiler/simpledef/Simpledef.scala | 2 +- compiler/shared/test/diff-ir/Class.mls | 182 + compiler/shared/test/diff-ir/Currying.mls | 95 + compiler/shared/test/diff-ir/IR.mls | 635 ++- compiler/shared/test/diff-ir/IRComplex.mls | 473 +-- compiler/shared/test/diff-ir/IRRec.mls | 1845 +++++---- compiler/shared/test/diff-ir/IRTailRec.mls | 3455 ++++++----------- compiler/shared/test/diff-ir/LiftClass.mls | 158 + compiler/shared/test/diff-ir/LiftFun.mls | 186 + compiler/shared/test/diff-ir/LiftLambda.mls | 87 + compiler/shared/test/diff-ir/Override.mls | 48 + compiler/shared/test/diff-ir/cpp/Makefile | 26 + compiler/shared/test/diff-ir/cpp/mlsprelude.h | 568 +++ compiler/shared/test/diff-ir/gcd.mls | 823 ++++ .../test/scala/mlscript/compiler/Test.scala | 2 +- .../test/scala/mlscript/compiler/TestIR.scala | 90 +- flake.lock | 97 + flake.nix | 34 + project/build.properties | 2 +- project/plugins.sbt | 4 +- shared/src/main/scala/mlscript/NewLexer.scala | 54 + .../src/test/scala/mlscript/DiffTests.scala | 29 +- 38 files changed, 6780 insertions(+), 4580 deletions(-) create mode 100644 .github/workflows/nix.yml delete mode 100644 .github/workflows/scala.yml rename compiler/shared/main/scala/mlscript/compiler/{optimizer => }/Document.scala (95%) create mode 100644 compiler/shared/main/scala/mlscript/compiler/codegen/CppAst.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/codegen/CppCodeGen.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/codegen/CppCompilerHost.scala delete mode 100644 compiler/shared/main/scala/mlscript/compiler/ir/DefnRefResolver.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/ir/RefResolver.scala create mode 100644 compiler/shared/test/diff-ir/Class.mls create mode 100644 compiler/shared/test/diff-ir/Currying.mls create mode 100644 compiler/shared/test/diff-ir/LiftClass.mls create mode 100644 compiler/shared/test/diff-ir/LiftFun.mls create mode 100644 compiler/shared/test/diff-ir/LiftLambda.mls create mode 100644 compiler/shared/test/diff-ir/Override.mls create mode 100644 compiler/shared/test/diff-ir/cpp/Makefile create mode 100644 compiler/shared/test/diff-ir/cpp/mlsprelude.h create mode 100644 compiler/shared/test/diff-ir/gcd.mls create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml new file mode 100644 index 0000000000..2623f85c29 --- /dev/null +++ b/.github/workflows/nix.yml @@ -0,0 +1,23 @@ +name: Cpp Backend CI with Nix + +on: + pull_request: + push: + branches: [ mlscript ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@main + - uses: rrbutani/use-nix-shell-action@v1 + with: + devShell: .#default + - name: Install TypeScript + run: npm ci + - name: Run test + run: sbt -J-Xmx4096M -J-Xss4M test + - name: Check no changes + run: git diff-files -p --exit-code diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml deleted file mode 100644 index 42559c2da7..0000000000 --- a/.github/workflows/scala.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Scala CI - -on: - push: - branches: [ mlscript ] - pull_request: - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 - with: - java-version: 1.8 - - uses: actions/setup-node@v3 - with: - node-version: '17.x' - - name: Install TypeScript - run: npm ci - - name: Run tests - run: sbt -J-Xmx4096M -J-Xss4M test - - name: Check no changes - run: git diff-files -p --exit-code diff --git a/build.sbt b/build.sbt index 883cb517fa..bf2fb754d8 100644 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,7 @@ import Wart._ enablePlugins(ScalaJSPlugin) -ThisBuild / scalaVersion := "2.13.12" +ThisBuild / scalaVersion := "2.13.14" ThisBuild / version := "0.1.0-SNAPSHOT" ThisBuild / organization := "io.lptk" ThisBuild / organizationName := "LPTK" @@ -52,7 +52,7 @@ lazy val mlscript = crossProject(JSPlatform, JVMPlatform).in(file(".")) ) .jsSettings( scalaJSUseMainModuleInitializer := true, - libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.1.0", + libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.2.0", ) lazy val mlscriptJVM = mlscript.jvm @@ -79,7 +79,7 @@ lazy val ts2mlsTest = project.in(file("ts2mls")) lazy val compiler = crossProject(JSPlatform, JVMPlatform).in(file("compiler")) .settings( name := "mlscript-compiler", - scalaVersion := "3.1.3", + scalaVersion := "3.3.3", sourceDirectory := baseDirectory.value.getParentFile()/"shared", watchSources += WatchSource( baseDirectory.value.getParentFile()/"shared"/"test"/"diff", "*.mls", NothingFilter), diff --git a/compiler/shared/main/scala/mlscript/compiler/optimizer/Document.scala b/compiler/shared/main/scala/mlscript/compiler/Document.scala similarity index 95% rename from compiler/shared/main/scala/mlscript/compiler/optimizer/Document.scala rename to compiler/shared/main/scala/mlscript/compiler/Document.scala index d5add5617b..22c938e4e4 100644 --- a/compiler/shared/main/scala/mlscript/compiler/optimizer/Document.scala +++ b/compiler/shared/main/scala/mlscript/compiler/Document.scala @@ -1,4 +1,4 @@ -package mlscript.compiler.optimizer +package mlscript.compiler.utils enum Document: case Indented(content: Document) @@ -10,7 +10,7 @@ enum Document: def <:>(other: Document) = line(List(this, other)) def <#>(other: Document) = line(List(this, other), sep = "") - override def toString(): String = print + override def toString: String = print def print: String = { val sb = StringBuffer() diff --git a/compiler/shared/main/scala/mlscript/compiler/codegen/CppAst.scala b/compiler/shared/main/scala/mlscript/compiler/codegen/CppAst.scala new file mode 100644 index 0000000000..ef054b0268 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/codegen/CppAst.scala @@ -0,0 +1,210 @@ +package mlscript.compiler.codegen.cpp + +import mlscript._ +import mlscript.utils._ +import mlscript.utils.shorthands._ +import mlscript.compiler.utils._ + +import scala.language.implicitConversions + +given Conversion[String, Document] = raw + +enum Specifier: + case Extern + case Static + case Inline + + def toDocument = raw: + this match + case Extern => "extern" + case Static => "static" + case Inline => "inline" + + override def toString: Str = toDocument.print + +object Type: + def toDocuments(args: Ls[Type], sep: Document, extraTypename: Bool = false): Document = + args.iterator.zipWithIndex.map { + case (x, 0) => + x.toDocument(extraTypename) + case (x, _) => + sep <#> x.toDocument(extraTypename) + }.fold(raw(""))(_ <#> _) + + def toDocuments(args: Ls[(Str, Type)], sep: Document): Document = + args.iterator.zipWithIndex.map { + case (x, 0) => + x._2.toDocument() <:> raw(x._1) + case (x, _) => + sep <#> x._2.toDocument() <:> raw(x._1) + }.fold(raw(""))(_ <#> _) + +enum Type: + case Prim(name: Str) + case Ptr(inner: Type) + case Ref(inner: Type) + case Array(inner: Type, size: Opt[Int]) + case FuncPtr(ret: Type, args: List[Type]) + case Struct(name: Str) + case Enum(name: Str) + case Template(name: Str, args: List[Type]) + case Var(name: Str) + case Qualifier(inner: Type, qual: Str) + + def toDocument(extraTypename: Bool = false): Document = + def aux(x: Type): Document = x match + case Prim(name) => name + case Ptr(inner) => aux(inner) <#> "*" + case Ref(inner) => aux(inner) <#> "&" + case Array(inner, size) => aux(inner) <#> "[" <#> size.fold(raw(""))(x => x.toString) <#> "]" + case FuncPtr(ret, args) => aux(ret) <#> "(" <#> Type.toDocuments(args, sep = ", ") <#> ")" + case Struct(name) => s"struct $name" + case Enum(name) => s"enum $name" + case Template(name, args) => s"$name" <#> "<" <#> Type.toDocuments(args, sep = ", ") <#> ">" + case Var(name) => name + case Qualifier(inner, qual) => aux(inner) <:> qual + aux(this) + + override def toString: Str = toDocument().print + +object Stmt: + def toDocuments(decl: Ls[Decl], stmts: Ls[Stmt]): Document = + stack_list(decl.map(_.toDocument) ++ stmts.map(_.toDocument)) + +enum Stmt: + case AutoBind(lhs: Ls[Str], rhs: Expr) + case Assign(lhs: Str, rhs: Expr) + case Return(expr: Expr) + case If(cond: Expr, thenStmt: Stmt, elseStmt: Opt[Stmt]) + case While(cond: Expr, body: Stmt) + case For(init: Stmt, cond: Expr, update: Stmt, body: Stmt) + case ExprStmt(expr: Expr) + case Break + case Continue + case Block(decl: Ls[Decl], stmts: Ls[Stmt]) + case Switch(expr: Expr, cases: Ls[(Expr, Stmt)]) + case Raw(stmt: Str) + + def toDocument: Document = + def aux(x: Stmt): Document = x match + case AutoBind(lhs, rhs) => + lhs match + case Nil => rhs.toDocument + case x :: Nil => "auto" <:> x <:> "=" <:> rhs.toDocument <#> ";" + case _ => "auto" <:> lhs.mkString("[", ",", "]") <:> "=" <:> rhs.toDocument <#> ";" + case Assign(lhs, rhs) => lhs <#> " = " <#> rhs.toDocument <#> ";" + case Return(expr) => "return " <#> expr.toDocument <#> ";" + case If(cond, thenStmt, elseStmt) => + "if (" <#> cond.toDocument <#> ")" <#> thenStmt.toDocument <:> elseStmt.fold(raw(""))(x => "else" <:> x.toDocument) + case While(cond, body) => + "while (" <#> cond.toDocument <#> ")" <#> body.toDocument + case For(init, cond, update, body) => + "for (" <#> init.toDocument <#> "; " <#> cond.toDocument <#> "; " <#> update.toDocument <#> ")" <#> body.toDocument + case ExprStmt(expr) => expr.toDocument <#> ";" + case Break => "break;" + case Continue => "continue;" + case Block(decl, stmts) => + stack( + "{", + Stmt.toDocuments(decl, stmts) |> indent, + "}") + case Switch(expr, cases) => + "switch (" <#> expr.toDocument <#> ")" <#> "{" <#> stack_list(cases.map { + case (cond, stmt) => "case " <#> cond.toDocument <#> ":" <#> stmt.toDocument + }) <#> "}" + case Raw(stmt) => stmt + aux(this) + +object Expr: + def toDocuments(args: Ls[Expr], sep: Document): Document = + args.zipWithIndex.map { + case (x, i) => + if i == 0 then x.toDocument + else sep <#> x.toDocument + }.fold(raw(""))(_ <#> _) + +enum Expr: + case Var(name: Str) + case IntLit(value: BigInt) + case DoubleLit(value: Double) + case StrLit(value: Str) + case CharLit(value: Char) + case Call(func: Expr, args: Ls[Expr]) + case Member(expr: Expr, member: Str) + case Index(expr: Expr, index: Expr) + case Unary(op: Str, expr: Expr) + case Binary(op: Str, lhs: Expr, rhs: Expr) + case Initializer(exprs: Ls[Expr]) + case Constructor(name: Str, init: Expr) + + def toDocument: Document = + def aux(x: Expr): Document = x match + case Var(name) => name + case IntLit(value) => value.toString + case DoubleLit(value) => value.toString + case StrLit(value) => s"\"$value\"" // need more reliable escape utils + case CharLit(value) => value.toInt.toString + case Call(func, args) => aux(func) <#> "(" <#> Expr.toDocuments(args, sep = ", ") <#> ")" + case Member(expr, member) => aux(expr) <#> "->" <#> member + case Index(expr, index) => aux(expr) <#> "[" <#> aux(index) <#> "]" + case Unary(op, expr) => "(" <#> op <#> aux(expr) <#> ")" + case Binary(op, lhs, rhs) => "(" <#> aux(lhs) <#> op <#> aux(rhs) <#> ")" + case Initializer(exprs) => "{" <#> Expr.toDocuments(exprs, sep = ", ") <#> "}" + case Constructor(name, init) => name <#> init.toDocument + aux(this) + +case class CompilationUnit(includes: Ls[Str], decls: Ls[Decl], defs: Ls[Def]): + def toDocument: Document = + stack_list(includes.map(x => raw(x)) ++ decls.map(_.toDocument) ++ defs.map(_.toDocument)) + def toDocumentWithoutHidden: Document = + val hiddenNames = Set( + "HiddenTheseEntities", "True", "False", "Callable", "List", "Cons", "Nil", "Option", "Some", "None", "Pair", "Tuple2", "Tuple3", "Nat", "S", "O" + ) + stack_list(defs.filterNot { + case Def.StructDef(name, _, _, _) => hiddenNames.contains(name.stripPrefix("_mls_")) + case _ => false + }.map(_.toDocument)) + +enum Decl: + case StructDecl(name: Str) + case EnumDecl(name: Str) + case FuncDecl(ret: Type, name: Str, args: Ls[Type]) + case VarDecl(name: Str, typ: Type) + + def toDocument: Document = + def aux(x: Decl): Document = x match + case StructDecl(name) => s"struct $name;" + case EnumDecl(name) => s"enum $name;" + case FuncDecl(ret, name, args) => ret.toDocument() <#> s" $name(" <#> Type.toDocuments(args, sep = ", ") <#> ");" + case VarDecl(name, typ) => typ.toDocument() <#> s" $name;" + aux(this) + +enum Def: + case StructDef(name: Str, fields: Ls[(Str, Type)], inherit: Opt[Ls[Str]], methods: Ls[Def] = Ls.empty) + case EnumDef(name: Str, fields: Ls[(Str, Opt[Int])]) + case FuncDef(specret: Type, name: Str, args: Ls[(Str, Type)], body: Stmt.Block, or: Bool = false, virt: Bool = false) + case VarDef(typ: Type, name: Str, init: Opt[Expr]) + case RawDef(raw: Str) + + def toDocument: Document = + def aux(x: Def): Document = x match + case StructDef(name, fields, inherit, defs) => + stack( + s"struct $name" <#> (if inherit.nonEmpty then ": public" <:> inherit.get.mkString(", ") else "" ) <:> "{", + stack_list(fields.map { + case (name, typ) => typ.toDocument() <#> " " <#> name <#> ";" + }) |> indent, + stack_list(defs.map(_.toDocument)) |> indent, + "};" + ) + case EnumDef(name, fields) => + s"enum $name" <:> "{" <#> stack_list(fields.map { + case (name, value) => value.fold(s"$name")(x => s"$name = $x") + }) <#> "};" + case FuncDef(specret, name, args, body, or, virt) => + (if virt then "virtual " else "") + <#> specret.toDocument() <#> s" $name(" <#> Type.toDocuments(args, sep = ", ") <#> ")" <#> (if or then " override" else "") <#> body.toDocument + case VarDef(typ, name, init) => + typ.toDocument() <#> s" $name" <#> init.fold(raw(""))(x => " = " <#> x.toDocument) <#> raw(";") + case RawDef(x) => x + aux(this) \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/codegen/CppCodeGen.scala b/compiler/shared/main/scala/mlscript/compiler/codegen/CppCodeGen.scala new file mode 100644 index 0000000000..20d08050d2 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/codegen/CppCodeGen.scala @@ -0,0 +1,234 @@ +package mlscript.compiler.codegen.cpp + +import mlscript.compiler.ir.{Expr => IExpr, _} +import mlscript.compiler.utils._ +import mlscript.utils._ +import mlscript.utils.shorthands._ +import scala.collection.mutable.ListBuffer + +def codegen(prog: Program): CompilationUnit = + val codegen = CppCodeGen() + codegen.codegen(prog) + +private class CppCodeGen: + def mapName(name: Name): Str = "_mls_" + name.str.replace('$', '_').replace('\'', '_') + def mapName(name: Str): Str = "_mls_" + name.replace('$', '_').replace('\'', '_') + val freshName = Fresh(div = '_'); + val mlsValType = Type.Prim("_mlsValue") + val mlsUnitValue = Expr.Call(Expr.Var("_mlsValue::create<_mls_Unit>"), Ls()); + val mlsRetValue = "_mls_retval" + val mlsRetValueDecl = Decl.VarDecl(mlsRetValue, mlsValType) + val mlsMainName = "_mlsMain" + val mlsPrelude = "#include \"mlsprelude.h\"" + val mlsPreludeImpl = "#include \"mlsprelude.cpp\"" + val mlsInternalClass = Set("True", "False", "Boolean", "Callable") + val mlsObject = "_mlsObject" + val mlsBuiltin = "builtin" + val mlsEntryPoint = s"int main() { return _mlsLargeStack(_mlsMainWrapper); }"; + def mlsIntLit(x: BigInt) = Expr.Call(Expr.Var("_mlsValue::fromIntLit"), Ls(Expr.IntLit(x))) + def mlsStrLit(x: Str) = Expr.Call(Expr.Var("_mlsValue::fromStrLit"), Ls(Expr.StrLit(x))) + def mlsCharLit(x: Char) = Expr.Call(Expr.Var("_mlsValue::fromIntLit"), Ls(Expr.CharLit(x))) + def mlsNewValue(cls: Str, args: Ls[Expr]) = Expr.Call(Expr.Var(s"_mlsValue::create<$cls>"), args) + def mlsIsValueOf(cls: Str, scrut: Expr) = Expr.Call(Expr.Var(s"_mlsValue::isValueOf<$cls>"), Ls(scrut)) + def mlsIsIntLit(scrut: Expr, lit: mlscript.IntLit) = Expr.Call(Expr.Var("_mlsValue::isIntLit"), Ls(scrut, Expr.IntLit(lit.value))) + def mlsDebugPrint(x: Expr) = Expr.Call(Expr.Var("_mlsValue::print"), Ls(x)) + def mlsTupleValue(init: Expr) = Expr.Constructor("_mlsValue::tuple", init) + def mlsAs(name: Str, cls: Str) = Expr.Var(s"_mlsValue::as<$cls>($name)") + def mlsAsUnchecked(name: Str, cls: Str) = Expr.Var(s"_mlsValue::cast<$cls>($name)") + def mlsObjectNameMethod(name: Str) = s"constexpr static inline const char *typeName = \"${name}\";" + def mlsTypeTag() = s"constexpr static inline uint32_t typeTag = nextTypeTag();" + def mlsTypeTag(n: Int) = s"constexpr static inline uint32_t typeTag = $n;" + def mlsCommonCreateMethod(cls: Str, fields: Ls[Str], id: Int) = + val parameters = fields.map{x => s"_mlsValue $x"}.mkString(", ") + val fieldsAssignment = fields.map{x => s"_mlsVal->$x = $x; "}.mkString + s"static _mlsValue create($parameters) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) $cls; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; $fieldsAssignment return _mlsValue(_mlsVal); }" + def mlsCommonPrintMethod(fields: Ls[Str]) = + if fields.isEmpty then s"virtual void print() const override { std::printf(\"%s\", typeName); }" + else + val fieldsPrint = fields.map{x => s"this->$x.print(); "}.mkString("std::printf(\", \"); ") + s"virtual void print() const override { std::printf(\"%s\", typeName); std::printf(\"(\"); $fieldsPrint std::printf(\")\"); }" + def mlsCommonDestructorMethod(cls: Str, fields: Ls[Str]) = + val fieldsDeletion = fields.map{x => s"_mlsValue::destroy(this->$x); "}.mkString + s"virtual void destroy() override { $fieldsDeletion operator delete (this, std::align_val_t(_mlsAlignment)); }" + def mlsThrowNonExhaustiveMatch = Stmt.Raw("_mlsNonExhaustiveMatch();"); + def mlsCall(fn: Str, args: Ls[Expr]) = Expr.Call(Expr.Var("_mlsCall"), Expr.Var(fn) :: args) + def mlsMethodCall(cls: ClassRef, method: Str, args: Ls[Expr]) = + Expr.Call(Expr.Member(Expr.Call(Expr.Var(s"_mlsMethodCall<${cls.name |> mapName}>"), Ls(args.head)), method), args.tail) + def mlsFnWrapperName(fn: Str) = s"_mlsFn_$fn" + def mlsFnCreateMethod(fn: Str) = s"static _mlsValue create() { static _mlsFn_$fn mlsFn alignas(_mlsAlignment); mlsFn.refCount = stickyRefCount; mlsFn.tag = typeTag; return _mlsValue(&mlsFn); }" + def mlsNeverValue(n: Int) = if (n <= 1) then Expr.Call(Expr.Var(s"_mlsValue::never"), Ls()) else Expr.Call(Expr.Var(s"_mlsValue::never<$n>"), Ls()) + + case class Ctx( + defnCtx: Set[Str], + ) + + def codegenClassInfo(using ctx: Ctx)(cls: ClassInfo): (Opt[Def], Decl) = + val fields = cls.fields.map{x => (x |> mapName, mlsValType)} + val parents = if cls.parents.nonEmpty then cls.parents.toList.map(mapName) else mlsObject :: Nil + val decl = Decl.StructDecl(cls.name |> mapName) + if mlsInternalClass.contains(cls.name) then return (None, decl) + val theDef = Def.StructDef( + cls.name |> mapName, fields, + if parents.nonEmpty then Some(parents) else None, + Ls(Def.RawDef(mlsObjectNameMethod(cls.name)), + Def.RawDef(mlsTypeTag()), + Def.RawDef(mlsCommonPrintMethod(cls.fields.map(mapName))), + Def.RawDef(mlsCommonDestructorMethod(cls.name |> mapName, cls.fields.map(mapName))), + Def.RawDef(mlsCommonCreateMethod(cls.name |> mapName, cls.fields.map(mapName), cls.id))) + ++ cls.methods.map{case (name, defn) => { + val (theDef, decl) = codegenDefn(using Ctx(ctx.defnCtx + cls.name))(defn) + theDef match + case x @ Def.FuncDef(_, name, _, _, _, _) => x.copy(virt = true) + case _ => theDef + }} + ) + (S(theDef), decl) + + def toExpr(texpr: TrivialExpr, reifyUnit: Bool = false)(using ctx: Ctx): Opt[Expr] = texpr match + case IExpr.Ref(name) => S(Expr.Var(name |> mapName)) + case IExpr.Literal(mlscript.IntLit(x)) => S(mlsIntLit(x)) + case IExpr.Literal(mlscript.DecLit(x)) => S(mlsIntLit(x.toBigInt)) + case IExpr.Literal(mlscript.StrLit(x)) => S(mlsStrLit(x)) + case IExpr.Literal(mlscript.UnitLit(_)) => if reifyUnit then S(mlsUnitValue) else None + + def toExpr(texpr: TrivialExpr)(using ctx: Ctx): Expr = texpr match + case IExpr.Ref(name) => Expr.Var(name |> mapName) + case IExpr.Literal(mlscript.IntLit(x)) => mlsIntLit(x) + case IExpr.Literal(mlscript.DecLit(x)) => mlsIntLit(x.toBigInt) + case IExpr.Literal(mlscript.StrLit(x)) => mlsStrLit(x) + case IExpr.Literal(mlscript.UnitLit(_)) => mlsUnitValue + + + def wrapMultiValues(exprs: Ls[TrivialExpr])(using ctx: Ctx): Expr = exprs match + case x :: Nil => toExpr(x, reifyUnit = true).get + case _ => + val init = Expr.Initializer(exprs.map{x => toExpr(x)}) + mlsTupleValue(init) + + def codegenCaseWithIfs(scrut: Name, cases: Ls[(Pat, Node)], default: Opt[Node], storeInto: Str)(using decls: Ls[Decl], stmts: Ls[Stmt])(using ctx: Ctx): (Ls[Decl], Ls[Stmt]) = + val scrutName = mapName(scrut) + val init: Stmt = + default.fold(mlsThrowNonExhaustiveMatch)(x => { + val (decls2, stmts2) = codegen(x, storeInto)(using Ls.empty, Ls.empty[Stmt]) + Stmt.Block(decls2, stmts2) + }) + val stmt = cases.foldRight(S(init)) { + case ((Pat.Class(cls), arm), nextarm) => + val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) + val stmt = Stmt.If(mlsIsValueOf(cls.name |> mapName, Expr.Var(scrutName)), Stmt.Block(decls2, stmts2), nextarm) + S(stmt) + case ((Pat.Lit(i @ mlscript.IntLit(_)), arm), nextarm) => + val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) + val stmt = Stmt.If(mlsIsIntLit(Expr.Var(scrutName), i), Stmt.Block(decls2, stmts2), nextarm) + S(stmt) + case _ => ??? + } + (decls, stmt.fold(stmts)(x => stmts :+ x)) + + def codegenJumpWithCall(defn: DefnRef, args: Ls[TrivialExpr], storeInto: Opt[Str])(using decls: Ls[Decl], stmts: Ls[Stmt])(using ctx: Ctx): (Ls[Decl], Ls[Stmt]) = + val call = Expr.Call(Expr.Var(defn.name |> mapName), args.map(toExpr)) + val stmts2 = stmts ++ Ls(storeInto.fold(Stmt.Return(call))(x => Stmt.Assign(x, call))) + (decls, stmts2) + + def codegenOps(op: Str, args: Ls[TrivialExpr])(using ctx: Ctx) = op match + case "+" => Expr.Binary("+", toExpr(args(0)), toExpr(args(1))) + case "-" => Expr.Binary("-", toExpr(args(0)), toExpr(args(1))) + case "*" => Expr.Binary("*", toExpr(args(0)), toExpr(args(1))) + case "/" => Expr.Binary("/", toExpr(args(0)), toExpr(args(1))) + case "%" => Expr.Binary("%", toExpr(args(0)), toExpr(args(1))) + case "==" => Expr.Binary("==", toExpr(args(0)), toExpr(args(1))) + case "!=" => Expr.Binary("!=", toExpr(args(0)), toExpr(args(1))) + case "<" => Expr.Binary("<", toExpr(args(0)), toExpr(args(1))) + case "<=" => Expr.Binary("<=", toExpr(args(0)), toExpr(args(1))) + case ">" => Expr.Binary(">", toExpr(args(0)), toExpr(args(1))) + case ">=" => Expr.Binary(">=", toExpr(args(0)), toExpr(args(1))) + case "&&" => Expr.Binary("&&", toExpr(args(0)), toExpr(args(1))) + case "||" => Expr.Binary("||", toExpr(args(0)), toExpr(args(1))) + case "!" => Expr.Unary("!", toExpr(args(0))) + case _ => mlscript.utils.TODO("codegenOps") + + + def codegen(expr: IExpr)(using ctx: Ctx): Expr = expr match + case x @ (IExpr.Ref(_) | IExpr.Literal(_)) => toExpr(x, reifyUnit = true).get + case IExpr.CtorApp(cls, args) => mlsNewValue(cls.name |> mapName, args.map(toExpr)) + case IExpr.Select(name, cls, field) => Expr.Member(mlsAsUnchecked(name |> mapName, cls.name |> mapName), field |> mapName) + case IExpr.BasicOp(name, args) => codegenOps(name, args) + case IExpr.AssignField(assignee, cls, field, value) => mlscript.utils.TODO("Assign field in the backend") + + def codegenBuiltin(names: Ls[Name], builtin: Str, args: Ls[TrivialExpr])(using ctx: Ctx): Ls[Stmt] = builtin match + case "error" => Ls(Stmt.Raw("throw std::runtime_error(\"Error\");"), Stmt.AutoBind(names.map(mapName), mlsNeverValue(names.size))) + case _ => Ls(Stmt.AutoBind(names.map(mapName), Expr.Call(Expr.Var("_mls_builtin_" + builtin), args.map(toExpr)))) + + def codegen(body: Node, storeInto: Str)(using decls: Ls[Decl], stmts: Ls[Stmt])(using ctx: Ctx): (Ls[Decl], Ls[Stmt]) = body match + case Node.Result(res) => + val expr = wrapMultiValues(res) + val stmts2 = stmts ++ Ls(Stmt.Assign(storeInto, expr)) + (decls, stmts2) + case Node.Jump(defn, args) => + codegenJumpWithCall(defn, args, S(storeInto)) + case Node.LetExpr(name, expr, body) => + val stmts2 = stmts ++ Ls(Stmt.AutoBind(Ls(name |> mapName), codegen(expr))) + codegen(body, storeInto)(using decls, stmts2) + case Node.LetMethodCall(names, cls, method, IExpr.Ref(Name("builtin")) :: args, body) => + val stmts2 = stmts ++ codegenBuiltin(names, args.head.toString.replace("\"", ""), args.tail) + codegen(body, storeInto)(using decls, stmts2) + case Node.LetMethodCall(names, cls, method, args, body) => + val call = mlsMethodCall(cls, method.str |> mapName, args.map(toExpr)) + val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(mapName), call)) + codegen(body, storeInto)(using decls, stmts2) + case Node.LetCall(names, defn, args, _, body) => + val call = Expr.Call(Expr.Var(defn.name |> mapName), args.map(toExpr)) + val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(mapName), call)) + codegen(body, storeInto)(using decls, stmts2) + case Node.Case(scrut, cases, default) => + codegenCaseWithIfs(scrut, cases, default, storeInto) + + private def codegenDefn(using ctx: Ctx)(defn: Defn): (Def, Decl) = defn match + case Defn(id, name, params, resultNum, body, _, _) => + val decls = Ls(mlsRetValueDecl) + val stmts = Ls.empty[Stmt] + val (decls2, stmts2) = codegen(body, mlsRetValue)(using decls, stmts) + val stmtsWithReturn = stmts2 :+ Stmt.Return(Expr.Var(mlsRetValue)) + val theDef = Def.FuncDef(mlsValType, name |> mapName, params.map(x => (x |> mapName, mlsValType)), Stmt.Block(decls2, stmtsWithReturn)) + val decl = Decl.FuncDecl(mlsValType, name |> mapName, params.map(x => mlsValType)) + (theDef, decl) + + def codegenTopNode(node: Node)(using ctx: Ctx): (Def, Decl) = + val decls = Ls(mlsRetValueDecl) + val stmts = Ls.empty[Stmt] + val (decls2, stmts2) = codegen(node, mlsRetValue)(using decls, stmts) + val stmtsWithReturn = stmts2 :+ Stmt.Return(Expr.Var(mlsRetValue)) + val theDef = Def.FuncDef(mlsValType, mlsMainName, Ls(), Stmt.Block(decls2, stmtsWithReturn)) + val decl = Decl.FuncDecl(mlsValType, mlsMainName, Ls()) + (theDef, decl) + + // Topological sort of classes based on inheritance relationships + def sortClasses(prog: Program): Ls[ClassInfo] = + var depgraph = prog.classes.map(x => (x.name, x.parents)).toMap + var degree = depgraph.view.mapValues(_.size).toMap + def removeNode(node: Str) = + degree -= node + depgraph -= node + depgraph = depgraph.view.mapValues(_.filter(_ != node)).toMap + degree = depgraph.view.mapValues(_.size).toMap + val sorted = ListBuffer.empty[ClassInfo] + var work = degree.filter(_._2 == 0).keys.toSet + while work.nonEmpty do + val node = work.head + work -= node + sorted.addOne(prog.classes.find(_.name == node).get) + removeNode(node) + val next = degree.filter(_._2 == 0).keys + work ++= next + if depgraph.nonEmpty then + val cycle = depgraph.keys.mkString(", ") + throw new Exception(s"Cycle detected in class hierarchy: $cycle") + sorted.toList + + def codegen(prog: Program): CompilationUnit = + val sortedClasses = sortClasses(prog) + val defnCtx = prog.defs.map(_.name) + val (defs, decls) = sortedClasses.map(codegenClassInfo(using Ctx(defnCtx))).unzip + val (defs2, decls2) = prog.defs.map(codegenDefn(using Ctx(defnCtx))).unzip + val (defMain, declMain) = codegenTopNode(prog.main)(using Ctx(defnCtx)) + CompilationUnit(Ls(mlsPrelude), decls ++ decls2 :+ declMain, defs.flatten ++ defs2 :+ defMain :+ Def.RawDef(mlsEntryPoint)) diff --git a/compiler/shared/main/scala/mlscript/compiler/codegen/CppCompilerHost.scala b/compiler/shared/main/scala/mlscript/compiler/codegen/CppCompilerHost.scala new file mode 100644 index 0000000000..3897648dbc --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/codegen/CppCompilerHost.scala @@ -0,0 +1,44 @@ +package mlscript.compiler.codegen.cpp + +import mlscript._ +import mlscript.utils.shorthands._ +import scala.collection.mutable.ListBuffer + +final class CppCompilerHost(val auxPath: Str): + import scala.sys.process._ + private def ifAnyCppCompilerExists(): Boolean = + Seq("g++", "--version").! == 0 || Seq("clang++", "--version").! == 0 + + private def isMakeExists(): Boolean = + import scala.sys.process._ + Seq("make", "--version").! == 0 + + val ready = ifAnyCppCompilerExists() && isMakeExists() + + def compileAndRun(src: Str, output: Str => Unit): Unit = + if !ready then + return + val srcPath = os.temp(contents = src, suffix = ".cpp") + val binPath = os.temp(suffix = ".mls.out") + var stdout = ListBuffer[Str]() + var stderr = ListBuffer[Str]() + val buildLogger = ProcessLogger(stdout :+= _, stderr :+= _) + val buildResult = Seq("make", "-B", "-C", auxPath, "auto", s"SRC=$srcPath", s"DST=$binPath") ! buildLogger + if buildResult != 0 then + output("Compilation failed: ") + for line <- stdout do output(line) + for line <- stderr do output(line) + return + + stdout.clear() + stderr.clear() + val runCmd = Seq(binPath.toString) + val runResult = runCmd ! buildLogger + if runResult != 0 then + output("Execution failed: ") + for line <- stdout do output(line) + for line <- stderr do output(line) + return + + output("Execution succeeded: ") + for line <- stdout do output(line) \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/ir/Builder.scala b/compiler/shared/main/scala/mlscript/compiler/ir/Builder.scala index c80a698f6f..86fb4986bc 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ir/Builder.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ir/Builder.scala @@ -4,35 +4,72 @@ import mlscript.compiler.optimizer.FreeVarAnalysis import mlscript.utils.shorthands._ import mlscript.utils._ import mlscript._ -import mlscript.Message._ -import collection.mutable.ListBuffer +import mlscript.Message.MessageContext +import scala.collection.mutable.ListBuffer final val ops = Set("+", "-", "*", "/", ">", "<", ">=", "<=", "!=", "==") +final val builtin = Set("builtin") -final class Builder(fresh: Fresh, fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diagnostic => Unit): +final class Builder(fresh: Fresh, fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diagnostic => Unit, verbose: Boolean = false): import Node._ import Expr._ - private type NameCtx = Map[Str, Name] - private type ClassCtx = Map[Str, ClassInfo] - private type FieldCtx = Map[Str, (Str, ClassInfo)] - private type FnCtx = Set[Str] - private type OpCtx = Set[Str] + private def log(x: Any) = if verbose then println(x) + + private final case class ClassInfoPartial(name: Str, fields: Ls[Str], methods: Set[Str]): + var freeVars = Ls.empty[Str] + var ctx = ctxEmpty + + private final case class DefnInfoPartial(name: Str, params: Ls[Str]): + var freeVars = Ls.empty[Str] + var ctx = ctxEmpty + + private type NameCtx = Map[Str, Name] // name -> new name + private type ClassCtx = Map[Str, ClassInfoPartial] // class name -> partial class info + private type FnCtx = Map[Str, DefnInfoPartial] // fn name -> partial defn info + private type OpCtx = Set[Str] // op names private final case class Ctx( - val nameCtx: NameCtx = Map.empty, - val classCtx: ClassCtx = Map.empty, - val fieldCtx: FieldCtx = Map.empty, - val fnCtx: FnCtx = Set.empty, - val opCtx: OpCtx = Set.empty, - var jpAcc: ListBuffer[Defn], + nameCtx: NameCtx = Map.empty, + tyNameCtx: NameCtx = Map.empty, + classCtx: ClassCtx = Map.empty, + fnCtx: FnCtx = Map.empty, + opCtx: OpCtx = Set.empty, + jpAcc: ListBuffer[Defn], + defAcc: ListBuffer[NuFunDef], + lcAcc: ListBuffer[NuTypeDef], + ): + def hasClassLifted = lcAcc.nonEmpty + def hasLifted = jpAcc.nonEmpty || defAcc.nonEmpty || lcAcc.nonEmpty + + private def ctxEmpty = Ctx( + nameCtx = Map.empty, + tyNameCtx = Map.empty, + classCtx = Map.empty, + fnCtx = Map.empty, + opCtx = ops, + jpAcc = ListBuffer.empty, + defAcc = ListBuffer.empty, + lcAcc = ListBuffer.empty, ) + private def ctxJoin(c1: Ctx, c2: Ctx) = + Ctx( + nameCtx = c1.nameCtx ++ c2.nameCtx, + tyNameCtx = c1.tyNameCtx ++ c2.tyNameCtx, + classCtx = c1.classCtx ++ c2.classCtx, + fnCtx = c1.fnCtx ++ c2.fnCtx, + opCtx = c1.opCtx ++ c2.opCtx, + jpAcc = c1.jpAcc, + defAcc = c1.defAcc, + lcAcc = c1.lcAcc, + ) + private def ref(x: Name) = Ref(x) private def result(x: Ls[TrivialExpr]) = Result(x).attachTag(tag) private def sresult(x: TrivialExpr) = Result(Ls(x)).attachTag(tag) private def unexpectedNode(x: Node) = throw IRError(s"unsupported node $x") - private def unexpectedTerm(x: Term) = throw IRError(s"unsupported term $x") + private def unexpectedTerm(x: Statement) = throw IRError(s"unsupported term $x") private def buildBinding(using ctx: Ctx)(name: Str, e: Term, body: Term)(k: Node => Node): Node = buildResultFromTerm(e) { @@ -60,64 +97,212 @@ final class Builder(fresh: Fresh, fnUid: FreshInt, classUid: FreshInt, tag: Fres } case Tup(Nil) => Nil |> result |> k - private def bindingPatternVariables(scrut: Str, tup: Tup, cls: ClassInfo, rhs: Term): Term = - val params = tup.fields.map { - case N -> Fld(FldFlags.empty, Var(name)) => name - case _ => throw IRError("unsupported field") - } + private def bindingPatternVariables(scrut: Str, tup: Tup, cls: ClassInfoPartial, rhs: Term): Term = + val params = tup |> getTupleFields val fields = cls.fields val tm = params.zip(fields).foldLeft(rhs) { case (tm, (param, field)) => - Let(false, Var(param), Sel(Var(scrut), Var(field)), tm) + Let(false, Var(param), App(Sel(Var(cls.name), Var(field)), Tup(Ls(N -> Fld(FldFlags.empty, Var(scrut))))), tm) } tm - private def buildResultFromTerm(using ctx: Ctx)(tm: Term)(k: Node => Node): Node = - def buildLetCall(f: Term, xs: Tup, ann: Option[Term]) = - buildResultFromTerm(f) { node => node match - case Result(Ref(g) :: Nil) if ctx.fnCtx.contains(g.str) => buildResultFromTerm(xs) { - case Result(args) => - val v = fresh.make - - ann match - case Some(ann @ Var(nme)) => - if nme === "tailcall" then - LetCall(List(v), DefnRef(Right(g.str)), args, true, v |> ref |> sresult |> k)(f.toLoc).attachTag(tag) - else - if nme === "tailrec" then - raise(ErrorReport(List(msg"@tailrec is for annotating functions; try @tailcall instead" -> ann.toLoc), true, Diagnostic.Compilation)) - LetCall(List(v), DefnRef(Right(g.str)), args, false, v |> ref |> sresult |> k)(f.toLoc).attachTag(tag) - case Some(_) => node |> unexpectedNode - case None => LetCall(List(v), DefnRef(Right(g.str)), args, false, v |> ref |> sresult |> k)(f.toLoc).attachTag(tag) - - case node @ _ => node |> unexpectedNode - } - case Result(Ref(f) :: Nil) => buildResultFromTerm(xs) { - case Result(args) => - throw IRError(s"not supported: apply") - case node @ _ => node |> unexpectedNode + private def freeVariablesIf(ucs: If): Set[Str] = + val ifbody: IfBody = ucs.body + val els: Opt[Term] = ucs.els + + def f(ifbody: IfBody): Set[Str] = ifbody match + case IfBlock(lines) => lines.foldLeft(Set.empty[Str]) { + case (acc, Left(ifbody2)) => acc ++ f(ifbody2) + case (acc, Right(rhs)) => acc ++ freeVariables(rhs)._2 + } + case IfElse(expr) => freeVariables(expr) + case IfLet(isRec, name, rhs, body) => + if isRec then + (freeVariables(rhs) -- freeVariables(name)) ++ (f(body) -- freeVariables(name)) + else + freeVariables(rhs) ++ (f(body) -- freeVariables(name)) + case IfOpApp(lhs, op, rhs) => freeVariables(lhs) ++ f(rhs) + case IfOpsApp(lhs, opsRhss) => freeVariables(lhs) ++ opsRhss.foldLeft(Set.empty[Str]) { + case (acc, (op, rhs)) => acc ++ f(rhs) + } + case IfThen(expr, rhs) => freeVariables(rhs) -- freeVariables(expr) + + val fvs1 = f(ifbody) + val fvs2 = els.fold(Set.empty[Str]) { freeVariables } + + fvs1 ++ fvs2 + + private def freeVariables(tu: TypingUnit): Set[Str] = + var all_defined = tu.rawEntities.foldLeft(Set.empty[Str]) { + case (defined, stmt) => defined ++ freeVariables(stmt)._1 + } + tu.rawEntities.foldLeft(Set.empty[Str]) { + case (acc, stmt) => acc ++ (freeVariables(stmt)._2 -- all_defined) + } + + // for this fv analysis, we also need to return the variables that are defined in this statement + private def freeVariables(stmt: Statement): (Set[Str], Set[Str]) = stmt match + case DataDefn(body) => throw IRError("unsupported DataDefn") + case DatatypeDefn(head, body) => throw IRError("unsupported DatatypeDefn") + case LetS(isRec, pat, rhs) => throw IRError("unsupported LetS") + case ntd: NuTypeDef => + val fvs = freeVariables(ntd.body) -- ntd.params.fold(Set.empty)(freeVariables) + (Set(ntd.nme.name), fvs) + case Constructor(params, body) => throw IRError("unsupported Constructor") + case nfd: NuFunDef => + val fvs = nfd.isLetRec match + case None | Some(true) => nfd.rhs.fold(tm => freeVariables(tm) -- freeVariables(nfd.nme), ty => Set.empty) + case Some(false) => nfd.rhs.fold(tm => freeVariables(tm), ty => Set.empty) + (freeVariables(nfd.nme), fvs) + case Def(rec, nme, rhs, isByname) => throw IRError("unsupported Def") + case TypeDef(kind, nme, tparams, body, mthDecls, mthDefs, positionals, adtInfo) => throw IRError("unsupported TypeDef") + case x: Term => + val fvs = freeVariables(x) + (Set.empty, fvs) + + private def freeVariables(tm: Term): Set[Str] = tm match + case AdtMatchWith(cond, arms) => + val inner: Set[Str] = arms.foldLeft(Set.empty){ + case (acc, AdtMatchPat(pat, body)) => acc ++ freeVariables(body) -- freeVariables(pat) + } + freeVariables(cond) ++ inner + case Ann(ann, receiver) => freeVariables(receiver) + case App(lhs, rhs) => freeVariables(lhs) ++ freeVariables(rhs) + case Asc(trm, ty) => freeVariables(trm) + case Assign(lhs, rhs) => freeVariables(lhs) ++ freeVariables(rhs) + case Bind(lhs, rhs) => freeVariables(lhs) + case Blk(stmts) => + var fvs = Set.empty[Str] + var defined = Set.empty[Str] + stmts.foreach { + stmt => { + val stmt_fvs = freeVariables(stmt) + fvs ++= stmt_fvs._2 + fvs --= defined + defined ++= stmt_fvs._1 } + } + fvs + case Bra(rcd, trm) => freeVariables(trm) + case CaseOf(trm, cases) => + import mlscript.{Case => CCase} + def f(pat: CaseBranches): Set[Str] = + pat match + case CCase(pat, body, rest) => freeVariables(body) -- freeVariables(pat) ++ f(rest) + case NoCases => Set.empty + case Wildcard(body) => freeVariables(body) + freeVariables(trm) ++ f(cases) + case Eqn(lhs, rhs) => freeVariables(rhs) + case Forall(params, body) => freeVariables(body) + case x: If => freeVariablesIf(x) + case Inst(body) => freeVariables(body) + case Lam(lhs, rhs) => + freeVariables(rhs) -- freeVariables(lhs) + case Let(isRec, name, rhs, body) => + if isRec then + (freeVariables(rhs) -- freeVariables(name)) ++ (freeVariables(body) -- freeVariables(name)) + else + freeVariables(rhs) ++ (freeVariables(body) -- freeVariables(name)) + case New(head, body) => throw IRError("unsupported New") + case NuNew(cls) => freeVariables(cls) + case Quoted(body) => throw IRError("unsupported Quoted") + case Rcd(fields) => fields.foldLeft(Set.empty[Str]) { + case (acc, (_, Fld(_, trm))) => acc ++ freeVariables(trm) + } + case Rft(base, decls) => throw IRError("unsupported Rft") + case Sel(receiver, fieldName) => freeVariables(receiver) + case Splc(fields) => fields.foldLeft(Set.empty[Str]) { + case (acc, Left(trm)) => acc ++ freeVariables(trm) + case (acc, Right(Fld(_, trm))) => acc ++ freeVariables(trm) + } + case Subs(arr, idx) => freeVariables(arr) ++ freeVariables(idx) + case Super() => Set.empty + case Test(trm, ty) => freeVariables(trm) + case Tup(fields) => fields.foldLeft(Set.empty[Str]) { + case (acc, (_, Fld(_, trm))) => acc ++ freeVariables(trm) + } + case TyApp(lhs, targs) => freeVariables(lhs) + case Unquoted(body) => throw IRError("unsupported Unquoted") + case Where(body, where) => throw IRError("unsupported Where") + case While(cond, body) => freeVariables(cond) ++ freeVariables(body) + case With(trm, fields) => freeVariables(trm) ++ freeVariables(fields: Term) + case Var(name) => Set(name) + case DecLit(value) => Set.empty + case IntLit(value) => Set.empty + case StrLit(value) => Set.empty + case UnitLit(undefinedOrNull) => Set.empty + + private def buildLetCall(using ctx: Ctx)(f: Var, xs: Tup, ann: Option[Term])(k: Node => Node) = + buildResultFromTup(xs) { + case Result(args) => + val v = fresh.make + ctx.nameCtx.get(f.name) match + case None => throw IRError(s"unknown name $f in $ctx") + case Some(f2) => + ctx.fnCtx.get(f2.str) match + case None => throw IRError(s"unknown function $f2 in $ctx") + case Some(dInfo) => + val args2 = + if args.size != dInfo.params.size then + args ++ dInfo.freeVars.map(x => Ref(ctx.nameCtx(x))) // it's possible that the free vars as parameters have been filled when do eta expansion + else + args + ann match + case Some(ann @ Var(nme)) => + if nme === "tailcall" then + LetCall(List(v), DefnRef(Right(f2.str)), args2, true, v |> ref |> sresult |> k)(f.toLoc).attachTag(tag) + else + if nme === "tailrec" then + raise(ErrorReport(List(msg"@tailrec is for annotating functions; try @tailcall instead" -> ann.toLoc), true, Diagnostic.Compilation)) + LetCall(List(v), DefnRef(Right(f2.str)), args2, false, v |> ref |> sresult |> k)(f.toLoc).attachTag(tag) + case Some(_) => throw IRError("unsupported annotation") + case None => LetCall(List(v), DefnRef(Right(f2.str)), args2, false, v |> ref |> sresult |> k)(f.toLoc).attachTag(tag) case node @ _ => node |> unexpectedNode } - + private def buildResultFromTerm(using ctx: Ctx)(tm: Statement)(k: Node => Node): Node = val res = tm match case lit: Lit => Literal(lit) |> sresult |> k case v @ Var(name) => if (name.isCapitalized) - val v = fresh.make - LetExpr(v, - CtorApp(ctx.classCtx(name), Nil), - v |> ref |> sresult |> k).attachTag(tag) + ctx.tyNameCtx.get(name) match + case Some(x) => + val v = fresh.make + ctx.classCtx.get(x.str) match + case Some(clsinfo) => + val args = (if clsinfo.freeVars.isEmpty then Nil else clsinfo.freeVars.map(x => Ref(ctx.nameCtx(x)))) + LetExpr(v, + CtorApp(ClassRef(Right(x.str)), args), + v |> ref |> sresult |> k).attachTag(tag) + case None => throw IRError(s"unknown class $name in $ctx") + case None => throw IRError(s"unknown type name $name in $ctx") else ctx.nameCtx.get(name) match { - case Some(x) => x |> ref |> sresult |> k - case _ => throw IRError(s"unknown name $name in $ctx") + case Some(x) => + if (ctx.fnCtx.contains(x.str)) + val info = ctx.fnCtx(x.str) + val arity = info.params.size - info.freeVars.size + val range = 0 until arity + val xs = range.map(_ => fresh.make.str).toList + val params = Tup(xs.map(x => N -> Fld(FldFlags.empty, Var(x)))) + val args = Tup(params.fields ++ info.freeVars.map(x => N -> Fld(FldFlags.empty, Var(x)))) + val lam = Lam(params, App(Var(x.str), args)) + buildResultFromTerm(lam)(k) + else + x |> ref |> sresult |> k + case None => throw IRError(s"unknown name $name in $ctx") } + case lam @ Lam(Tup(fields), body) => + val tmp = fresh.make + val lambdaName = fresh.make("Lambda") + val result = Var(lambdaName.str) + val localCls = Blk( + NuTypeDef(Cls, TypeName(lambdaName.str), Nil, N, N, N, Ls(Var("Callable")), N, N, TypingUnit( + NuFunDef(N, Var(s"apply${fields.size}"), None, Nil, L(Lam(Tup(fields), body)))(tm.getLoc, N, N, N, N, false, Nil) :: Nil + ))(tm.getLoc, tm.getLoc, Nil) :: result :: Nil) + buildResultFromTerm(localCls)(k) - case Lam(Tup(fields), body) => - throw IRError("not supported: lambda") case App( - App(Var(name), Tup((_ -> Fld(_, e1)) :: Nil)), + App(Var(name), Tup((_ -> Fld(_, e1)) :: Nil)), Tup((_ -> Fld(_, e2)) :: Nil)) if ctx.opCtx.contains(name) => buildResultFromTerm(e1) { case Result(v1 :: Nil) => @@ -131,19 +316,68 @@ final class Builder(fresh: Fresh, fnUid: FreshInt, classUid: FreshInt, tag: Fres } case node @ _ => node |> unexpectedNode } - - case App(Var(name), xs @ Tup(_)) if name.isCapitalized => - buildResultFromTerm(xs) { - case Result(args) => - val v = fresh.make - LetExpr(v, - CtorApp(ctx.classCtx(name), args), - v |> ref |> sresult |> k).attachTag(tag) + case x @ App(Var(name), xs @ Tup(_)) if name.isCapitalized || ctx.opCtx.contains(name) => + if name.isCapitalized then + buildResultFromTerm(xs) { + case Result(args) => + ctx.tyNameCtx.get(name) match + case Some(x) => + val v = fresh.make + ctx.classCtx.get(x.str) match + case Some(clsinfo) => + val args2 = args ++ clsinfo.freeVars.map(x => Ref(ctx.nameCtx(x))) + LetExpr(v, + CtorApp(ClassRef(Right(x.str)), args2), + v |> ref |> sresult |> k).attachTag(tag) + case None => throw IRError(s"unknown class $name in $ctx") + case None => throw IRError(s"unknown type name $name in $ctx") + case node @ _ => node |> unexpectedNode + } + else + buildResultFromTerm(xs) { + case Result(args) => + val v = fresh.make + LetExpr(v, + BasicOp(name, args), + v |> ref |> sresult |> k).attachTag(tag) + case node @ _ => node |> unexpectedNode + } + case App( + member @ Sel(Var(clsName), Var(fld)), + xs @ Tup((_ -> Fld(_, Var(s))) :: _)) if clsName.isCapitalized => + buildResultFromTup(xs) { + case Result(xs @ (Ref(name) :: args)) => + ctx.tyNameCtx.get(clsName) match + case Some(x) => + val v = fresh.make + val cls = ctx.classCtx(x.str) + val isField = cls.fields.contains(fld) + if isField then + LetExpr(v, Select(name, ClassRef(Right(x.str)), fld), + v |> ref |> sresult |> k).attachTag(tag) + else + if cls.methods.contains(fld) then + LetMethodCall(Ls(v), ClassRef(Right(x.str)), Name(fld), xs, v |> ref |> sresult |> k).attachTag(tag) + else + throw IRError(s"unknown field or method $fld in $cls") + case None => throw IRError(s"unknown type name $clsName in $ctx") case node @ _ => node |> unexpectedNode } - - case App(f, xs @ Tup(_)) => buildLetCall(f, xs, None) - case Ann(ann, App(f, xs @ Tup(_))) => buildLetCall(f, xs, Some(ann)) + case App(vf @ Var(f), xs @ Tup(_)) if ctx.fnCtx.contains(f) || ctx.nameCtx.get(f).fold(false)(x => ctx.fnCtx.contains(x.str)) => + buildLetCall(vf, xs, None)(k) + case Ann(ann, App(vf @ Var(f), xs @ Tup(_))) if ctx.fnCtx.contains(f) || ctx.nameCtx.get(f).fold(false)(x => ctx.fnCtx.contains(x.str)) => + buildLetCall(vf, xs, Some(ann))(k) + case App(f, xs @ Tup(_)) => + buildResultFromTerm(f) { + case Result(Ref(f) :: Nil) => buildResultFromTerm(xs) { + case Result(args) => + val v = fresh.make + // LetApply(List(v), f, args, v |> ref |> sresult |> k).attachTag(tag) + LetMethodCall(List(v), ClassRef(R("Callable")), Name("apply" + args.length), (Ref(f): TrivialExpr) :: args, v |> ref |> sresult |> k).attachTag(tag) + case node @ _ => node |> unexpectedNode + } + case node @ _ => node |> unexpectedNode + } case Ann(ann @ Var(name), recv) => if name === "tailcall" then @@ -152,7 +386,6 @@ final class Builder(fresh: Fresh, fnUid: FreshInt, classUid: FreshInt, tag: Fres raise(ErrorReport(List(msg"@tailrec may only be used to annotate functions" -> ann.toLoc), true, Diagnostic.Compilation)) buildResultFromTerm(recv)(k) - case Let(false, Var(name), rhs, body) => buildBinding(name, rhs, body)(k) @@ -183,16 +416,13 @@ final class Builder(fresh: Fresh, fnUid: FreshInt, classUid: FreshInt, tag: Fres case Result(xs) => Jump(DefnRef(Right(jp.str)), xs ++ fvs.map(x => Ref(Name(x)))).attachTag(tag) case node @ _ => node |> unexpectedNode } - Case(cond, Ls((ctx.classCtx("True"), tru2), (ctx.classCtx("False"), fls2))).attachTag(tag) + Case(cond, Ls( + (Pat.Class(ClassRef(Right("True"))), tru2), + (Pat.Class(ClassRef(Right("False"))), fls2)), None).attachTag(tag) case node @ _ => node |> unexpectedNode } case If(IfOpApp(lhs, Var("is"), IfBlock(lines)), N) - if lines forall { - case L(IfThen(App(Var(ctor), Tup((N -> Fld(FldFlags.empty, _: Var)) :: _)), _)) => ctor.isCapitalized - case L(IfThen(Var(ctor), _)) => ctor.isCapitalized || ctor == "_" - case _ => false - } => buildResultFromTerm(lhs) { case Result(Ref(scrut) :: Nil) => val jp = fresh make "j" @@ -206,12 +436,13 @@ final class Builder(fresh: Fresh, fnUid: FreshInt, classUid: FreshInt, tag: Fres resultNum = 1, jpbody, false, - None + None, ) ctx.jpAcc.addOne(jpdef) - val cases: Ls[(ClassInfo, Node)] = lines map { + var defaultCase: Opt[Node] = None + val cases: Ls[(Pat, Node)] = lines flatMap { case L(IfThen(App(Var(ctor), params: Tup), rhs)) => - ctx.classCtx(ctor) -> { + S(Pat.Class(ClassRef(Right(ctor))) -> { // need this because we have built terms (selections in case arms) containing names that are not in the original term given Ctx = ctx.copy(nameCtx = ctx.nameCtx + (scrut.str -> scrut)) buildResultFromTerm( @@ -219,151 +450,303 @@ final class Builder(fresh: Fresh, fnUid: FreshInt, classUid: FreshInt, tag: Fres case Result(xs) => Jump(DefnRef(Right(jp.str)), xs ++ fvs.map(x => Ref(Name(x)))).attachTag(tag) case node @ _ => node |> unexpectedNode } - } + }) + case L(IfThen(lit @ IntLit(_), rhs)) => + S(Pat.Lit(lit) -> buildResultFromTerm(rhs) { + case Result(xs) => Jump(DefnRef(Right(jp.str)), xs ++ fvs.map(x => Ref(Name(x)))).attachTag(tag) + case node @ _ => node |> unexpectedNode + }) + case L(IfThen(Var("_"), rhs)) => + defaultCase = Some(buildResultFromTerm(rhs) { + case Result(xs) => Jump(DefnRef(Right(jp.str)), xs ++ fvs.map(x => Ref(Name(x)))).attachTag(tag) + case node @ _ => node |> unexpectedNode + }) + N case L(IfThen(Var(ctor), rhs)) => - ctx.classCtx(ctor) -> buildResultFromTerm(rhs) { + S(Pat.Class(ClassRef(Right(ctor))) -> buildResultFromTerm(rhs) { case Result(xs) => Jump(DefnRef(Right(jp.str)), xs ++ fvs.map(x => Ref(Name(x)))).attachTag(tag) case node @ _ => node |> unexpectedNode - } + }) case _ => throw IRError(s"not supported UCS") } - Case(scrut, cases).attachTag(tag) + Case(scrut, cases, defaultCase).attachTag(tag) case node @ _ => node |> unexpectedNode } case Bra(false, tm) => buildResultFromTerm(tm)(k) - case Blk((tm: Term) :: Nil) => buildResultFromTerm(tm)(k) - - case Blk((tm: Term) :: xs) => buildBinding("_", tm, Blk(xs))(k) - - case Blk(NuFunDef(S(false), Var(name), None, _, L(tm)) :: Nil) => - buildBinding(name, tm, Var(name))(k) - - case Blk(NuFunDef(S(false), Var(name), None, _, L(tm)) :: xs) => - buildBinding(name, tm, Blk(xs))(k) - - case Sel(tm @ Var(name), Var(fld)) => - buildResultFromTerm(tm) { - case Result(Ref(res) :: Nil) => - val v = fresh.make - val cls = ctx.fieldCtx(fld)._2 - LetExpr(v, - Select(res, cls, fld), - v |> ref |> sresult |> k).attachTag(tag) - case node @ _ => node |> unexpectedNode - } + case Blk(stmts) => + val (nfds, ntds, terms) = collectInfo(stmts) + val (ctx2, nfds2, ntds2) = renameToBeLifted(nfds, ntds) + val ctx3 = initContextForStatementsFrom( + nfds2, ntds2, terms, scanNamesInThisScope(stmts) + )(using ctx2) + + ctx.lcAcc.addAll(ntds2) + ctx.defAcc.addAll(nfds2) + + buildResultFromTerms(using ctx3)(terms)(k) case tup: Tup => buildResultFromTup(tup)(k) case term => term |> unexpectedTerm res - - private def buildDefFromNuFunDef(using ctx: Ctx)(nfd: Statement): Defn = nfd match - case nfd: NuFunDef => nfd match - case NuFunDef(_, Var(name), None, Nil, L(Lam(Tup(fields), body))) => - val strs = fields map { - case N -> Fld(FldFlags.empty, Var(x)) => x - case _ => throw IRError("unsupported field") + + private def buildResultFromTerms(using ctx: Ctx)(tms: Ls[Statement])(k: Node => Node): Node = + tms match + case Nil => throw IRError("empty term list") + case NuFunDef(S(false), Var(name), _, _, Left(tm)) :: xs => + xs match + case Nil => throw IRError("unsupported NuFunDef at tail position") + case _ => buildResultFromTerm(tm) { + case Result((r: Ref) :: Nil) => + given Ctx = ctx.copy(nameCtx = ctx.nameCtx + (name -> r.name)) + buildResultFromTerms(xs)(k) + case Result((lit: Literal) :: Nil) => + val v = fresh.make + given Ctx = ctx.copy(nameCtx = ctx.nameCtx + (name -> v)) + LetExpr(v, + lit, + buildResultFromTerms(xs)(k)).attachTag(tag) + case node @ _ => node |> unexpectedNode } - val names = strs map (fresh.make(_)) - given Ctx = ctx.copy(nameCtx = ctx.nameCtx ++ (strs zip names)) - val trAnn = nfd.annotations.find { - case Var("tailrec") => true - case ann @ Var("tailcall") => - raise(ErrorReport(List(msg"@tailcall is for annotating function calls; try @tailrec instead" -> ann.toLoc), true, Diagnostic.Compilation)) - false - case _ => false } - - Defn( - fnUid.make, - name, - params = names, - resultNum = 1, - buildResultFromTerm(body) { x => x }, - trAnn.isDefined, - trAnn.flatMap(_.toLoc) - ) - case _ => throw IRError("unsupported NuFunDef") - case _ => throw IRError("unsupported NuFunDef") - - private def buildClassInfo(ntd: Statement): ClassInfo = ntd match - case NuTypeDef(Cls, TypeName(name), Nil, S(Tup(args)), N, N, Nil, N, N, TypingUnit(Nil)) => - ClassInfo( - classUid.make, - name, - args map { - case N -> Fld(FldFlags.empty, Var(name)) => name - case _ => throw IRError("unsupported field") - } - ) - case NuTypeDef(Cls, TypeName(name), Nil, N, N, N, Nil, N, N, TypingUnit(Nil)) => - ClassInfo( - classUid.make, + case x :: Nil => buildResultFromTerm(x)(k) + case x :: xs => buildResultFromTerm(x) { + case _ => buildResultFromTerms(xs)(k) + } + + private def getTupleFields(tup: Tup) = tup.fields.map { + case N -> Fld(FldFlags.empty, Var(name)) => name + case S(Var(name)) -> Fld(_, ty) => name + case _ => throw IRError("unsupported field") + } + + private def buildDefFromMethod(using ctx: Ctx)(fields: List[Str], nfd: Statement): Defn = nfd match + case nfd @ NuFunDef(_, Var(name), None, Nil, L(Lam(xs @ Tup(_), body))) => + val defnInfoPartial = getDefnInfoPartial(ctx.fnCtx.keySet ++ ctx.classCtx.keySet ++ fields, ctx)(nfd).get + val params = defnInfoPartial.params + val names = params map (fresh.make(_)) + val ctx2 = ctxJoin(ctx, defnInfoPartial.ctx) + given Ctx = ctx2.copy(nameCtx = ctx2.nameCtx ++ (params zip names)) + Defn( + fnUid.make, name, - Ls(), + params = names, + resultNum = 1, + body = buildResultFromTerm(body) { x => x }, + isTailRec = false, + loc = nfd.getLoc, ) - case x @ _ => throw IRError(f"unsupported NuTypeDef $x") + case fd @ _ => throw IRError("unsupported NuFunDef " + fd.toString) - private def checkDuplicateField(ctx: Set[Str], cls: ClassInfo): Set[Str] = - val u = cls.fields.toSet intersect ctx - if (u.nonEmpty) throw IRError(f"duplicate class field $u") - cls.fields.toSet union ctx - - private def getDefinitionName(nfd: Statement): Str = nfd match - case NuFunDef(_, Var(name), _, _, _) => name - case _ => throw IRError("unsupported NuFunDef") - - def buildGraph(unit: TypingUnit): Program = unit match - case TypingUnit(entities) => - val grouped = entities groupBy { - case ntd: NuTypeDef => 0 - case nfd: NuFunDef => 1 - case tm: Term => 2 - case _ => throw IRError("unsupported entity") + private def buildDefFromNuFunDef(using ctx: Ctx)(nfd: Statement): Defn = nfd match + case nfd @ NuFunDef(_, Var(name), None, Nil, L(Lam(xs @ Tup(_), body))) => + val defnInfoPartial = getDefnInfoPartial(ctx.fnCtx.keySet ++ ctx.classCtx.keySet, ctx)(nfd).get + val params = defnInfoPartial.params + val names = params map (fresh.make(_)) + val ctx2 = ctxJoin(ctx, defnInfoPartial.ctx) + given Ctx = ctx2.copy(nameCtx = ctx2.nameCtx ++ (params zip names)) + val trAnn = nfd.annotations.find { + case Var("tailrec") => true + case ann @ Var("tailcall") => + raise(ErrorReport(List(msg"@tailcall is for annotating function calls; try @tailrec instead" -> ann.toLoc), true, Diagnostic.Compilation)) + false + case _ => false } + Defn( + fnUid.make, + name, + params = names, + resultNum = 1, + buildResultFromTerm(body) { x => x }, + trAnn.isDefined, + trAnn.flatMap(_.toLoc) + ) + case fd @ _ => throw IRError("unsupported NuFunDef " + fd.toString) + + private def buildClassInfo(using ctx: Ctx)(ntd: Statement): ClassInfo = ntd match + case ntd @ NuTypeDef(Cls | Mod, TypeName(name), _, params, N, _, parents, N, N, TypingUnit(methods)) => + val clsInfoPartial = getClassInfoPartial(ctx.classCtx.keySet ++ ctx.fnCtx.keySet, ctx)(ntd) + val cls = ClassInfo(classUid.make, name, clsInfoPartial.fields) + val ctx2 = ctxJoin(ctx, clsInfoPartial.ctx) + given Ctx = ctx2.copy( + nameCtx = ctx2.nameCtx ++ clsInfoPartial.fields.map(x => x -> Name(x)), + classCtx = ctx2.classCtx + (name -> clsInfoPartial) + ) + def resolveParentName(parent: Term): String = parent match { + case Var(name) if name.isCapitalized => name + case TyApp(lhs, _) => resolveParentName(lhs) + case App(lhs, _) => resolveParentName(lhs) + case _ => throw IRError("unsupported parent") } + cls.parents = parents.map(resolveParentName).toSet + cls.methods = methods.map { + case x: NuFunDef => x.name -> buildDefFromMethod(clsInfoPartial.fields, x) + case x @ _ => throw IRError(f"unsupported method $x") + }.toMap + cls + case x @ _ => throw IRError(f"unsupported NuTypeDef $x") - import scala.collection.mutable.{ HashSet => MutHSet } - - // TODO: properly add prelude classes such as "True" and "False" rather than this hacky method - val cls = ClassInfo(classUid.make, "True", List()) - :: ClassInfo(classUid.make, "False", List()) - :: grouped.getOrElse(0, Nil).map(buildClassInfo) - - cls.foldLeft(Set.empty)(checkDuplicateField(_, _)) - - val clsinfo = cls.toSet - val defn_names = grouped.getOrElse(1, Nil).map(getDefinitionName) - val class_ctx: ClassCtx = cls.map { case ClassInfo(_, name, _) => name }.zip(cls).toMap - val field_ctx: FieldCtx = cls.flatMap { case ClassInfo(_, name, fields) => fields.map((_, (name, class_ctx(name)))) }.toMap - val fn_ctx: FnCtx = defn_names.toSet - var name_ctx: NameCtx = defn_names.zip(defn_names.map(Name(_))).toMap ++ ops.map { op => (op, Name(op)) }.toList - - val jp_acc = ListBuffer.empty[Defn] - given Ctx = Ctx( - nameCtx = name_ctx, - classCtx = class_ctx, - fieldCtx = field_ctx, - fnCtx = fn_ctx, - opCtx = ops, - jpAcc = jp_acc, - ) - var defs: Set[Defn] = grouped.getOrElse(1, Nil).map(buildDefFromNuFunDef).toSet - val terms: Ls[Term] = grouped.getOrElse(2, Nil).map { - case tm: Term => tm - case _ => ??? /* unreachable */ + private def getDefnInfoPartial(names: Set[Str], ctx: Ctx)(nfd: NuFunDef): Opt[DefnInfoPartial] = nfd match + case NuFunDef(_, Var(name), _, _, Left(Lam(Var(x), _))) => + val originalFvs = freeVariables(nfd)._2 + val fvs = (originalFvs -- builtin -- ops -- names).toList + val params = x :: fvs + val dip = DefnInfoPartial(name, params) + dip.freeVars = fvs + dip.ctx = ctx + S(dip) + case NuFunDef(_, Var(name), _, _, Left(Lam(tp @ Tup(fields), _))) => + val originalFvs = freeVariables(nfd)._2 + val fvs = (originalFvs -- builtin -- ops -- names).toList + val params = getTupleFields(tp) ++ fvs + val dip = DefnInfoPartial(name, params) + dip.freeVars = fvs + dip.ctx = ctx + S(dip) + case NuFunDef(_, Var(name), _, _, _) => N + + + private def getClassInfoPartial(names: Set[Str], ctx: Ctx)(ntd: NuTypeDef): ClassInfoPartial = ntd match + case ntd @ NuTypeDef(Cls | Mod, TypeName(name), _, params, N, _, parents, N, N, TypingUnit(other)) => + val originalFvs = freeVariables(ntd)._2 + log(s"getClassInfoPartial $name") + log(originalFvs) + log(names) + val fvs = (originalFvs -- builtin -- ops -- names).toList + val fields = params.fold(fvs)(xs => getTupleFields(xs) ++ fvs) + val methods = other.map { + case x: NuFunDef => x.name + case x @ _ => throw IRError(f"unsupported method $x") } + val cls = ClassInfoPartial(name, fields, methods.toSet) + cls.freeVars = fvs + cls.ctx = ctx + cls + case x @ _ => throw IRError(f"unsupported NuTypeDef $x") + + private def collectInfo(stmts: Ls[Statement]): (Ls[NuFunDef], Ls[NuTypeDef], Ls[Statement]) = + var nfds = ListBuffer.empty[NuFunDef] + var ntds = ListBuffer.empty[NuTypeDef] + var terms = ListBuffer.empty[Statement] + stmts.foreach { + case tm @ NuFunDef(S(false), Var(_), _, _, Left(_)) => + terms.addOne(tm) + case nfd: NuFunDef => nfds.addOne(nfd) + case ntd: NuTypeDef => ntds.addOne(ntd) + case tm: Term => terms.addOne(tm) + case _ => throw IRError("unsupported statement") + } + (nfds.toList, ntds.toList, terms.toList) - val main = buildResultFromTerm (terms match { - case x :: Nil => x - case _ => throw IRError("only one term is allowed in the top level scope") - }) { k => k } - - defs ++= jp_acc.toList + private def makeNameMap(str: IterableOnce[Str]) = str.iterator.map(x => (x, Name(x))).toMap - resolveDefnRef(main, defs, true) - validate(main, defs) - - Program(clsinfo, defs, main) + private def scanNamesInThisScope(stmt: Ls[Statement]): Set[Str] = + val names = stmt flatMap { + case NuTypeDef(_, TypeName(name), _, _, _, _, _, _, _, _) => S(name) + case NuFunDef(_, Var(name), _, _, _) => S(name) + case _ => Nil + } + names.toSet + + private def renameToBeLifted(nfds: Ls[NuFunDef], ntds: Ls[NuTypeDef])(using ctx: Ctx): (Ctx, Ls[NuFunDef], Ls[NuTypeDef]) = + val oldFnNames = scanNamesInThisScope(nfds).toList + val oldTyNames = scanNamesInThisScope(ntds).toList + // TODO: currently, rename cause bugs + //val newFnNames = oldFnNames.map(x => fresh.make(x)) + //val newTyNames = oldTyNames.map(x => if x.startsWith("Lambda$") then Name(x) else fresh.make(x)) + val newFnNames = oldFnNames.map(Name(_)) + val newTyNames = oldTyNames.map(Name(_)) + val nameCtx = oldFnNames.zip(newFnNames).toMap + val tyNameCtx = oldTyNames.zip(newTyNames).toMap + val nfds2 = nfds.map(x => x.copy(nme = Var(nameCtx(x.name).str))(x.declareLoc, x.virtualLoc, x.mutLoc, x.signature, x.outer, x.genField, x.annotations)) + val ntds2 = ntds.map(x => x.copy(nme = TypeName(tyNameCtx(x.name).str))(x.declareLoc, x.abstractLoc, x.annotations)) + + (ctx.copy(nameCtx = ctx.nameCtx ++ nameCtx, tyNameCtx = ctx.tyNameCtx ++ tyNameCtx), nfds2, ntds2) + + private def initContextForStatementsFrom(nfds: Ls[NuFunDef], ntds: Ls[NuTypeDef], terms: Ls[Statement], excluded: Set[Str])(using ctx: Ctx): Ctx = + // they are in the same mutual group or higher group, mustn't capture them + val excludedNames = excluded ++ scanNamesInThisScope(nfds) ++ scanNamesInThisScope(ntds) ++ ctx.fnCtx.keySet ++ ctx.classCtx.keySet + val partialDefnInfo = nfds flatMap getDefnInfoPartial(excludedNames, ctx) + val partialClassInfo = ntds map getClassInfoPartial(excludedNames, ctx) + val fnNames = partialDefnInfo.map(_.name) + val fnCtx = fnNames.zip(partialDefnInfo).toMap + val nameCtx = makeNameMap(builtin) ++ makeNameMap(fnNames) ++ makeNameMap(ops) + val tyNames = partialClassInfo.map(_.name) + val tyNameCtx = makeNameMap(tyNames) + val classCtx = tyNames.zip(partialClassInfo).toMap + + ctx.copy( + tyNameCtx = ctx.tyNameCtx ++ tyNameCtx, + nameCtx = ctx.nameCtx ++ nameCtx, + classCtx = ctx.classCtx ++ classCtx, + fnCtx = ctx.fnCtx ++ fnCtx, + ) + + private def initContextForStatements(nfds: Ls[NuFunDef], ntds: Ls[NuTypeDef], terms: Ls[Statement]): Ctx = + val ctx = Ctx( + nameCtx = Map.empty, + tyNameCtx = Map.empty, + classCtx = Map.empty, + fnCtx = Map.empty, + opCtx = ops, + jpAcc = ListBuffer.empty, + defAcc = ListBuffer.empty, + lcAcc = ListBuffer.empty, + ) + initContextForStatementsFrom(nfds, ntds, terms, Set.empty)(using ctx) + + def getHiddenNames(prelude: TypingUnit): Set[Str] = + def resolveTypeName(x: Term): Str = x match + case Var(name) => name + case TyApp(lhs, _) => resolveTypeName(lhs) + case App(lhs, _) => resolveTypeName(lhs) + case _ => throw IRError("unsupported type name") + val hidden = prelude.rawEntities.flatMap { + case NuFunDef(_, Var(name), _, _, _) => Nil + case NuTypeDef(_, TypeName(name), _, params, _, _, _, _, _, _) if name == "HiddenTheseEntities" => + params.fold{Nil}{ + x => x.fields.flatMap { + case S(Var(name)) -> Fld(FldFlags.empty, ty) => resolveTypeName(ty) :: Nil + case _ => Nil + } + } + case NuTypeDef(_, TypeName(name), _, _, _, _, _, _, _, _) => Nil + case _ => Nil + } + hidden.toSet + + def buildGraph(unit: TypingUnit, prelude: TypingUnit, addPrelude: Boolean = true): Program = + val unit2 = if addPrelude then TypingUnit(prelude.rawEntities ++ unit.rawEntities) else unit + val hiddenNames = getHiddenNames(unit2) + val (nfds, ntds, terms) = collectInfo(unit2.rawEntities) + var ctx = initContextForStatements(nfds, ntds, terms) + + val definitions = ListBuffer.empty[Defn] + val classes = ListBuffer.empty[ClassInfo] + + var first = true + + var curNfds = nfds + var curNtds = ntds + val main = buildResultFromTerm(using ctx)(Blk(terms)){ k => k } + while first || ctx.hasLifted do + first = false + ctx.jpAcc.clear() + ctx.defAcc.clear() + ctx.lcAcc.clear() + definitions.addAll(curNfds.map(buildDefFromNuFunDef(using ctx))) + definitions.addAll(ctx.jpAcc) + classes.addAll(curNtds.map(buildClassInfo(using ctx))) + curNfds = ctx.defAcc.toList + curNtds = ctx.lcAcc.toList + ctx = initContextForStatementsFrom(curNfds, curNtds, Nil, Set.empty)(using ctx) + + val clsInfo = classes.toSet + val defs = definitions.toSet + + resolveRef(main, defs, clsInfo, true) + validate(main, defs, clsInfo) + + Program(clsInfo, defs, main) diff --git a/compiler/shared/main/scala/mlscript/compiler/ir/DefnRefResolver.scala b/compiler/shared/main/scala/mlscript/compiler/ir/DefnRefResolver.scala deleted file mode 100644 index 96ee1d635d..0000000000 --- a/compiler/shared/main/scala/mlscript/compiler/ir/DefnRefResolver.scala +++ /dev/null @@ -1,33 +0,0 @@ -package mlscript.compiler.ir - -import mlscript.utils.shorthands._ -import mlscript.compiler.ir._ - -import Node._ - -// Resolves the definition references by turning them from Right(name) to Left(Defn). -private final class DefnRefResolver(defs: Set[Defn], allowInlineJp: Bool): - private def f(x: Node): Unit = x match - case Result(res) => - case Case(scrut, cases) => cases map { (_, body) => f(body) } - case LetExpr(name, expr, body) => f(body) - case LetCall(resultNames, defnref, args, _, body) => - defs.find{_.getName == defnref.getName} match - case Some(defn) => defnref.defn = Left(defn) - case None => throw IRError(f"unknown function ${defnref.getName} in ${defs.map{_.getName}.mkString(",")}") - f(body) - case Jump(defnref, _) => - // maybe not promoted yet - defs.find{_.getName == defnref.getName} match - case Some(defn) => defnref.defn = Left(defn) - case None => - if (!allowInlineJp) - throw IRError(f"unknown function ${defnref.getName} in ${defs.map{_.getName}.mkString(",")}") - def run(node: Node) = f(node) - def run(node: Defn) = f(node.body) - - -def resolveDefnRef(entry: Node, defs: Set[Defn], allowInlineJp: Bool = false): Unit = - val rl = DefnRefResolver(defs, allowInlineJp) - rl.run(entry) - defs.foreach(rl.run(_)) diff --git a/compiler/shared/main/scala/mlscript/compiler/ir/Fresh.scala b/compiler/shared/main/scala/mlscript/compiler/ir/Fresh.scala index de2ed437db..2ea438dc12 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ir/Fresh.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ir/Fresh.scala @@ -3,13 +3,12 @@ package mlscript.compiler.ir import collection.mutable.{HashMap => MutHMap} import mlscript.utils.shorthands._ -final class Fresh: +final class Fresh(div : Char = '$'): private val counter = MutHMap[Str, Int]() - private val div = '$' private def gensym(s: Str) = { val n = s.lastIndexOf(div) val (ts, suffix) = s.splitAt(if n == -1 then s.length() else n) - var x = if suffix.stripPrefix(div.toString()).forall(_.isDigit) then ts else s + var x = if suffix.stripPrefix(div.toString).forall(_.isDigit) then ts else s val count = counter.getOrElse(x, 0) val tmp = s"$x$div$count" counter.update(x, count + 1) diff --git a/compiler/shared/main/scala/mlscript/compiler/ir/IR.scala b/compiler/shared/main/scala/mlscript/compiler/ir/IR.scala index a84f48fd36..5bc51bc59f 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ir/IR.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ir/IR.scala @@ -3,8 +3,9 @@ package mlscript.compiler.ir import mlscript._ import mlscript.utils._ import mlscript.utils.shorthands._ -import mlscript.compiler.ir._ +import mlscript.compiler.utils._ import mlscript.compiler.optimizer._ +import mlscript.compiler.ir._ import mlscript.Loc @@ -12,6 +13,7 @@ import collection.mutable.{Map as MutMap, Set as MutSet, HashMap, ListBuffer} import annotation.unused import util.Sorting import scala.collection.immutable.SortedSet +import scala.language.implicitConversions final case class IRError(message: String) extends Exception(message) @@ -25,7 +27,22 @@ case class Program( val t2 = defs.toArray Sorting.quickSort(t1) Sorting.quickSort(t2) - s"Program({${t1.mkString(",")}}, {\n${t2.mkString("\n")}\n},\n$main)" + s"Program({${t1.mkString(",\n")}}, {\n${t2.mkString("\n")}\n},\n$main)" + + def show(hiddenNames: Set[Str] = Set.empty) = toDocument(hiddenNames).print + + def toDocument(hiddenNames: Set[Str] = Set.empty) : Document = + val t1 = classes.toArray + val t2 = defs.toArray + Sorting.quickSort(t1) + Sorting.quickSort(t2) + given Conversion[String, Document] = raw + stack( + "Program:", + stack_list(t1.filter(x => !hiddenNames.contains(x.name)).map(_.toDocument).toList) |> indent, + stack_list(t2.map(_.toDocument).toList) |> indent, + main.toDocument |> indent + ) implicit object ClassInfoOrdering extends Ordering[ClassInfo] { def compare(a: ClassInfo, b: ClassInfo) = a.id.compare(b.id) @@ -33,99 +50,132 @@ implicit object ClassInfoOrdering extends Ordering[ClassInfo] { case class ClassInfo( id: Int, - ident: Str, + name: Str, fields: Ls[Str], ): + var parents: Set[Str] = Set.empty + var methods: Map[Str, Defn] = Map.empty override def hashCode: Int = id override def toString: String = - s"ClassInfo($id, $ident, [${fields mkString ","}])" + s"ClassInfo($id, $name, [${fields mkString ","}], parents: ${parents mkString ","}, methods:\n${methods mkString ",\n"})" + + def show = toDocument.print + def toDocument: Document = + given Conversion[String, Document] = raw + val extension = if parents.isEmpty then "" else " extends " + parents.mkString(", ") + if methods.isEmpty then + "class" <:> name <#> "(" <#> fields.mkString(",") <#> ")" <#> extension + else + stack( + "class" <:> name <#> "(" <#> fields.mkString(",") <#> ")" <#> extension <:> "{", + stack_list( methods.map { (_, defn) => defn.toDocument |> indent }.toList), + "}" + ) -case class Name(str: Str): +case class Name(val str: Str): def copy: Name = Name(str) def trySubst(map: Map[Str, Name]) = map.getOrElse(str, this) - override def toString: String = str class DefnRef(var defn: Either[Defn, Str]): - def getName: String = defn.fold(_.getName, x => x) + def name: String = defn.fold(_.name, x => x) def expectDefn: Defn = defn match { - case Left(godef) => godef + case Left(defn) => defn case Right(name) => throw Exception(s"Expected a def, but got $name") } def getDefn: Opt[Defn] = defn.left.toOption override def equals(o: Any): Bool = o match { - case o: DefnRef => o.getName == this.getName + case o: DefnRef => o.name == this.name case _ => false } +class ClassRef(var cls: Either[ClassInfo, Str]): + def name: String = cls.fold(_.name, x => x) + def expectClass: ClassInfo = cls match { + case Left(cls) => cls + case Right(name) => throw Exception(s"Expected a class, but got $name") + } + def getClass: Opt[ClassInfo] = cls.left.toOption + override def equals(o: Any): Bool = o match { + case o: ClassRef => o.name == this.name + case _ => false + } implicit object DefOrdering extends Ordering[Defn] { def compare(a: Defn, b: Defn) = a.id.compare(b.id) } case class Defn( - val id: Int, - val name: Str, - val params: Ls[Name], - val resultNum: Int, - val body: Node, - val isTailRec: Bool, - val loc: Opt[Loc] = None + id: Int, + name: Str, + params: Ls[Name], + resultNum: Int, + body: Node, + isTailRec: Bool, + loc: Opt[Loc] = None ): override def hashCode: Int = id - def getName: String = name override def toString: String = val ps = params.map(_.toString).mkString("[", ",", "]") s"Def($id, $name, $ps,\n$resultNum, \n$body\n)" + def show = toDocument.print + + def toDocument: Document = + given Conversion[String, Document] = raw + stack( + "def" <:> name <#> "(" <#> params.map(_.toString).mkString(",") <#> ")" <:> "=", + body.toDocument |> indent + ) + sealed trait TrivialExpr: import Expr._ override def toString: String def show: String def toDocument: Document - def mapNameOfTrivialExpr(f: Name => Name): TrivialExpr = this match case x: Ref => Ref(f(x.name)) case x: Literal => x - def toExpr: Expr = this match { case x: Expr => x } -private def show_args(args: Ls[TrivialExpr]) = args map (_.show) mkString "," +private def showArguments(args: Ls[TrivialExpr]) = args map (_.show) mkString "," enum Expr: case Ref(name: Name) extends Expr, TrivialExpr case Literal(lit: Lit) extends Expr, TrivialExpr - case CtorApp(name: ClassInfo, args: Ls[TrivialExpr]) - case Select(name: Name, cls: ClassInfo, field: Str) + case CtorApp(cls: ClassRef, args: Ls[TrivialExpr]) + case Select(name: Name, cls: ClassRef, field: Str) case BasicOp(name: Str, args: Ls[TrivialExpr]) - case AssignField(assignee: Name, clsInfo: ClassInfo, fieldName: Str, value: TrivialExpr) + case AssignField(assignee: Name, cls: ClassRef, field: Str, value: TrivialExpr) override def toString: String = show def show: String = toDocument.print - def toDocument: Document = this match - case Ref(s) => s.toString |> raw - case Literal(IntLit(lit)) => s"$lit" |> raw - case Literal(DecLit(lit)) => s"$lit" |> raw - case Literal(StrLit(lit)) => s"$lit" |> raw - case Literal(UnitLit(lit)) => (if lit then "undefined" else "null") |> raw - case CtorApp(ClassInfo(_, name, _), args) => - raw(name) <#> raw("(") <#> raw(args |> show_args) <#> raw(")") - case Select(s, _, fld) => - raw(s.toString) <#> raw(".") <#> raw(fld) + def toDocument: Document = + given Conversion[String, Document] = raw + this match + case Ref(s) => s.toString + case Literal(IntLit(lit)) => s"$lit" + case Literal(DecLit(lit)) => s"$lit" + case Literal(StrLit(lit)) => s"$lit" + case Literal(UnitLit(lit)) => s"$lit" + case CtorApp(cls, args) => + cls.name <#> "(" <#> (args |> showArguments) <#> ")" + case Select(s, cls, fld) => + cls.name <#> "." <#> fld <#> "(" <#> s.toString <#> ")" case BasicOp(name: Str, args) => - raw(name) <#> raw("(") <#> raw(args |> show_args) <#> raw(")") + name <#> "(" <#> (args |> showArguments) <#> ")" case AssignField(assignee, clsInfo, fieldName, value) => stack( - raw("assign") - <:> raw(assignee.toString + "." + fieldName) - <:> raw(":=") - <:> value.toDocument - ) + "assign" + <:> (assignee.toString + "." + fieldName) + <:> ":=" + <:> value.toDocument + ) def mapName(f: Name => Name): Expr = this match case Ref(name) => Ref(f(name)) @@ -138,18 +188,38 @@ enum Expr: def locMarker: LocMarker = this match case Ref(name) => LocMarker.MRef(name.str) case Literal(lit) => LocMarker.MLit(lit) - case CtorApp(name, args) => LocMarker.MCtorApp(name, args.map(_.toExpr.locMarker)) + case CtorApp(cls, args) => LocMarker.MCtorApp(cls, args.map(_.toExpr.locMarker)) case Select(name, cls, field) => LocMarker.MSelect(name.str, cls, field) case BasicOp(name, args) => LocMarker.MBasicOp(name, args.map(_.toExpr.locMarker)) case AssignField(assignee, clsInfo, fieldName, value) => LocMarker.MAssignField(assignee.str, fieldName, value.toExpr.locMarker) +enum Pat: + case Lit(lit: mlscript.Lit) + case Class(cls: ClassRef) + + def isTrue = this match + case Class(cls) => cls.name == "True" + case _ => false + + def isFalse = this match + case Class(cls) => cls.name == "False" + case _ => false + + override def toString: String = this match + case Lit(lit) => s"$lit" + case Class(cls) => s"${cls.name}" + enum Node: // Terminal forms: case Result(res: Ls[TrivialExpr]) case Jump(defn: DefnRef, args: Ls[TrivialExpr]) - case Case(scrut: Name, cases: Ls[(ClassInfo, Node)]) + case Case(scrut: Name, cases: Ls[(Pat, Node)], default: Opt[Node]) // Intermediate forms: case LetExpr(name: Name, expr: Expr, body: Node) + case LetMethodCall(names: Ls[Name], cls: ClassRef, method: Name, args: Ls[TrivialExpr], body: Node) + // Deprecated: + // LetApply(names, fn, args, body) => LetMethodCall(names, ClassRef(R("Callable")), Name("apply" + args.length), (Ref(fn): TrivialExpr) :: args, body) + // case LetApply(names: Ls[Name], fn: Name, args: Ls[TrivialExpr], body: Node) case LetCall(names: Ls[Name], defn: DefnRef, args: Ls[TrivialExpr], isTailRec: Bool, body: Node)(val loc: Opt[Loc] = None) var tag = DefnTag(-1) @@ -171,78 +241,197 @@ enum Node: def mapName(f: Name => Name): Node = this match case Result(res) => Result(res.map(_.mapNameOfTrivialExpr(f))) case Jump(defn, args) => Jump(defn, args.map(_.mapNameOfTrivialExpr(f))) - case Case(scrut, cases) => Case(f(scrut), cases.map { (cls, arm) => (cls, arm.mapName(f)) }) + case Case(scrut, cases, default) => Case(f(scrut), cases.map { (cls, arm) => (cls, arm.mapName(f)) }, default.map(_.mapName(f))) case LetExpr(name, expr, body) => LetExpr(f(name), expr.mapName(f), body.mapName(f)) - case x: LetCall => - val LetCall(names, defn, args, isTailRec, body) = x - LetCall(names.map(f), defn, args.map(_.mapNameOfTrivialExpr(f)), isTailRec, body.mapName(f))(x.loc) + case LetMethodCall(names, cls, method, args, body) => LetMethodCall(names.map(f), cls, f(method), args.map(_.mapNameOfTrivialExpr(f)), body.mapName(f)) + case lc @ LetCall(names, defn, args, itr, body) => LetCall(names.map(f), defn, args.map(_.mapNameOfTrivialExpr(f)), itr, body.mapName(f))(lc.loc) def copy(ctx: Map[Str, Name]): Node = this match case Result(res) => Result(res.map(_.mapNameOfTrivialExpr(_.trySubst(ctx)))) case Jump(defn, args) => Jump(defn, args.map(_.mapNameOfTrivialExpr(_.trySubst(ctx)))) - case Case(scrut, cases) => Case(ctx(scrut.str), cases.map { (cls, arm) => (cls, arm.copy(ctx)) }) + case Case(scrut, cases, default) => Case(ctx(scrut.str), cases.map { (cls, arm) => (cls, arm.copy(ctx)) }, default.map(_.copy(ctx))) case LetExpr(name, expr, body) => val name_copy = name.copy LetExpr(name_copy, expr.mapName(_.trySubst(ctx)), body.copy(ctx + (name_copy.str -> name_copy))) - case x: LetCall => - val LetCall(names, defn, args, isTailRec, body) = x + case LetMethodCall(names, cls, method, args, body) => val names_copy = names.map(_.copy) - LetCall(names_copy, defn, args.map(_.mapNameOfTrivialExpr(_.trySubst(ctx))), isTailRec, body.copy(ctx ++ names_copy.map(x => x.str -> x)))(x.loc) + LetMethodCall(names_copy, cls, method.copy, args.map(_.mapNameOfTrivialExpr(_.trySubst(ctx))), body.copy(ctx ++ names_copy.map(x => x.str -> x))) + case lc @ LetCall(names, defn, args, itr, body) => + val names_copy = names.map(_.copy) + LetCall(names_copy, defn, args.map(_.mapNameOfTrivialExpr(_.trySubst(ctx))), itr, body.copy(ctx ++ names_copy.map(x => x.str -> x)))(lc.loc) - private def toDocument: Document = this match - case Result(res) => raw(res |> show_args) <:> raw(s"-- $tag") + def toDocument: Document = + given Conversion[String, Document] = raw + this match + case Result(res) => (res |> showArguments) <:> s"-- $tag" case Jump(jp, args) => - raw("jump") - <:> raw(jp.getName) - <#> raw("(") - <#> raw(args |> show_args) - <#> raw(")") - <:> raw(s"-- $tag") - case Case(x, Ls((tcls, tru), (fcls, fls))) if tcls.ident == "True" && fcls.ident == "False" => - val first = raw("if") <:> raw(x.toString) <:> raw(s"-- $tag") - val tru2 = indent(stack(raw("true") <:> raw ("=>"), tru.toDocument |> indent)) - val fls2 = indent(stack(raw("false") <:> raw ("=>"), fls.toDocument |> indent)) + "jump" + <:> jp.name + <#> "(" + <#> (args |> showArguments) + <#> ")" + <:> s"-- $tag" + case Case(x, Ls((tpat, tru), (fpat, fls)), N) if tpat.isTrue && fpat.isFalse => + val first = "if" <:> x.toString <:> s"-- $tag" + val tru2 = indent(stack("true" <:> "=>", tru.toDocument |> indent)) + val fls2 = indent(stack("false" <:> "=>", fls.toDocument |> indent)) Document.Stacked(Ls(first, tru2, fls2)) - case Case(x, cases) => - val first = raw("case") <:> raw(x.toString) <:> raw("of") <:> raw(s"-- $tag") - val other = cases map { - case (ClassInfo(_, name, _), node) => - indent(stack(raw(name) <:> raw("=>"), node.toDocument |> indent)) + case Case(x, cases, default) => + val first = "case" <:> x.toString <:> "of" <:> s"-- $tag" + val other = cases flatMap { + case (pat, node) => + Ls(pat.toString <:> "=>", node.toDocument |> indent) } - Document.Stacked(first :: other) + default match + case N => stack(first, (Document.Stacked(other) |> indent)) + case S(dc) => + val default = Ls("_" <:> "=>", dc.toDocument |> indent) + stack(first, (Document.Stacked(other ++ default) |> indent)) case LetExpr(x, expr, body) => stack( - raw("let") - <:> raw(x.toString) - <:> raw("=") + "let" + <:> x.toString + <:> "=" <:> expr.toDocument - <:> raw("in") - <:> raw(s"-- $tag"), + <:> "in" + <:> s"-- $tag", + body.toDocument) + case LetMethodCall(xs, cls, method, args, body) => + stack( + "let" + <:> xs.map(_.toString).mkString(",") + <:> "=" + <:> cls.name + <#> "." + <#> method.toString + <#> "(" + <#> args.map{ x => x.toString }.mkString(",") + <#> ")" + <:> "in" + <:> s"-- $tag", body.toDocument) - case LetCall(xs, defn, args, isTailRec, body) => + case LetCall(xs, defn, args, itr, body) => stack( - raw("let*") - <:> raw("(") - <#> raw(xs.map(_.toString).mkString(",")) - <#> raw(")") - <:> raw("=") - <:> raw((if isTailRec then "@tailcall " else "") + defn.getName) - <#> raw("(") - <#> raw(args.map{ x => x.toString }.mkString(",")) - <#> raw(")") - <:> raw("in") - <:> raw(s"-- $tag"), + "let*" + <:> "(" + <#> xs.map(_.toString).mkString(",") + <#> ")" + <:> "=" + <:> (if itr then "@tailcall " else "") + defn.name + <#> "(" + <#> args.map{ x => x.toString }.mkString(",") + <#> ")" + <:> "in" + <:> s"-- $tag", body.toDocument) + def locMarker: LocMarker = val marker = this match case Result(res) => LocMarker.MResult(res.map(_.toExpr.locMarker)) - case Jump(defn, args) => LocMarker.MJump(defn.getName, args.map(_.toExpr.locMarker)) - case Case(scrut, cases) => LocMarker.MCase(scrut.str, cases.map(_._1)) + case Jump(defn, args) => LocMarker.MJump(defn.name, args.map(_.toExpr.locMarker)) + case Case(scrut, cases, default) => LocMarker.MCase(scrut.str, cases.map(_._1), default.isDefined) case LetExpr(name, expr, _) => LocMarker.MLetExpr(name.str, expr.locMarker) - case LetCall(names, defn, args, _, _) => LocMarker.MLetCall(names.map(_.str), defn.getName, args.map(_.toExpr.locMarker)) + case LetMethodCall(names, cls, method, args, _) => LocMarker.MLetMethodCall(names.map(_.str), cls, method.str, args.map(_.toExpr.locMarker)) + case LetCall(names, defn, args, _, _) => LocMarker.MLetCall(names.map(_.str), defn.name, args.map(_.toExpr.locMarker)) marker.tag = this.tag marker + +trait DefTraversalOrdering: + def ordered(entry: Node, defs: Set[Defn]): Ls[Defn] + def orderedNames(entry: Node, defs: Set[Defn]): Ls[Str] + +object DefDfs: + import Node._ + + private object Successors: + def find(node: Node)(using acc: Ls[Defn]): Ls[Defn] = + node match + case Result(res) => acc + case Jump(defn, args) => defn.expectDefn :: acc + case Case(scrut, cases, default) => + val acc2 = cases.map(_._2) ++ default.toList + acc2.foldLeft(acc)((acc, x) => find(x)(using acc)) + case LetExpr(name, expr, body) => find(body) + case LetMethodCall(names, cls, method, args, body) => find(body) + case LetCall(names, defn, args, _, body) => find(body)(using defn.expectDefn :: acc) + + def find(defn: Defn)(using acc: Ls[Defn]): Ls[Defn] = find(defn.body) + def findNames(node: Node)(using acc: Ls[Str]): Ls[Str] = + node match + case Result(res) => acc + case Jump(defn, args) => defn.name :: acc + case Case(scrut, cases, default) => + val acc2 = cases.map(_._2) ++ default.toList + acc2.foldLeft(acc)((acc, x) => findNames(x)(using acc)) + case LetExpr(name, expr, body) => findNames(body) + case LetMethodCall(names, cls, method, args, body) => findNames(body) + case LetCall(names, defn, args, _, body) => findNames(body)(using defn.name :: acc) + + def findNames(defn: Defn)(using acc: Ls[Str]): Ls[Str] = findNames(defn.body) + + private def dfs(using visited: HashMap[Str, Bool], out: ListBuffer[Defn], postfix: Bool)(x: Defn): Unit = + visited.update(x.name, true) + if (!postfix) + out += x + Successors.find(x)(using Nil).foreach { y => + if (!visited(y.name)) + dfs(y) + } + if (postfix) + out += x + + private def dfs(using visited: HashMap[Str, Bool], out: ListBuffer[Defn], postfix: Bool)(x: Node): Unit = + Successors.find(x)(using Nil).foreach { y => + if (!visited(y.name)) + dfs(y) + } + + private def dfsNames(using visited: HashMap[Str, Bool], defs: Set[Defn], out: ListBuffer[Str], postfix: Bool)(x: Defn): Unit = + visited.update(x.name, true) + if (!postfix) + out += x.name + Successors.findNames(x)(using Nil).foreach { y => + if (!visited(y)) + dfsNames(defs.find(_.name == y).get) + } + if (postfix) + out += x.name + + private def dfsNames(using visited: HashMap[Str, Bool], defs: Set[Defn], out: ListBuffer[Str], postfix: Bool)(x: Node): Unit = + Successors.findNames(x)(using Nil).foreach { y => + if (!visited(y)) + dfsNames(defs.find(_.name == y).get) + } + + def dfs(entry: Node, defs: Set[Defn], postfix: Bool): Ls[Defn] = + val visited = HashMap[Str, Bool]() + visited ++= defs.map(_.name -> false) + val out = ListBuffer[Defn]() + dfs(using visited, out, postfix)(entry) + out.toList + + def dfsNames(entry: Node, defs: Set[Defn], postfix: Bool): Ls[Str] = + val visited = HashMap[Str, Bool]() + visited ++= defs.map(_.name -> false) + val out = ListBuffer[Str]() + dfsNames(using visited, defs, out, postfix)(entry) + out.toList + +object DefRevPostOrdering extends DefTraversalOrdering: + def ordered(entry: Node, defs: Set[Defn]): Ls[Defn] = + DefDfs.dfs(entry, defs, true).reverse + def orderedNames(entry: Node, defs: Set[Defn]): Ls[Str] = + DefDfs.dfsNames(entry, defs, true).reverse + +object DefRevPreOrdering extends DefTraversalOrdering: + def ordered(entry: Node, defs: Set[Defn]): Ls[Defn] = + DefDfs.dfs(entry, defs, false).reverse + def orderedNames(entry: Node, defs: Set[Defn]): Ls[Str] = + DefDfs.dfsNames(entry, defs, false).reverse + + + case class DefnTag(inner: Int): def is_valid = inner >= 0 override def equals(x: Any): Bool = x match @@ -250,7 +439,7 @@ case class DefnTag(inner: Int): (this, o) match case (DefnTag(a), DefnTag(b)) => this.is_valid && o.is_valid && a == b case _ => false - override def toString(): String = if is_valid then s"#$inner" else "#x" + override def toString: String = if is_valid then s"#$inner" else "#x" case class DefnLocMarker(val defn: Str, val marker: LocMarker): override def toString: String = s"$defn:$marker" @@ -259,49 +448,60 @@ case class DefnLocMarker(val defn: Str, val marker: LocMarker): enum LocMarker: case MRef(name: Str) case MLit(lit: Lit) - case MCtorApp(name: ClassInfo, args: Ls[LocMarker]) - case MSelect(name: Str, cls: ClassInfo, field: Str) + case MCtorApp(name: ClassRef, args: Ls[LocMarker]) + case MSelect(name: Str, cls: ClassRef, field: Str) case MBasicOp(name: Str, args: Ls[LocMarker]) + case MAssignField(assignee: Str, field: Str, value: LocMarker) case MResult(res: Ls[LocMarker]) case MJump(name: Str, args: Ls[LocMarker]) - case MCase(scrut: Str, cases: Ls[ClassInfo]) + case MCase(scrut: Str, cases: Ls[Pat], default: Bool) case MLetExpr(name: Str, expr: LocMarker) + case MLetMethodCall(names: Ls[Str], cls: ClassRef, method: Str, args: Ls[LocMarker]) case MLetCall(names: Ls[Str], defn: Str, args: Ls[LocMarker]) - case MAssignField(assignee: Str, field: Str, value: LocMarker) var tag = DefnTag(-1) - def toDocument: Document = this match - case MResult(res) => raw("...") + def toDocument: Document = + given Conversion[String, Document] = raw + this match + case MResult(res) => "..." case MJump(jp, args) => - raw("jump") - <:> raw(jp) - <:> raw("...") - case MCase(x, Ls(tcls, fcls)) if tcls.ident == "True" && fcls.ident == "False" => - raw("if") <:> raw(x.toString) <:> raw("...") - case MCase(x, cases) => - raw("case") <:> raw(x.toString) <:> raw("of") <:> raw("...") + "jump" + <:> jp + <:> "..." + case MCase(x, Ls(tpat, fpat), false) if tpat.isTrue && fpat.isFalse => + "if" <:> x.toString <:> "..." + case MCase(x, cases, default) => + "case" <:> x.toString <:> "of" <:> "..." case MLetExpr(x, expr) => - raw("let") - <:> raw(x.toString) - <:> raw("=") - <:> raw("...") + "let" + <:> x.toString + <:> "=" + <:> "..." + case MLetMethodCall(xs, cls, method, args) => + "let" + <:> xs.map(_.toString).mkString(",") + <:> "=" + <:> cls.name + <:> "." + <:> method + <:> "..." case MLetCall(xs, defn, args) => - raw("let*") - <:> raw("(") - <#> raw(xs.map(_.toString).mkString(",")) - <#> raw(")") - <:> raw("=") - <:> raw(defn) - <:> raw("...") - case MRef(s) => s.toString |> raw - case MLit(IntLit(lit)) => s"$lit" |> raw - case MLit(DecLit(lit)) => s"$lit" |> raw - case MLit(StrLit(lit)) => s"$lit" |> raw - case MLit(UnitLit(lit)) => (if lit then "undefined" else "null") |> raw - case _ => raw("...") + "let*" + <:> "(" + <#> xs.map(_.toString).mkString(",") + <#> ")" + <:> "=" + <:> defn + <:> "..." + case MRef(s) => s.toString + case MLit(IntLit(lit)) => s"$lit" + case MLit(DecLit(lit)) => s"$lit" + case MLit(StrLit(lit)) => s"$lit" + case MLit(UnitLit(undefinedOrNull)) => if undefinedOrNull then "undefined" else "null" + case _ => "..." def show = s"$tag-" + toDocument.print - override def toString(): String = show + override def toString: String = show def matches(x: Node): Bool = this.tag == x.tag diff --git a/compiler/shared/main/scala/mlscript/compiler/ir/Interp.scala b/compiler/shared/main/scala/mlscript/compiler/ir/Interp.scala index 016ab09938..8ff52e4f64 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ir/Interp.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ir/Interp.scala @@ -1,324 +1,207 @@ package mlscript.compiler.ir import mlscript._ -import mlscript.compiler._ -import mlscript.compiler.ir.{Node => INode, Expr => IExpr, Program => IProgram, Defn => IDefn, DefnRef => IDefnRef} +import mlscript.compiler.ir._ +import mlscript.compiler.utils._ import mlscript.compiler.optimizer._ import mlscript.utils._ import scala.collection.immutable._ import scala.annotation._ import shorthands._ +import scala.collection.mutable.ListBuffer +import scala.util.boundary, boundary.break -final case class IRInterpreterError(message: String) extends Exception(message) +enum Stuck: + case StuckExpr(expr: Expr, msg: Str) + case StuckNode(node: Node, msg: Str) + + override def toString: String = + this match + case StuckExpr(expr, msg) => s"StuckExpr(${expr.show}, $msg)" + case StuckNode(node, msg) => s"StuckNode(${node.show}, $msg)" + +final case class InterpreterError(message: String) extends Exception(message) class Interpreter(verbose: Bool): private def log(x: Any) = if verbose then println(x) + import Stuck._ - // We have a similar definition of IR here to represent the result of the interpreter. - // This is because IR itself is in A-normal form. - // It represent terms, e.g. "Pair(True, False)", like: - // let x = CtorApp(True, []) in - // let y = CtorApp(False, []) in - // let z = CtorApp(Pair, [x, y]) in - // z - // But I don't want the result of an interpreter to be like this. - // So we release the limitation of the ANF IR here and allow expressions in argument position. - - private case class Program( - classes: Set[ClassInfo], - defs: Set[Defn], - main: Node, + private case class Configuration( + var context: Ctx ) - private case class Defn( - val name: Str, - val params: Ls[Name], - val body: Node, - ) + private type Result[T] = Either[Stuck, T] - private enum Expr: - case Ref(name: Name) + private enum Value: + case Class(cls: ClassInfo, var fields: Ls[Value]) case Literal(lit: Lit) - case CtorApp(name: ClassInfo, var args: Ls[Expr]) - case Select(name: Name, cls: ClassInfo, field: Str) - case BasicOp(name: Str, args: Ls[Expr]) - case AssignField(assignee: Name, clsInfo: ClassInfo, fieldName: Str, value: Expr) - - def show: Str = - document.print - - private def show_args(args: Ls[Expr]) = args map { x => x.show } mkString "," - - def document: Document = this match - case Ref(Name(s)) => s |> raw - case Literal(IntLit(lit)) => s"$lit" |> raw - case Literal(DecLit(lit)) => s"$lit" |> raw - case Literal(StrLit(lit)) => s"$lit" |> raw - case Literal(UnitLit(lit)) => s"$lit" |> raw - case CtorApp(ClassInfo(_, name, _), args) => - raw(name) <#> raw("(") <#> raw(args |> show_args) <#> raw(")") - case Select(Name(s), _, fld) => - raw(s) <#> raw(".") <#> raw(fld) - case BasicOp(name: Str, args) => - raw(name) <#> raw("(") <#> raw(args |> show_args) <#> raw(")") - case AssignField(Name(assignee), clsInfo, fieldName, value) => - stack( - raw("assign") - <:> raw(assignee) - <#> raw(".") - <#> raw(fieldName) - <:> raw("=") - <:> value.document, - ) - - private enum Node: - case Result(res: Ls[Expr]) - case Jump(defn: DefnRef, args: Ls[Expr]) - case Case(scrut: Name, cases: Ls[(ClassInfo, Node)]) - case LetExpr(name: Name, expr: Expr, body: Node) - case LetJoin(joinName: Name, params: Ls[Name], rhs: Node, body: Node) - case LetCall(resultNames: Ls[Name], defn: DefnRef, args: Ls[Expr], body: Node) - - def show: Str = - document.print - - private def showArgs(args: Ls[Expr]) = args map { x => x.show } mkString "," - def document: Document = this match - case Result(res) => raw(res |> showArgs) - case Jump(jp, args) => - raw("jump") - <:> raw(jp.name) - <#> raw("(") - <#> raw(args |> showArgs) - <#> raw(")") - case Case(Name(x), Ls((tcls, tru), (fcls, fls))) if tcls.ident == "True" && fcls.ident == "False" => - val first = raw("if") <:> raw(x) - val tru2 = indent(raw("true") <:> raw ("=>") <:> tru.document) - val fls2 = indent(raw("false") <:> raw ("=>") <:> fls.document) - Document.Stacked(Ls(first, tru2, fls2)) - case Case(Name(x), cases) => - val first = raw("case") <:> raw(x) <:> raw("of") - val other = cases map { - case (ClassInfo(_, name, _), node) => - indent(raw(name) <:> raw("=>") <:> node.document) - } - Document.Stacked(first :: other) - case LetExpr(Name(x), expr, body) => - stack( - raw("let") - <:> raw(x) - <:> raw("=") - <:> expr.document, - raw("in") <:> body.document |> indent) - case LetJoin(Name(x), params, rhs, body) => - stack( - raw("let") - <:> raw("join") - <:> raw(x) - <#> raw("(") - <#> raw(params.map{ x => x.toString }.mkString(",")) - <#> raw(")") - <:> raw("=") - <:> (rhs.document |> indent |> indent), - raw("in") <:> body.document |> indent - ) - case LetCall(resultNames, defn, args, body) => - stack( - raw("let*") - <:> raw("(") - <#> raw(resultNames.map{ x => x.toString }.mkString(",")) - <#> raw(")") - <:> raw("=") - <:> raw(defn.name) - <#> raw("(") - <#> raw(args.map{ x => x.toString }.mkString(",")) - <#> raw(")"), - raw("in") <:> body.document |> indent - ) + override def toString: String = + this match + case Class(cls, fields) => s"${cls.name}(${fields.mkString(",")})" + case Literal(IntLit(lit)) => lit.toString + case Literal(DecLit(lit)) => lit.toString + case Literal(StrLit(lit)) => lit.toString + case Literal(UnitLit(undefinedOrNull)) => if undefinedOrNull then "undefined" else "null" + + private final case class Ctx( + bindingCtx: Map[Str, Value], + classCtx: Map[Str, ClassInfo], + defnCtx: Map[Str, Defn], + ) - private class DefnRef(var defn: Either[Defn, Str]): - def name = defn match - case Left(defn) => defn.name - case Right(name) => name - import Node._ import Expr._ - private def convert(texpr: ir.TrivialExpr): Expr = texpr match - case IExpr.Ref(x) => Ref(x) - case IExpr.Literal(x) => Literal(x) - - private def convertArgs(xs: Ls[ir.TrivialExpr]): Ls[Expr] = xs.map(convert) - - private def convert(expr: IExpr): Expr = expr match - case IExpr.Ref(x) => Ref(x) - case IExpr.Literal(x) => Literal(x) - case IExpr.CtorApp(name, args) => CtorApp(name, args |> convertArgs) - case IExpr.Select(name, cls, field) => Select(name, cls, field) - case IExpr.BasicOp(name, args) => BasicOp(name, args |> convertArgs) - case IExpr.AssignField(assignee, clsInfo, fieldName, value) => AssignField(assignee, clsInfo, fieldName, value |> convert) - - private def convert(node: INode): Node = node match - case INode.Result(xs) => Result(xs |> convertArgs) - case INode.Jump(defnref, args) => Jump(DefnRef(Right(defnref.getName)), args |> convertArgs) - case INode.Case(scrut, cases) => Case(scrut, cases.map{(cls, node) => (cls, node |> convert)}) - case INode.LetExpr(name, expr, body) => LetExpr(name, expr |> convert, body |> convert) - case INode.LetCall(xs, defnref, args, _, body) => - LetCall(xs, DefnRef(Right(defnref.getName)), args |> convertArgs, body |> convert) - - private def convert(defn: IDefn): Defn = - Defn(defn.name, defn.params, defn.body |> convert) - - private def resolveDefnRef(defs: Set[Defn], node: Node): Unit = node match - case Case(_, cases) => cases.foreach { case (cls, node) => resolveDefnRef(defs, node) } - case LetExpr(name, expr, body) => resolveDefnRef(defs, body) - case LetJoin(joinName, params, rhs, body) => resolveDefnRef(defs, body) - case Jump(defnref, args) => defnref.defn = Left(defs.find(_.name == defnref.name).get) - case LetCall(xs, defnref, args, body) => - defnref.defn = Left(defs.find(_.name == defnref.name).get) - resolveDefnRef(defs, body) - case _ => - - private def convert(prog: IProgram): Program = - val classes = prog.classes - val old_defs = prog.defs - val old_main = prog.main - - val defs: Set[Defn] = old_defs.map(convert) - defs.foreach { - case Defn(_, _, body) => resolveDefnRef(defs, body) - } - - val main = convert(old_main) - resolveDefnRef(defs, main) - - Program(classes, defs, main) - - private type Ctx = Map[Str, Expr] - private type ClassCtx = Map[Str, ClassInfo] - - private def getTrue(using clsctx: ClassCtx) = CtorApp(clsctx("True"), Ls.empty) - private def getFalse(using clsctx: ClassCtx) = CtorApp(clsctx("False"), Ls.empty) - - private def eval(using ctx: Ctx, clsctx: ClassCtx)(op: Str, x1: Expr, x2: Expr): Opt[Expr] = (op, x1, x2) match - case ("+", Literal(IntLit(x)), Literal(IntLit(y))) => Some(Literal(IntLit(x + y))) - case ("-", Literal(IntLit(x)), Literal(IntLit(y))) => Some(Literal(IntLit(x - y))) - case ("*", Literal(IntLit(x)), Literal(IntLit(y))) => Some(Literal(IntLit(x * y))) - case ("/", Literal(IntLit(x)), Literal(IntLit(y))) => Some(Literal(IntLit(x / y))) - case ("==", Literal(IntLit(x)), Literal(IntLit(y))) => Some(if x == y then getTrue else getFalse) - case ("!=", Literal(IntLit(x)), Literal(IntLit(y))) => Some(if x != y then getTrue else getFalse) - case ("<=", Literal(IntLit(x)), Literal(IntLit(y))) => Some(if x <= y then getTrue else getFalse) - case (">=", Literal(IntLit(x)), Literal(IntLit(y))) => Some(if x >= y then getTrue else getFalse) - case (">", Literal(IntLit(x)), Literal(IntLit(y))) => Some(if x > y then getTrue else getFalse) - case ("<", Literal(IntLit(x)), Literal(IntLit(y))) => Some(if x < y then getTrue else getFalse) - case _ => None - - private def unifyEvalResult[A](x: Either[A, A]) = - x match - case Left(expr) => expr - case Right(expr) => expr - - private def evalArgs(using ctx: Ctx, clsctx: ClassCtx)(exprs: Ls[Expr]): Either[Ls[Expr], Ls[Expr]] = - var changed = false - - val xs = exprs.map { - arg => eval(arg) match - case Left(expr) => changed = true; expr - case Right(expr) => expr - } - if (changed) Left(xs) else Right(exprs) - - private def evalArgsMayNotProgress(using ctx: Ctx, clsctx: ClassCtx)(exprs: Ls[Expr]) = - exprs.map { - arg => eval(arg) |> unifyEvalResult - } - - private def evalMayNotProgress(using ctx: Ctx, clsctx: ClassCtx)(expr: Expr) = eval(expr) |> unifyEvalResult - - private def eval(using ctx: Ctx, clsctx: ClassCtx)(expr: Expr): Either[Expr, Expr] = expr match - case Ref(Name(x)) => ctx.get(x).toLeft(expr) - case Literal(x) => Right(expr) - case CtorApp(name, args) => - evalArgs(args) match - case Left(xs) => Left(CtorApp(name, xs)) - case Right(xs) => Right(CtorApp(name, xs)) // TODO: This makes recursion modulo cons work, but should be investigated further. - case Select(name, cls, field) => - ctx.get(name.str).map { - case CtorApp(cls2, xs) if cls == cls2 => + private def getTrue(using ctx: Ctx) = Value.Class(ctx.classCtx("True"), Ls.empty) + private def getFalse(using ctx: Ctx) = Value.Class(ctx.classCtx("False"), Ls.empty) + + private def eval(op: Str, x1: Value, x2: Value)(using ctx: Ctx): Opt[Value] = + import Value.{Literal => Li} + (op, x1, x2) match + case ("+", Li(IntLit(x)), Li(IntLit(y))) => S(Li(IntLit(x + y))) + case ("-", Li(IntLit(x)), Li(IntLit(y))) => S(Li(IntLit(x - y))) + case ("*", Li(IntLit(x)), Li(IntLit(y))) => S(Li(IntLit(x * y))) + case ("/", Li(IntLit(x)), Li(IntLit(y))) => S(Li(IntLit(x / y))) + case ("==", Li(IntLit(x)), Li(IntLit(y))) => S(if x == y then getTrue else getFalse) + case ("!=", Li(IntLit(x)), Li(IntLit(y))) => S(if x != y then getTrue else getFalse) + case ("<=", Li(IntLit(x)), Li(IntLit(y))) => S(if x <= y then getTrue else getFalse) + case (">=", Li(IntLit(x)), Li(IntLit(y))) => S(if x >= y then getTrue else getFalse) + case (">", Li(IntLit(x)), Li(IntLit(y))) => S(if x > y then getTrue else getFalse) + case ("<", Li(IntLit(x)), Li(IntLit(y))) => S(if x < y then getTrue else getFalse) + case _ => N + + private def evalArgs(using ctx: Ctx)(exprs: Ls[TrivialExpr]): Result[Ls[Value]] = + var values = ListBuffer.empty[Value] + var stuck: Opt[Stuck] = None + exprs foreach { expr => + stuck match + case None => eval(expr) match + case L(x) => stuck = Some(x) + case R(x) => values += x + case _ => () + } + stuck.toLeft(values.toList) + + private def eval(expr: TrivialExpr)(using ctx: Ctx): Result[Value] = expr match + case e @ Ref(name) => ctx.bindingCtx.get(name.str).toRight(StuckExpr(e, s"undefined variable $name")) + case Literal(lit) => R(Value.Literal(lit)) + + private def eval(expr: Expr)(using ctx: Ctx): Result[Value] = expr match + case Ref(Name(x)) => ctx.bindingCtx.get(x).toRight(StuckExpr(expr, s"undefined variable $x")) + case Literal(x) => R(Value.Literal(x)) + case CtorApp(cls, args) => for { + xs <- evalArgs(args) + cls <- ctx.classCtx.get(cls.name).toRight(StuckExpr(expr, s"undefined class ${cls.name}")) + } yield Value.Class(cls, xs) + case Select(name, cls, field) => + ctx.bindingCtx.get(name.str).toRight(StuckExpr(expr, s"undefined variable $name")).flatMap { + case Value.Class(cls2, xs) if cls.name == cls2.name => xs.zip(cls2.fields).find{_._2 == field} match - case Some((x, _)) => x - case None => throw IRInterpreterError("unable to find selected field") - case x @ _ => throw IRInterpreterError(s"unexpected node: select $field but got $x when eval $expr") - }.toLeft(expr) - case BasicOp(name, args) => - val xs = evalArgsMayNotProgress(args) - val x = name match - case "+" | "-" | "*" | "/" | "==" | "!=" | "<=" | ">=" | "<" | ">" => - eval(using ctx, clsctx)(name, xs.head, xs.tail.head) - case _ => throw IRInterpreterError("unexpected basic operation") - x.toLeft(expr) - case AssignField(assignee, clsInfo, fieldName, expr) => - val value = evalMayNotProgress(expr) - ctx.get(assignee.str) match - case Some(x: CtorApp) => - val CtorApp(cls, args) = x - val idx = cls.fields.indexOf(fieldName) - val newArgs = args.updated(idx, value) - x.args = newArgs - Left(x) - case Some(_) => throw IRInterpreterError("tried to assign a field of a non-ctor") - case None => throw IRInterpreterError("could not find value " + assignee) - - private def expectDefn(r: DefnRef) = r.defn match - case Left(value) => value - case Right(value) => throw IRInterpreterError("only has the name of definition") - - private def evalMayNotProgress(using ctx: Ctx, clsctx: ClassCtx)(node: Node) = eval(node) |> unifyEvalResult - - @tailrec - private def eval(using ctx: Ctx, clsctx: ClassCtx)(node: Node): Either[Node, Node] = node match - case Result(xs) => - xs |> evalArgs match - case Left(xs) => Left(Result(xs)) - case _ => Right(node) - case Jump(defnref, args) => - val xs = args |> evalArgsMayNotProgress - val defn = defnref |> expectDefn - val ctx1 = ctx ++ defn.params.map{_.str}.zip(xs) - eval(using ctx1, clsctx)(defn.body) - case Case(scrut, cases) => - val CtorApp(cls, xs) = (Ref(scrut):Expr) |> evalMayNotProgress(using ctx, clsctx) match { - case x: CtorApp => x - case x => throw IRInterpreterError(s"not a class $x") + case Some((x, _)) => R(x) + case None => L(StuckExpr(expr, s"unable to find selected field $field")) + case Value.Class(cls2, xs) => L(StuckExpr(expr, s"unexpected class $cls2")) + case x => L(StuckExpr(expr, s"unexpected value $x")) } - val arm = cases.find{_._1 == cls} match { - case Some((_, x)) => x - case _ => throw IRInterpreterError(s"can not find the matched case, $cls expected") + case BasicOp(name, args) => boundary: + evalArgs(args).flatMap( + xs => + name match + case "+" | "-" | "*" | "/" | "==" | "!=" | "<=" | ">=" | "<" | ">" => + if xs.length < 2 then break: + L(StuckExpr(expr, s"not enough arguments for basic operation $name")) + else eval(name, xs.head, xs.tail.head).toRight(StuckExpr(expr, s"unable to evaluate basic operation")) + case _ => L(StuckExpr(expr, s"unexpected basic operation $name"))) + case AssignField(assignee, cls, field, value) => + for { + x <- eval(Ref(assignee): TrivialExpr) + y <- eval(value) + res <- x match + case obj @ Value.Class(cls2, xs) if cls.name == cls2.name => + xs.zip(cls2.fields).find{_._2 == field} match + case Some((_, _)) => + obj.fields = xs.map(x => if x == obj then y else x) + // Ideally, we should return a unit value here, but here we return the assignee value for simplicity. + R(obj) + case None => L(StuckExpr(expr, s"unable to find selected field $field")) + case Value.Class(cls2, xs) => L(StuckExpr(expr, s"unexpected class $cls2")) + case x => L(StuckExpr(expr, s"unexpected value $x")) + } yield res + + private def eval(node: Node)(using ctx: Ctx): Result[Ls[Value]] = node match + case Result(res) => evalArgs(res) + case Jump(defn, args) => for { + xs <- evalArgs(args) + defn <- ctx.defnCtx.get(defn.name).toRight(StuckNode(node, s"undefined function ${defn.name}")) + ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx ++ defn.params.map{_.str}.zip(xs)) + res <- eval(defn.body)(using ctx1) + } yield res + case Case(scrut, cases, default) => + eval(Ref(scrut): Expr) flatMap { + case Value.Class(cls, fields) => + cases.find { + case (Pat.Class(cls2), _) => cls.name == cls2.name + case _ => false + } match { + case Some((_, x)) => eval(x) + case None => + default match + case S(x) => eval(x) + case N => L(StuckNode(node, s"can not find the matched case, ${cls.name} expected")) + } + case Value.Literal(lit) => + cases.find { + case (Pat.Lit(lit2), _) => lit == lit2 + case _ => false + } match { + case Some((_, x)) => eval(x) + case None => + default match + case S(x) => eval(x) + case N => L(StuckNode(node, s"can not find the matched case, $lit expected")) + } } - eval(arm) case LetExpr(name, expr, body) => - val x = evalMayNotProgress(expr) - val ctx1 = ctx + (name.str -> x) - eval(using ctx1, clsctx)(body) - case LetCall(xs, defnref, args, body) => - val defn = defnref |> expectDefn - val ys = args |> evalArgsMayNotProgress - val ctx1 = ctx ++ defn.params.map{_.str}.zip(ys) - val res = evalMayNotProgress(using ctx1, clsctx)(defn.body) match { - case Result(xs) => xs - case _ => throw IRInterpreterError("unexpected node") - } - val ctx2 = ctx ++ xs.map{_.str}.zip(res) - eval(using ctx2, clsctx)(body) - case _ => throw IRInterpreterError("unexpected node") - - private def interpret(prog: Program): Node = + for { + x <- eval(expr) + ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx + (name.str -> x)) + res <- eval(body)(using ctx1) + } yield res + case LetMethodCall(names, cls, method, args, body) => + for { + ys <- evalArgs(args).flatMap { + case Value.Class(cls2, xs) :: args => + cls2.methods.get(method.str).toRight(StuckNode(node, s"undefined method ${method.str}")).flatMap { method => + val ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx ++ cls2.fields.zip(xs) ++ method.params.map{_.str}.zip(args)) + eval(method.body)(using ctx1) + } + case _ => L(StuckNode(node, s"not enough arguments for method call, or the first argument is not a class")) + } + ctx2 = ctx.copy(bindingCtx = ctx.bindingCtx ++ names.map{_.str}.zip(ys)) + res <- eval(body)(using ctx2) + } yield res + // case LetApply(names, fn, args, body) => eval(LetMethodCall(names, ClassRef(R("Callable")), Name("apply" + args.length), (Ref(fn): TrivialExpr) :: args, body)) + case LetCall(names, defn, args, _, body) => + for { + xs <- evalArgs(args) + defn <- ctx.defnCtx.get(defn.name).toRight(StuckNode(node, s"undefined function ${defn.name}")) + ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx ++ defn.params.map{_.str}.zip(xs)) + ys <- eval(defn.body)(using ctx1) + ctx2 = ctx.copy(bindingCtx = ctx.bindingCtx ++ names.map{_.str}.zip(ys)) + res <- eval(body)(using ctx2) + } yield res + + private def f(prog: Program): Ls[Value] = val Program(classes, defs, main) = prog - val clsctx = classes.map(x => x.ident -> x).toMap - evalMayNotProgress(using Map.empty, clsctx)(main) + given Ctx = Ctx( + bindingCtx = Map.empty, + classCtx = classes.map{cls => cls.name -> cls}.toMap, + defnCtx = defs.map{defn => defn.name -> defn}.toMap, + ) + eval(main) match + case R(x) => x + case L(x) => throw InterpreterError("Stuck evaluation: " + x.toString) - def interpret(irprog: ir.Program): Str = - val prog = convert(irprog) - val node = interpret(prog) - node.show + def interpret(prog: Program): Str = + val node = f(prog) + node.map(_.toString).mkString(",") diff --git a/compiler/shared/main/scala/mlscript/compiler/ir/RefResolver.scala b/compiler/shared/main/scala/mlscript/compiler/ir/RefResolver.scala new file mode 100644 index 0000000000..a1574137f9 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/ir/RefResolver.scala @@ -0,0 +1,55 @@ +package mlscript.compiler.ir + +import mlscript.utils.shorthands._ +import mlscript.compiler.ir._ + +import Node._ + +// Resolves the definition references by turning them from Right(name) to Left(Defn). +private final class RefResolver(defs: Map[Str, Defn], classes: Map[Str, ClassInfo], allowInlineJp: Bool): + private def f(x: Expr): Unit = x match + case Expr.Ref(name) => + case Expr.Literal(lit) => + case Expr.CtorApp(cls, args) => classes.get(cls.name) match + case None => throw IRError(f"unknown class ${cls.name} in ${classes.keySet.mkString(",")}") + case Some(value) => cls.cls = Left(value) + case Expr.Select(name, cls, field) => classes.get(cls.name) match + case None => throw IRError(f"unknown class ${cls.name} in ${classes.keySet.mkString(",")}") + case Some(value) => cls.cls = Left(value) + case Expr.BasicOp(name, args) => + case Expr.AssignField(assigneee, cls, field, value) => classes.get(cls.name) match + case None => throw IRError(f"unknown class ${cls.name} in ${classes.keySet.mkString(",")}") + case Some(value) => cls.cls = Left(value) + + private def f(x: Pat): Unit = x match + case Pat.Lit(lit) => + case Pat.Class(cls) => classes.get(cls.name) match + case None => throw IRError(f"unknown class ${cls.name} in ${classes.keySet.mkString(",")}") + case Some(value) => cls.cls = Left(value) + + private def f(x: Node): Unit = x match + case Result(res) => + case Case(scrut, cases, default) => cases foreach { (_, body) => f(body) }; default foreach f + case LetExpr(name, expr, body) => f(expr); f(body) + case LetMethodCall(names, cls, method, args, body) => f(body) + case LetCall(resultNames, defnref, args, _, body) => + defs.get(defnref.name) match + case Some(defn) => defnref.defn = Left(defn) + case None => throw IRError(f"unknown function ${defnref.name} in ${defs.keySet.mkString(",")}") + f(body) + case Jump(defnref, _) => + // maybe not promoted yet + defs.get(defnref.name) match + case Some(defn) => defnref.defn = Left(defn) + case None => + if (!allowInlineJp) + throw IRError(f"unknown function ${defnref.name} in ${defs.keySet.mkString(",")}") + def run(node: Node) = f(node) + def run(node: Defn) = f(node.body) + +def resolveRef(entry: Node, defs: Set[Defn], classes: Set[ClassInfo], allowInlineJp: Bool = false): Unit = + val defsMap = defs.map(x => x.name -> x).toMap + val classesMap = classes.map(x => x.name -> x).toMap + val rl = RefResolver(defsMap, classesMap, allowInlineJp) + rl.run(entry) + defs.foreach(rl.run(_)) diff --git a/compiler/shared/main/scala/mlscript/compiler/ir/Validator.scala b/compiler/shared/main/scala/mlscript/compiler/ir/Validator.scala index ce7f09c2c9..2a9695c382 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ir/Validator.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ir/Validator.scala @@ -3,14 +3,31 @@ package mlscript.compiler.ir import mlscript.utils.shorthands._ import mlscript.compiler.ir._ -import Node._ -private final class DefnRefInSet(defs: Set[Defn]): +private final class DefnRefInSet(defs: Set[Defn], classes: Set[ClassInfo]): + import Node._ + import Expr._ + + private def f(x: Expr): Unit = x match + case Ref(name) => + case Literal(lit) => + case CtorApp(name, args) => + case Select(name, clsref, field) => clsref.getClass match { + case Some(real_class) => if (!classes.exists(_ eq real_class)) throw IRError("ref is not in the set") + case _ => + } + case BasicOp(name, args) => + case AssignField(assignee, clsref, _, value) => clsref.getClass match { + case Some(real_class) => if (!classes.exists(_ eq real_class)) throw IRError("ref is not in the set") + case _ => + } + private def f(x: Node): Unit = x match case Result(res) => case Jump(defn, args) => - case Case(scrut, cases) => cases map { (_, body) => f(body) } + case Case(scrut, cases, default) => cases foreach { (_, body) => f(body) }; default foreach f case LetExpr(name, expr, body) => f(body) + case LetMethodCall(names, cls, method, args, body) => f(body) case LetCall(res, defnref, args, _, body) => defnref.getDefn match { case Some(real_defn) => if (!defs.exists(_ eq real_defn)) throw IRError("ref is not in the set") @@ -20,10 +37,10 @@ private final class DefnRefInSet(defs: Set[Defn]): def run(node: Node) = f(node) def run(defn: Defn) = f(defn.body) -def validateDefnRefInSet(entry: Node, defs: Set[Defn]): Unit = - val dris = DefnRefInSet(defs) +def validateRefInSet(entry: Node, defs: Set[Defn], classes: Set[ClassInfo]): Unit = + val dris = DefnRefInSet(defs, classes) defs.foreach(dris.run(_)) -def validate(entry: Node, defs: Set[Defn]): Unit = - validateDefnRefInSet(entry, defs) +def validate(entry: Node, defs: Set[Defn], classes: Set[ClassInfo]): Unit = + validateRefInSet(entry, defs, classes) diff --git a/compiler/shared/main/scala/mlscript/compiler/optimizer/Analysis.scala b/compiler/shared/main/scala/mlscript/compiler/optimizer/Analysis.scala index f0b02d2777..b320a87fbf 100644 --- a/compiler/shared/main/scala/mlscript/compiler/optimizer/Analysis.scala +++ b/compiler/shared/main/scala/mlscript/compiler/optimizer/Analysis.scala @@ -46,7 +46,8 @@ class UsefulnessAnalysis(verbose: Bool = false): private def f(x: Node): Unit = x match case Result(res) => res.foreach(f) case Jump(defn, args) => args.foreach(f) - case Case(scrut, cases) => addUse(scrut); cases.foreach { case (cls, body) => f(body) } + case Case(scrut, cases, default) => addUse(scrut); cases.foreach { case (cls, body) => f(body) }; default.foreach(f) + case LetMethodCall(names, cls, method, args, body) => addUse(method); args.foreach(f); names.foreach(addDef); f(body) case LetExpr(name, expr, body) => f(expr); addDef(name); f(body) case LetCall(names, defn, args, _, body) => args.foreach(f); names.foreach(addDef); f(body) @@ -77,17 +78,22 @@ class FreeVarAnalysis(extended_scope: Bool = true, verbose: Bool = false): case Result(res) => res.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) case Jump(defnref, args) => var fv2 = args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) - if (extended_scope && !visited.contains(defnref.getName)) + if (extended_scope && !visited.contains(defnref.name)) val defn = defnref.expectDefn visited.add(defn.name) val defined2 = defn.params.foldLeft(defined)((acc, param) => acc + param.str) fv2 = f(using defined2)(defn, fv2) fv2 - case Case(scrut, cases) => + case Case(scrut, cases, default) => val fv2 = if (defined.contains(scrut.str)) fv else fv + scrut.str - cases.foldLeft(fv2) { + val fv3 = cases.foldLeft(fv2) { case (acc, (cls, body)) => f(using defined)(body, acc) } + fv3 + case LetMethodCall(resultNames, cls, method, args, body) => + var fv2 = args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) + val defined2 = resultNames.foldLeft(defined)((acc, name) => acc + name.str) + f(using defined2)(body, fv2) case LetExpr(name, expr, body) => val fv2 = f(using defined)(expr, fv) val defined2 = defined + name.str @@ -95,7 +101,7 @@ class FreeVarAnalysis(extended_scope: Bool = true, verbose: Bool = false): case LetCall(resultNames, defnref, args, _, body) => var fv2 = args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) val defined2 = resultNames.foldLeft(defined)((acc, name) => acc + name.str) - if (extended_scope && !visited.contains(defnref.getName)) + if (extended_scope && !visited.contains(defnref.name)) val defn = defnref.expectDefn visited.add(defn.name) val defined2 = defn.params.foldLeft(defined)((acc, param) => acc + param.str) diff --git a/compiler/shared/main/scala/mlscript/compiler/optimizer/TailRecOpt.scala b/compiler/shared/main/scala/mlscript/compiler/optimizer/TailRecOpt.scala index 1405e45765..3019421f8e 100644 --- a/compiler/shared/main/scala/mlscript/compiler/optimizer/TailRecOpt.scala +++ b/compiler/shared/main/scala/mlscript/compiler/optimizer/TailRecOpt.scala @@ -80,7 +80,7 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag case TailCallInfo(src, defn) => f"TailCall { ${src.name}$$${src.id} -> ${defn.name}$$${defn.id} }" case ModConsCallInfo(src, startNode, defn, letCallNode, letCtorNode, _, _) => - f"ModConsCall { ${src.name}$$${src.id} -> ${defn.name}$$${defn.id}, class: ${letCtorNode.cls.ident}, field: ${letCtorNode.fieldName} }" + f"ModConsCall { ${src.name}$$${src.id} -> ${defn.name}$$${defn.id}, class: ${letCtorNode.cls.name}, field: ${letCtorNode.fieldName} }" def getSrc = this match case NormalCallInfo(src, _) => src @@ -107,8 +107,8 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag // Hack to make scala think discoverJoinPoints is tail recursive and be // partially optimized :P - def casesToJps(cases: List[(ClassInfo, Node)], acc: Set[Defn]): Set[Defn] = - cases.foldLeft(acc)((jps, branch) => discoverJoinPoints(branch._2, jps)) + def casesToJps(cases: List[(Pat, Node)], default: Opt[Node], acc: Set[Defn]): Set[Defn] = + cases.foldLeft(default.fold(acc)(x => discoverJoinPoints(x, acc)))((jps, branch) => discoverJoinPoints(branch._2, jps)) def discoverJoinPointsCont(defn: Defn, acc: Set[Defn]) = discoverJoinPoints(defn.body, acc) + defn @@ -122,7 +122,8 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag val ret = node match case Jump(defn, args) => isIdentityJp(defn.expectDefn) case _: LetCall => false - case Case(scrut, cases) => cases.foldLeft(true)((value, branch) => value && isPure(branch._2)) + case LetMethodCall(names, cls, method, args, body) => false + case Case(scrut, cases, default) => cases.foldLeft(default.fold(false)(isPure))((value, branch) => value && isPure(branch._2)) case LetExpr(name, expr: Expr.AssignField, body) => false case x: LetExpr => true case Result(res) => true @@ -144,8 +145,9 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag if isIdentityJp(defn) then acc else if acc.contains(defn) then acc else discoverJoinPointsCont(defn, acc + defn) - case Case(scrut, cases) => casesToJps(cases, acc) + case Case(scrut, cases, default) => casesToJps(cases, default, acc) case LetExpr(name, expr, body) => discoverJoinPoints(body, acc) + case LetMethodCall(names, cls, method, args, body) => discoverJoinPoints(body, acc) case LetCall(names, defn, args, isTailRec, body) => discoverJoinPoints(body, acc) private def getRetName(names: Set[Name], retVals: List[TrivialExpr]): Option[Name] = @@ -234,7 +236,7 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag case _ => returnNone case _ => returnNone - case Case(scrut, cases) => Right(cases.map(_._2)) + case Case(scrut, cases, default) => Right(cases.map(_._2) ++ default.toList) case x @ LetExpr(name, expr, body) => expr match // Check if this let binding references the mod cons call. @@ -288,10 +290,10 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag case _ => false } - val fieldName = clsInfo.fields(ctorArgIndex) + val fieldName = clsInfo.expectClass.fields(ctorArgIndex) // populate required values - searchOptCalls(body)(acc, src, scc, start, calledDefn, letCallNode, Some(LetCtorNodeInfo(x, y, clsInfo, name, fieldName, ctorArgIndex)), Set(name)) + searchOptCalls(body)(acc, src, scc, start, calledDefn, letCallNode, Some(LetCtorNodeInfo(x, y, clsInfo.expectClass, name, fieldName, ctorArgIndex)), Set(name)) case Some(_) => // another constructor is already using the call. Not OK @@ -340,6 +342,10 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag // If this assignment overwrites the mod cons value, forget it if containingCtors.contains(assignee) then invalidateAndCont(body) else searchOptCalls(body) + case LetMethodCall(names, cls, method, args, body) => + // method call is unresolved, just ignore it + // `containingCtors -- names.toSet` takes care of variable shadowing + searchOptCalls(body)(acc, src, scc, start, calledDefn, letCallNode, letCtorNode, containingCtors -- names.toSet) case x @ LetCall(names, defn, args, isTailRec, body) => val callInScc = scc.contains(defn.expectDefn) @@ -468,8 +474,9 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag node match case Result(res) => acc case Jump(defn, args) => acc - case Case(scrut, cases) => cases.foldLeft(acc)((acc, item) => searchCalls(item._2)(src, acc)) + case Case(scrut, cases, default) => cases.foldLeft(default.fold(acc)(x => searchCalls(x)(src, acc)))((acc, item) => searchCalls(item._2)(src, acc)) case LetExpr(name, expr, body) => searchCalls(body) + case LetMethodCall(names, cls, method, args, body) => searchCalls(body) case LetCall(names, defn, args, isTailRec, body) => val newSet = acc.get(src.id) match case None => Set(defn.expectDefn) @@ -580,7 +587,7 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag // False -> e2 def makeCaseBranch(value: Int, e1: Node, e2: Node): Node = val name = Name("scrut") - val cases = Case(name, List((trueClass, e1), (falseClass, e2))).attachTag(tag) + val cases = Case(name, List((Pat.Class(ClassRef(L(trueClass))), e1), (Pat.Class(ClassRef(L(falseClass))), e2)), None).attachTag(tag) LetExpr( name, Expr.BasicOp("==", List(asLit(value), Expr.Ref(scrutName))), @@ -616,6 +623,8 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag // The idea to use `ptr` and `field` to represent a pointer is by @LPTK. final val ID_CTX_CLASS = ClassInfo(classUid.make, ID_CONTEXT_NAME, Nil) final val CTX_CLASS = ClassInfo(classUid.make, CONTEXT_NAME, List("acc", "ptr", "field")) + final val ID_CTX_CLASS_REF = ClassRef(L(ID_CTX_CLASS)) + final val CTX_CLASS_REF = ClassRef(L(CTX_CLASS)) // Given a strongly connected component `defns` of mutually // tail recursive functions, returns a strongly connected component contaning the @@ -632,8 +641,8 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag if modConsCalls.isEmpty then (component, Set()) else - val trueClass = classes.find(c => c.ident == "True").get - val falseClass = classes.find(c => c.ident == "False").get + val trueClass = classes.find(c => c.name == "True").get + val falseClass = classes.find(c => c.name == "False").get // CONTEXT APPLICATION @@ -666,18 +675,18 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag // acc val node = LetExpr( Name("ptr"), - Expr.Select(appCtxName, CTX_CLASS, "ptr"), + Expr.Select(appCtxName, CTX_CLASS_REF, "ptr"), LetExpr( Name("_"), Expr.AssignField( Name("ptr"), - cls, + ClassRef(L(cls)), fieldName, Expr.Ref(appValName) ), LetExpr( Name("acc"), - Expr.Select(appCtxName, CTX_CLASS, "acc"), // this could be a join point but it's not that bad + Expr.Select(appCtxName, CTX_CLASS_REF, "acc"), // this could be a join point but it's not that bad Result( List(Expr.Ref(Name("acc"))) ).attachTag(tag) @@ -690,7 +699,7 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag val ctxBranch = LetExpr( - Name("field"), Expr.Select(appCtxName, CTX_CLASS, "field"), + Name("field"), Expr.Select(appCtxName, CTX_CLASS_REF, "field"), makeSwitch(Name("field"), assignmentCases.tail, assignmentCases.head._2)(trueClass, falseClass) ).attachTag(tag) @@ -698,9 +707,10 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag val appNode = Case(appCtxName, List( - (ID_CTX_CLASS, idBranch), - (CTX_CLASS, ctxBranch) - ) + (Pat.Class(ID_CTX_CLASS_REF), idBranch), + (Pat.Class(CTX_CLASS_REF), ctxBranch) + ), + None ).attachTag(tag) val appDefn = Defn(ctxAppId, ctxAppName, List(appCtxName, appValName), 1, appNode, false) @@ -721,20 +731,20 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag // ret val cmpNode = LetExpr( Name("ctx2acc"), - Expr.Select(cmpCtx2Name, CTX_CLASS, "acc"), + Expr.Select(cmpCtx2Name, CTX_CLASS_REF, "acc"), LetExpr( Name("ctx2ptr"), - Expr.Select(cmpCtx2Name, CTX_CLASS, "ptr"), + Expr.Select(cmpCtx2Name, CTX_CLASS_REF, "ptr"), LetExpr( Name("ctx2field"), - Expr.Select(cmpCtx2Name, CTX_CLASS, "field"), + Expr.Select(cmpCtx2Name, CTX_CLASS_REF, "field"), LetCall( List(Name("newAcc")), DefnRef(Left(appDefn)), List(Expr.Ref(cmpCtx1Name), Expr.Ref(Name("ctx2acc"))), false, LetExpr( Name("ret"), - Expr.CtorApp(CTX_CLASS, List("newAcc", "ctx2ptr", "ctx2field").map(n => Expr.Ref(Name(n)))), + Expr.CtorApp(CTX_CLASS_REF, List("newAcc", "ctx2ptr", "ctx2field").map(n => Expr.Ref(Name(n)))), Result( List(Expr.Ref(Name("ret"))) ).attachTag(tag) @@ -777,8 +787,9 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag case None => throw IRError("could not find jump point with id" + defn.expectDefn.id) case Some(value) => Jump(value, Expr.Ref(Name("ctx")) :: args) - case Case(scrut, cases) => Case(scrut, cases.map { (cls, body) => (cls, transformNode(body)) }).attachTag(tag) + case Case(scrut, cases, default) => Case(scrut, cases.map { (cls, body) => (cls, transformNode(body)) }, default.map(transformNode)).attachTag(tag) case LetExpr(name, expr, body) => LetExpr(name, expr, transformNode(body)).attachTag(tag) + case LetMethodCall(names, cls, method, args, body) => LetMethodCall(names, cls, method, args, transformNode(body)).attachTag(tag) case LetCall(names, defn, args, isTailRec, body) => // Handle the case when we see a tail call. // This case is not handled by the paper. The way to transform this is: @@ -803,7 +814,7 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag // f(composed, *args) LetExpr( Name("ctx2"), - Expr.CtorApp(CTX_CLASS, List(Expr.Ref(call.retName), Expr.Ref(call.letCtorNode.ctorValName), asLit(field))), + Expr.CtorApp(CTX_CLASS_REF, List(Expr.Ref(call.retName), Expr.Ref(call.letCtorNode.ctorValName), asLit(field))), LetCall( List(Name("composed")), DefnRef(Left(cmpDefn)), @@ -831,7 +842,7 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag // rewrite the ctor, but set the field containing the call as to 0 val idx = call.letCtorNode.idx val argsList = call.letCtorNode.ctor.args.updated(idx, asLit(0)) - LetExpr(name, Expr.CtorApp(call.letCtorNode.cls, argsList), transformModConsBranch(body)).attachTag(tag) + LetExpr(name, Expr.CtorApp(ClassRef(L(call.letCtorNode.cls)), argsList), transformModConsBranch(body)).attachTag(tag) else LetExpr(name, expr, transformModConsBranch(body)).attachTag(tag) case LetCall(names, defn, args, isTailRec, body) => @@ -855,7 +866,7 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag val modConsCall = LetExpr( Name("idCtx"), - Expr.CtorApp(ID_CTX_CLASS, Nil), + Expr.CtorApp(ID_CTX_CLASS_REF, Nil), LetCall( List(Name("res")), DefnRef(Left(modConsDefn)), @@ -896,8 +907,8 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag // Explicitly returns the merged function in case tailrec needs to be checked. private def optimizeTailRec(component: ScComponent, classes: Set[ClassInfo]): (Set[Defn], Defn) = // To build the case block, we need to compare integers and check if the result is "True" - val trueClass = classes.find(c => c.ident == "True").get - val falseClass = classes.find(c => c.ident == "False").get + val trueClass = classes.find(c => c.name == "True").get + val falseClass = classes.find(c => c.name == "False").get // undefined for dummy values val dummyVal = Expr.Literal(UnitLit(true)) @@ -924,8 +935,9 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag def transformNode(node: Node): Node = node match case Result(res) => node.attachTag(tag) case Jump(defn, args) => node.attachTag(tag) - case Case(scrut, cases) => Case(scrut, cases.map((cls, body) => (cls, transformNode(body)))).attachTag(tag) + case Case(scrut, cases, default) => Case(scrut, cases.map((cls, body) => (cls, transformNode(body))), default.map(transformNode)).attachTag(tag) case LetExpr(name, expr, body) => LetExpr(name, expr, transformNode(body)).attachTag(tag) + case LetMethodCall(names, cls, method, args, body) => LetMethodCall(names, cls, method, args, transformNode(body)).attachTag(tag) case LetCall(names, defn_, args, isTailRec, body) => if isTailCall(node) && defn_.expectDefn.id == defn.id then Jump(jpDefnRef, args).attachTag(tag) @@ -990,9 +1002,11 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag Jump(jpDefnRef, transformStackFrame(args, defnInfoMap(defn.expectDefn.id))).attachTag(tag) else node.attachTag(tag) - case Result(_) => node.attachTag(tag) - case Case(scrut, cases) => Case(scrut, cases.map(n => (n._1, transformNode(n._2)))).attachTag(tag) + case Result(_) => node.attachTag(tag) + case Case(scrut, cases, default) => Case(scrut, cases.map(n => (n._1, transformNode(n._2))), default.map(transformNode)).attachTag(tag) case LetExpr(name, expr, body) => LetExpr(name, expr, transformNode(body)).attachTag(tag) + case LetMethodCall(names, cls, method, args, body) => + LetMethodCall(names, cls, method, args, transformNode(body)).attachTag(tag) case LetCall(names, defn, args, isTailRec, body) => if isTailCall(node) && defnInfoMap.contains(defn.expectDefn.id) then Jump(jpDefnRef, transformStackFrame(args, defnInfoMap(defn.expectDefn.id))).attachTag(tag) @@ -1075,11 +1089,12 @@ class TailRecOpt(fnUid: FreshInt, classUid: FreshInt, tag: FreshInt, raise: Diag val partitions = partition(p.defs) val newDefs = partitions.flatMap { optimizeParition(_, p.classes) }.toSet + val newClasses = p.classes + ID_CTX_CLASS + CTX_CLASS // update the definition refs - newDefs.foreach { defn => resolveDefnRef(defn.body, newDefs, true) } - resolveDefnRef(p.main, newDefs, true) + newDefs.foreach { defn => resolveRef(defn.body, newDefs, newClasses, true) } + resolveRef(p.main, newDefs, newClasses, true) - (Program(p.classes + ID_CTX_CLASS + CTX_CLASS, newDefs, p.main), partitions.map(t => t.nodes.map(f => f.name))) + (Program(newClasses, newDefs, p.main), partitions.map(t => t.nodes.map(f => f.name))) def run(p: Program): Program = run_debug(p)._1 \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/simpledef/Simpledef.scala b/compiler/shared/main/scala/mlscript/compiler/simpledef/Simpledef.scala index 4b59f69499..3b05c09669 100644 --- a/compiler/shared/main/scala/mlscript/compiler/simpledef/Simpledef.scala +++ b/compiler/shared/main/scala/mlscript/compiler/simpledef/Simpledef.scala @@ -5,7 +5,7 @@ package simpledef import mlscript.utils.*, shorthands.* import scala.collection.mutable import java.util.IdentityHashMap -import scala.collection.JavaConverters._ +import scala.jdk.CollectionConverters.* type TypeVar type TermId = Uid[Term] diff --git a/compiler/shared/test/diff-ir/Class.mls b/compiler/shared/test/diff-ir/Class.mls new file mode 100644 index 0000000000..9db12fc415 --- /dev/null +++ b/compiler/shared/test/diff-ir/Class.mls @@ -0,0 +1,182 @@ +:NewDefs +:ParseOnly +:UseIR +:NoTailRec + +:prelude +module True +module False +module Callable { + fun apply0() = 0 + fun apply1(x0) = 0 + fun apply2(x0,x1) = 0 + fun apply3(x0,x1,x2) = 0 + fun apply4(x0,x1,x2,x3) = 0 + fun apply5(x0,x1,x2,x3,x4) = 0 +} +module List[A, B] +class Cons[A, B](h: A, t: Cons[A, B]) extends List[A, B] +module Nil[A, B] extends List[A, B] +module Option[A] +class Some[A](x: A) extends Option[A] +module None[A] extends Option[A] +class Pair[A, B](x: A, y: B) +class Tuple2[A, B](x: A, y: B) +class Tuple3[A, B, C](x: A, y: B, z: C) +module Nat +class S(s: Nat) extends Nat +module O extends Nat +class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O) +//│ |#module| |True|↵|#module| |False|↵|#module| |Callable| |{|→|#fun| |apply0|(||)| |#=| |0|↵|#fun| |apply1|(|x0|)| |#=| |0|↵|#fun| |apply2|(|x0|,|x1|)| |#=| |0|↵|#fun| |apply3|(|x0|,|x1|,|x2|)| |#=| |0|↵|#fun| |apply4|(|x0|,|x1|,|x2|,|x3|)| |#=| |0|↵|#fun| |apply5|(|x0|,|x1|,|x2|,|x3|,|x4|)| |#=| |0|←|↵|}|↵|#module| |List|[|A|,| |B|]|↵|#class| |Cons|[|A|,| |B|]|(|h|#:| |A|,| |t|#:| |Cons|[|A|,| |B|]|)| |#extends| |List|[|A|,| |B|]|↵|#module| |Nil|[|A|,| |B|]| |#extends| |List|[|A|,| |B|]|↵|#module| |Option|[|A|]|↵|#class| |Some|[|A|]|(|x|#:| |A|)| |#extends| |Option|[|A|]|↵|#module| |None|[|A|]| |#extends| |Option|[|A|]|↵|#class| |Pair|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple2|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple3|[|A|,| |B|,| |C|]|(|x|#:| |A|,| |y|#:| |B|,| |z|#:| |C|)|↵|#module| |Nat|↵|#class| |S|(|s|#:| |Nat|)| |#extends| |Nat|↵|#module| |O| |#extends| |Nat|↵|#class| |HiddenTheseEntities|(|_0|#:| |HiddenTheseEntities|,| |_1|#:| |True|,| |_2|#:| |False|,| |_3|#:| |Callable|,| |_4|#:| |List|,| |_5|#:| |Cons|,| |_6|#:| |Nil|,| |_7|#:| |Option|,| |_8|#:| |Some|,| |_9|#:| |None|,| |_10|#:| |Pair|,| |_11|#:| |Tuple2|,| |_12|#:| |Tuple3|,| |_13|#:| |Nat|,| |_14|#:| |S|,| |_15|#:| |O|)| +//│ Parsed: {module True {}; module False {}; module Callable {fun apply0 = () => 0; fun apply1 = (x0,) => 0; fun apply2 = (x0, x1,) => 0; fun apply3 = (x0, x1, x2,) => 0; fun apply4 = (x0, x1, x2, x3,) => 0; fun apply5 = (x0, x1, x2, x3, x4,) => 0}; module List‹A, B› {}; class Cons‹A, B›(h: A, t: Cons‹A, B›,): List‹A, B› {}; module Nil‹A, B›: List‹A, B› {}; module Option‹A› {}; class Some‹A›(x: A,): Option‹A› {}; module None‹A›: Option‹A› {}; class Pair‹A, B›(x: A, y: B,) {}; class Tuple2‹A, B›(x: A, y: B,) {}; class Tuple3‹A, B, C›(x: A, y: B, z: C,) {}; module Nat {}; class S(s: Nat,): Nat {}; module O: Nat {}; class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O,) {}} +//│ +//│ Preluded. +//│ + +:genCpp +:runCpp +:showCpp +module Fn extends Callable { + fun apply1(x) = builtin("println", x) +} +class Fn2(a) extends Callable { + fun apply1(x) = + builtin("println", a) + builtin("println", x) +} +class Demo(n) { + fun x() = n +} +fun f(fn) = fn(1) +fun main() = + let d1 = Demo(2) + Demo.x(d1) + let print = Fn() + Fn.apply1(print, 3) + f(print) + let print2 = Fn2(4) + Fn2.apply1(print2, 5) + print2(6) + f(print2) +main() +//│ |#module| |Fn| |#extends| |Callable| |{|→|#fun| |apply1|(|x|)| |#=| |builtin|(|"println"|,| |x|)|←|↵|}|↵|#class| |Fn2|(|a|)| |#extends| |Callable| |{|→|#fun| |apply1|(|x|)| |#=|→|builtin|(|"println"|,| |a|)|↵|builtin|(|"println"|,| |x|)|←|←|↵|}|↵|#class| |Demo|(|n|)| |{|→|#fun| |x|(||)| |#=| |n|←|↵|}|↵|#fun| |f|(|fn|)| |#=| |fn|(|1|)|↵|#fun| |main|(||)| |#=|→|#let| |d1| |#=| |Demo|(|2|)|↵|Demo|.x|(|d1|)|↵|#let| |print| |#=| |Fn|(||)|↵|Fn|.apply1|(|print|,| |3|)|↵|f|(|print|)|↵|#let| |print2| |#=| |Fn2|(|4|)|↵|Fn2|.apply1|(|print2|,| |5|)|↵|print2|(|6|)|↵|f|(|print2|)|←|↵|main|(||)| +//│ Parsed: {module Fn: Callable {fun apply1 = (x,) => builtin("println", x,)}; class Fn2(a,): Callable {fun apply1 = (x,) => {builtin("println", a,); builtin("println", x,)}}; class Demo(n,) {fun x = () => n}; fun f = (fn,) => fn(1,); fun main = () => {let d1 = Demo(2,); (Demo).x(d1,); let print = Fn(); (Fn).apply1(print, 3,); f(print,); let print2 = Fn2(4,); (Fn2).apply1(print2, 5,); print2(6,); f(print2,)}; main()} +//│ +//│ +//│ IR: +//│ Program: +//│ class Fn() extends Callable { +//│ def apply1(x$11) = +//│ let x$12 = Callable.apply2(builtin,println,x$11) in -- #64 +//│ x$12 -- #63 +//│ } +//│ class Fn2(a) extends Callable { +//│ def apply1(x$13) = +//│ let x$14 = Callable.apply2(builtin,println,a) in -- #80 +//│ let x$15 = Callable.apply2(builtin,println,x$13) in -- #79 +//│ x$15 -- #78 +//│ } +//│ class Demo(n) { +//│ def x() = +//│ n -- #81 +//│ } +//│ def f(fn$0) = +//│ let x$1 = Callable.apply1(fn$0,1) in -- #8 +//│ x$1 -- #7 +//│ def main() = +//│ let x$2 = Demo(2) in -- #56 +//│ let x$3 = Demo.x(x$2) in -- #55 +//│ let x$4 = Fn() in -- #54 +//│ let x$5 = Fn.apply1(x$4,3) in -- #53 +//│ let* (x$6) = f(x$4) in -- #52 +//│ let x$7 = Fn2(4) in -- #51 +//│ let x$8 = Fn2.apply1(x$7,5) in -- #50 +//│ let x$9 = Callable.apply1(x$7,6) in -- #49 +//│ let* (x$10) = f(x$7) in -- #48 +//│ x$10 -- #47 +//│ let* (x$0) = main() in -- #2 +//│ x$0 -- #1 +//│ +//│ Cpp: +//│ struct _mls_Demo: public _mlsObject { +//│ _mlsValue _mls_n; +//│ constexpr static inline const char *typeName = "Demo"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_n.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_n); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_n) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Demo; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_n = _mls_n; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_x(){ +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mls_n; +//│ return _mls_retval; +//│ } +//│ }; +//│ struct _mls_Fn: public _mls_Callable { +//│ +//│ constexpr static inline const char *typeName = "Fn"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Fn; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply1(_mlsValue _mls_x_11){ +//│ _mlsValue _mls_retval; +//│ auto _mls_x_12 = _mls_builtin_println(_mls_x_11); +//│ _mls_retval = _mls_x_12; +//│ return _mls_retval; +//│ } +//│ }; +//│ struct _mls_Fn2: public _mls_Callable { +//│ _mlsValue _mls_a; +//│ constexpr static inline const char *typeName = "Fn2"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_a.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_a); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_a) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Fn2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_a = _mls_a; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply1(_mlsValue _mls_x_13){ +//│ _mlsValue _mls_retval; +//│ auto _mls_x_14 = _mls_builtin_println(_mls_a); +//│ auto _mls_x_15 = _mls_builtin_println(_mls_x_13); +//│ _mls_retval = _mls_x_15; +//│ return _mls_retval; +//│ } +//│ }; +//│ _mlsValue _mls_f(_mlsValue _mls_fn_0){ +//│ _mlsValue _mls_retval; +//│ auto _mls_x_1 = _mlsMethodCall<_mls_Callable>(_mls_fn_0)->_mls_apply1(_mlsValue::fromIntLit(1)); +//│ _mls_retval = _mls_x_1; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_main(){ +//│ _mlsValue _mls_retval; +//│ auto _mls_x_2 = _mlsValue::create<_mls_Demo>(_mlsValue::fromIntLit(2)); +//│ auto _mls_x_3 = _mlsMethodCall<_mls_Demo>(_mls_x_2)->_mls_x(); +//│ auto _mls_x_4 = _mlsValue::create<_mls_Fn>(); +//│ auto _mls_x_5 = _mlsMethodCall<_mls_Fn>(_mls_x_4)->_mls_apply1(_mlsValue::fromIntLit(3)); +//│ auto _mls_x_6 = _mls_f(_mls_x_4); +//│ auto _mls_x_7 = _mlsValue::create<_mls_Fn2>(_mlsValue::fromIntLit(4)); +//│ auto _mls_x_8 = _mlsMethodCall<_mls_Fn2>(_mls_x_7)->_mls_apply1(_mlsValue::fromIntLit(5)); +//│ auto _mls_x_9 = _mlsMethodCall<_mls_Callable>(_mls_x_7)->_mls_apply1(_mlsValue::fromIntLit(6)); +//│ auto _mls_x_10 = _mls_f(_mls_x_7); +//│ _mls_retval = _mls_x_10; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain(){ +//│ _mlsValue _mls_retval; +//│ auto _mls_x_0 = _mls_main(); +//│ _mls_retval = _mls_x_0; +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } +//│ +//│ +//│ Execution succeeded: +//│ 3 +//│ 1 +//│ 4 +//│ 5 +//│ 4 +//│ 6 +//│ 4 +//│ 1 +//│ Unit +//│ diff --git a/compiler/shared/test/diff-ir/Currying.mls b/compiler/shared/test/diff-ir/Currying.mls new file mode 100644 index 0000000000..313e1ea98f --- /dev/null +++ b/compiler/shared/test/diff-ir/Currying.mls @@ -0,0 +1,95 @@ +:NewDefs +:ParseOnly +:UseIR +:NoTailRec + +:prelude +module True +module False +module Callable { + fun apply0() = 0 + fun apply1(x0) = 0 + fun apply2(x0,x1) = 0 + fun apply3(x0,x1,x2) = 0 + fun apply4(x0,x1,x2,x3) = 0 + fun apply5(x0,x1,x2,x3,x4) = 0 +} +module List[A, B] +class Cons[A, B](h: A, t: Cons[A, B]) extends List[A, B] +module Nil[A, B] extends List[A, B] +module Option[A] +class Some[A](x: A) extends Option[A] +module None[A] extends Option[A] +class Pair[A, B](x: A, y: B) +class Tuple2[A, B](x: A, y: B) +class Tuple3[A, B, C](x: A, y: B, z: C) +module Nat +class S(s: Nat) extends Nat +module O extends Nat +class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O) +//│ |#module| |True|↵|#module| |False|↵|#module| |Callable| |{|→|#fun| |apply0|(||)| |#=| |0|↵|#fun| |apply1|(|x0|)| |#=| |0|↵|#fun| |apply2|(|x0|,|x1|)| |#=| |0|↵|#fun| |apply3|(|x0|,|x1|,|x2|)| |#=| |0|↵|#fun| |apply4|(|x0|,|x1|,|x2|,|x3|)| |#=| |0|↵|#fun| |apply5|(|x0|,|x1|,|x2|,|x3|,|x4|)| |#=| |0|←|↵|}|↵|#module| |List|[|A|,| |B|]|↵|#class| |Cons|[|A|,| |B|]|(|h|#:| |A|,| |t|#:| |Cons|[|A|,| |B|]|)| |#extends| |List|[|A|,| |B|]|↵|#module| |Nil|[|A|,| |B|]| |#extends| |List|[|A|,| |B|]|↵|#module| |Option|[|A|]|↵|#class| |Some|[|A|]|(|x|#:| |A|)| |#extends| |Option|[|A|]|↵|#module| |None|[|A|]| |#extends| |Option|[|A|]|↵|#class| |Pair|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple2|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple3|[|A|,| |B|,| |C|]|(|x|#:| |A|,| |y|#:| |B|,| |z|#:| |C|)|↵|#module| |Nat|↵|#class| |S|(|s|#:| |Nat|)| |#extends| |Nat|↵|#module| |O| |#extends| |Nat|↵|#class| |HiddenTheseEntities|(|_0|#:| |HiddenTheseEntities|,| |_1|#:| |True|,| |_2|#:| |False|,| |_3|#:| |Callable|,| |_4|#:| |List|,| |_5|#:| |Cons|,| |_6|#:| |Nil|,| |_7|#:| |Option|,| |_8|#:| |Some|,| |_9|#:| |None|,| |_10|#:| |Pair|,| |_11|#:| |Tuple2|,| |_12|#:| |Tuple3|,| |_13|#:| |Nat|,| |_14|#:| |S|,| |_15|#:| |O|)| +//│ Parsed: {module True {}; module False {}; module Callable {fun apply0 = () => 0; fun apply1 = (x0,) => 0; fun apply2 = (x0, x1,) => 0; fun apply3 = (x0, x1, x2,) => 0; fun apply4 = (x0, x1, x2, x3,) => 0; fun apply5 = (x0, x1, x2, x3, x4,) => 0}; module List‹A, B› {}; class Cons‹A, B›(h: A, t: Cons‹A, B›,): List‹A, B› {}; module Nil‹A, B›: List‹A, B› {}; module Option‹A› {}; class Some‹A›(x: A,): Option‹A› {}; module None‹A›: Option‹A› {}; class Pair‹A, B›(x: A, y: B,) {}; class Tuple2‹A, B›(x: A, y: B,) {}; class Tuple3‹A, B, C›(x: A, y: B, z: C,) {}; module Nat {}; class S(s: Nat,): Nat {}; module O: Nat {}; class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O,) {}} +//│ +//│ Preluded. +//│ + +:interpIR +:genCpp +:runCpp +fun add2c(a)(b) = a + b +fun add2(a, b) = a + b +fun add3c(a)(b)(c) = a + b + c +fun main() = + add2c(1)(2) + add2(1, 2) + add3c(1)(2)(3) +main() +//│ |#fun| |add2c|(|a|)|(|b|)| |#=| |a| |+| |b|↵|#fun| |add2|(|a|,| |b|)| |#=| |a| |+| |b|↵|#fun| |add3c|(|a|)|(|b|)|(|c|)| |#=| |a| |+| |b| |+| |c|↵|#fun| |main|(||)| |#=|→|add2c|(|1|)|(|2|)|↵|add2|(|1|,| |2|)|↵|add3c|(|1|)|(|2|)|(|3|)|←|↵|main|(||)| +//│ Parsed: {fun add2c = (a,) => (b,) => +(a, b,); fun add2 = (a, b,) => +(a, b,); fun add3c = (a,) => (b,) => (c,) => +(+(a, b,), c,); fun main = () => {add2c(1,)(2,); add2(1, 2,); add3c(1,)(2,)(3,)}; main()} +//│ +//│ +//│ IR: +//│ Program: +//│ class Lambda$0(a) extends Callable { +//│ def apply1(b$1) = +//│ let x$12 = +(a,b$1) in -- #58 +//│ x$12 -- #57 +//│ } +//│ class Lambda$1(a) extends Callable { +//│ def apply1(b$2) = +//│ let x$14 = Lambda$2(a,b$2) in -- #60 +//│ x$14 -- #59 +//│ } +//│ class Lambda$2(a,b) extends Callable { +//│ def apply1(c$0) = +//│ let x$15 = +(a,b) in -- #73 +//│ let x$16 = +(x$15,c$0) in -- #72 +//│ x$16 -- #71 +//│ } +//│ def add2c(a$0) = +//│ let x$2 = Lambda$0(a$0) in -- #4 +//│ x$2 -- #3 +//│ def add2(a$1,b$0) = +//│ let x$3 = +(a$1,b$0) in -- #11 +//│ x$3 -- #10 +//│ def add3c(a$2) = +//│ let x$5 = Lambda$1(a$2) in -- #13 +//│ x$5 -- #12 +//│ def main() = +//│ let* (x$6) = add2c(1) in -- #45 +//│ let x$7 = Callable.apply1(x$6,2) in -- #44 +//│ let* (x$8) = add2(1,2) in -- #43 +//│ let* (x$9) = add3c(1) in -- #42 +//│ let x$10 = Callable.apply1(x$9,2) in -- #41 +//│ let x$11 = Callable.apply1(x$10,3) in -- #40 +//│ x$11 -- #39 +//│ let* (x$0) = main() in -- #2 +//│ x$0 -- #1 +//│ +//│ Interpreted: +//│ 6 +//│ +//│ +//│ Execution succeeded: +//│ 6 +//│ diff --git a/compiler/shared/test/diff-ir/IR.mls b/compiler/shared/test/diff-ir/IR.mls index b5b44bbcf9..ce5dbd1641 100644 --- a/compiler/shared/test/diff-ir/IR.mls +++ b/compiler/shared/test/diff-ir/IR.mls @@ -1,85 +1,108 @@ -:NewParser +:NewDefs :ParseOnly :UseIR :NoTailRec +:prelude +module True +module False +module Callable { + fun apply0() = 0 + fun apply1(x0) = 0 + fun apply2(x0,x1) = 0 + fun apply3(x0,x1,x2) = 0 + fun apply4(x0,x1,x2,x3) = 0 + fun apply5(x0,x1,x2,x3,x4) = 0 +} +module List[A, B] +class Cons[A, B](h: A, t: Cons[A, B]) extends List[A, B] +module Nil[A, B] extends List[A, B] +module Option[A] +class Some[A](x: A) extends Option[A] +module None[A] extends Option[A] +class Pair[A, B](x: A, y: B) +class Tuple2[A, B](x: A, y: B) +class Tuple3[A, B, C](x: A, y: B, z: C) +module Nat +class S(s: Nat) extends Nat +module O extends Nat +module Either[A, B] +class Left[A, B](x: A) extends Either[A, B] +class Right[A, B](y: B) extends Either[A, B] +class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O, _16: Either, _17: Left, _18: Right) +//│ |#module| |True|↵|#module| |False|↵|#module| |Callable| |{|→|#fun| |apply0|(||)| |#=| |0|↵|#fun| |apply1|(|x0|)| |#=| |0|↵|#fun| |apply2|(|x0|,|x1|)| |#=| |0|↵|#fun| |apply3|(|x0|,|x1|,|x2|)| |#=| |0|↵|#fun| |apply4|(|x0|,|x1|,|x2|,|x3|)| |#=| |0|↵|#fun| |apply5|(|x0|,|x1|,|x2|,|x3|,|x4|)| |#=| |0|←|↵|}|↵|#module| |List|[|A|,| |B|]|↵|#class| |Cons|[|A|,| |B|]|(|h|#:| |A|,| |t|#:| |Cons|[|A|,| |B|]|)| |#extends| |List|[|A|,| |B|]|↵|#module| |Nil|[|A|,| |B|]| |#extends| |List|[|A|,| |B|]|↵|#module| |Option|[|A|]|↵|#class| |Some|[|A|]|(|x|#:| |A|)| |#extends| |Option|[|A|]|↵|#module| |None|[|A|]| |#extends| |Option|[|A|]|↵|#class| |Pair|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple2|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple3|[|A|,| |B|,| |C|]|(|x|#:| |A|,| |y|#:| |B|,| |z|#:| |C|)|↵|#module| |Nat|↵|#class| |S|(|s|#:| |Nat|)| |#extends| |Nat|↵|#module| |O| |#extends| |Nat|↵|#module| |Either|[|A|,| |B|]|↵|#class| |Left|[|A|,| |B|]|(|x|#:| |A|)| |#extends| |Either|[|A|,| |B|]|↵|#class| |Right|[|A|,| |B|]|(|y|#:| |B|)| |#extends| |Either|[|A|,| |B|]|↵|#class| |HiddenTheseEntities|(|_0|#:| |HiddenTheseEntities|,| |_1|#:| |True|,| |_2|#:| |False|,| |_3|#:| |Callable|,| |_4|#:| |List|,| |_5|#:| |Cons|,| |_6|#:| |Nil|,| |_7|#:| |Option|,| |_8|#:| |Some|,| |_9|#:| |None|,| |_10|#:| |Pair|,| |_11|#:| |Tuple2|,| |_12|#:| |Tuple3|,| |_13|#:| |Nat|,| |_14|#:| |S|,| |_15|#:| |O|,| |_16|#:| |Either|,| |_17|#:| |Left|,| |_18|#:| |Right|)| +//│ Parsed: {module True {}; module False {}; module Callable {fun apply0 = () => 0; fun apply1 = (x0,) => 0; fun apply2 = (x0, x1,) => 0; fun apply3 = (x0, x1, x2,) => 0; fun apply4 = (x0, x1, x2, x3,) => 0; fun apply5 = (x0, x1, x2, x3, x4,) => 0}; module List‹A, B› {}; class Cons‹A, B›(h: A, t: Cons‹A, B›,): List‹A, B› {}; module Nil‹A, B›: List‹A, B› {}; module Option‹A› {}; class Some‹A›(x: A,): Option‹A› {}; module None‹A›: Option‹A› {}; class Pair‹A, B›(x: A, y: B,) {}; class Tuple2‹A, B›(x: A, y: B,) {}; class Tuple3‹A, B, C›(x: A, y: B, z: C,) {}; module Nat {}; class S(s: Nat,): Nat {}; module O: Nat {}; module Either‹A, B› {}; class Left‹A, B›(x: A,): Either‹A, B› {}; class Right‹A, B›(y: B,): Either‹A, B› {}; class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O, _16: Either, _17: Left, _18: Right,) {}} +//│ +//│ Preluded. +//│ + + :interpIR -class Pair(x, y) fun mktup2(x, y) = mktup(x, y) fun mktup(x, y) = Pair(x, y) fun foo() = mktup2(1, 2) foo() -//│ |#class| |Pair|(|x|,| |y|)|↵|#fun| |mktup2|(|x|,| |y|)| |#=| |mktup|(|x|,| |y|)|↵|#fun| |mktup|(|x|,| |y|)| |#=| |Pair|(|x|,| |y|)|↵|#fun| |foo|(||)| |#=|→|mktup2|(|1|,| |2|)|←|↵|foo|(||)| -//│ Parsed: {class Pair(x, y,) {}; fun mktup2 = (x, y,) => mktup(x, y,); fun mktup = (x, y,) => Pair(x, y,); fun foo = () => {mktup2(1, 2,)}; foo()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Pair, [x,y])}, { -//│ Def(0, mktup2, [x$0,y$0], -//│ 1, -//│ let* (x$1) = mktup(x$0,y$0) in -- #7 -//│ x$1 -- #6 -//│ ) -//│ Def(1, mktup, [x$2,y$1], -//│ 1, -//│ let x$3 = Pair(x$2,y$1) in -- #14 -//│ x$3 -- #13 -//│ ) -//│ Def(2, foo, [], -//│ 1, -//│ let* (x$4) = mktup2(1,2) in -- #22 -//│ x$4 -- #21 -//│ ) -//│ }, -//│ let* (x$5) = foo() in -- #26 -//│ x$5 -- #25) +//│ |#fun| |mktup2|(|x|,| |y|)| |#=| |mktup|(|x|,| |y|)|↵|#fun| |mktup|(|x|,| |y|)| |#=| |Pair|(|x|,| |y|)|↵|#fun| |foo|(||)| |#=|→|mktup2|(|1|,| |2|)|←|↵|foo|(||)| +//│ Parsed: {fun mktup2 = (x, y,) => mktup(x, y,); fun mktup = (x, y,) => Pair(x, y,); fun foo = () => {mktup2(1, 2,)}; foo()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def mktup2(x$1,y$0) = +//│ let* (x$2) = mktup(x$1,y$0) in -- #9 +//│ x$2 -- #8 +//│ def mktup(x$3,y$1) = +//│ let x$4 = Pair(x$3,y$1) in -- #16 +//│ x$4 -- #15 +//│ def foo() = +//│ let* (x$5) = mktup2(1,2) in -- #23 +//│ x$5 -- #22 +//│ let* (x$0) = foo() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ Pair(1,2) +//│ :interpIR -class Pair(x, y) fun foo(pair) = if pair is Pair(x, y) then Pair(x, y) fun bar() = foo(Pair(1, 2)) bar() -//│ |#class| |Pair|(|x|,| |y|)|↵|#fun| |foo|(|pair|)| |#=|→|#if| |pair| |is|→|Pair|(|x|,| |y|)| |#then| |Pair|(|x|,| |y|)|←|←|↵|#fun| |bar|(||)| |#=|→|foo|(|Pair|(|1|,| |2|)|)|←|↵|bar|(||)| -//│ Parsed: {class Pair(x, y,) {}; fun foo = (pair,) => {if pair is ‹(Pair(x, y,)) then Pair(x, y,)›}; fun bar = () => {foo(Pair(1, 2,),)}; bar()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Pair, [x,y])}, { -//│ Def(0, foo, [pair$0], -//│ 1, -//│ case pair$0 of -- #16 -//│ Pair => -//│ let x$1 = pair$0.y in -- #15 -//│ let x$2 = pair$0.x in -- #14 -//│ let x$3 = Pair(x$2,x$1) in -- #13 -//│ jump j$0(x$3) -- #12 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, bar, [], -//│ 1, -//│ let x$4 = Pair(1,2) in -- #28 -//│ let* (x$5) = foo(x$4) in -- #27 -//│ x$5 -- #26 -//│ ) -//│ }, -//│ let* (x$6) = bar() in -- #32 -//│ x$6 -- #31) +//│ |#fun| |foo|(|pair|)| |#=|→|#if| |pair| |is|→|Pair|(|x|,| |y|)| |#then| |Pair|(|x|,| |y|)|←|←|↵|#fun| |bar|(||)| |#=|→|foo|(|Pair|(|1|,| |2|)|)|←|↵|bar|(||)| +//│ Parsed: {fun foo = (pair,) => {if pair is ‹(Pair(x, y,)) then Pair(x, y,)›}; fun bar = () => {foo(Pair(1, 2,),)}; bar()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def foo(pair$0) = +//│ case pair$0 of -- #23 +//│ Pair => +//│ let x$2 = Pair.y(pair$0) in -- #22 +//│ let x$3 = Pair.x(pair$0) in -- #21 +//│ let x$4 = Pair(x$3,x$2) in -- #20 +//│ jump j$0(x$4) -- #19 +//│ def j$0(x$1) = +//│ x$1 -- #4 +//│ def bar() = +//│ let x$5 = Pair(1,2) in -- #34 +//│ let* (x$6) = foo(x$5) in -- #33 +//│ x$6 -- #32 +//│ let* (x$0) = bar() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ Pair(1,2) +//│ :interpIR -class Pair(x, y) {} fun silly(pair) = let _ = 0 let n = if pair is @@ -92,52 +115,45 @@ fun foo() = let b = silly(a) b foo() -//│ |#class| |Pair|(|x|,| |y|)| |{||}|↵|#fun| |silly|(|pair|)| |#=|→|#let| |_| |#=| |0|↵|#let| |n| |#=| |#if| |pair| |is|→|Pair|(|x1|,| |x2|)| |#then|→|#if| |pair| |is|→|Pair| |(|x3|,| |x4|)| |#then| |x3| |+| |1|←|←|←|↵|n| |+| |1|←|↵|#fun| |foo|(||)| |#=|→|#let| |a| |#=| |Pair|(|0|,| |1|)|↵|#let| |b| |#=| |silly|(|a|)|↵|b|←|↵|foo|(||)| -//│ Parsed: {class Pair(x, y,) {}; fun silly = (pair,) => {let _ = 0; let n = if pair is ‹(Pair(x1, x2,)) then {if pair is ‹(Pair(x3, x4,)) then +(x3,)(1,)›}›; +(n,)(1,)}; fun foo = () => {let a = Pair(0, 1,); let b = silly(a,); b}; foo()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Pair, [x,y])}, { -//│ Def(0, silly, [pair$0], -//│ 1, -//│ let x$0 = 0 in -- #29 -//│ case pair$0 of -- #28 -//│ Pair => -//│ let x$3 = pair$0.y in -- #27 -//│ let x$4 = pair$0.x in -- #26 -//│ case pair$0 of -- #25 +//│ |#fun| |silly|(|pair|)| |#=|→|#let| |_| |#=| |0|↵|#let| |n| |#=| |#if| |pair| |is|→|Pair|(|x1|,| |x2|)| |#then|→|#if| |pair| |is|→|Pair| |(|x3|,| |x4|)| |#then| |x3| |+| |1|←|←|←|↵|n| |+| |1|←|↵|#fun| |foo|(||)| |#=|→|#let| |a| |#=| |Pair|(|0|,| |1|)|↵|#let| |b| |#=| |silly|(|a|)|↵|b|←|↵|foo|(||)| +//│ Parsed: {fun silly = (pair,) => {let _ = 0; let n = if pair is ‹(Pair(x1, x2,)) then {if pair is ‹(Pair(x3, x4,)) then +(x3, 1,)›}›; +(n, 1,)}; fun foo = () => {let a = Pair(0, 1,); let b = silly(a,); b}; foo()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def silly(pair$0) = +//│ let x$1 = 0 in -- #46 +//│ case pair$0 of -- #45 //│ Pair => -//│ let x$6 = pair$0.y in -- #24 -//│ let x$7 = pair$0.x in -- #23 -//│ let x$8 = +(x$7,1) in -- #22 -//│ jump j$1(x$8) -- #21 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ let x$2 = +(x$1,1) in -- #6 -//│ x$2 -- #5 -//│ ) -//│ Def(2, j$1, [x$5], -//│ 1, -//│ jump j$0(x$5) -- #13 -//│ ) -//│ Def(3, foo, [], -//│ 1, -//│ let x$9 = Pair(0,1) in -- #43 -//│ let* (x$10) = silly(x$9) in -- #42 -//│ x$10 -- #41 -//│ ) -//│ }, -//│ let* (x$11) = foo() in -- #47 -//│ x$11 -- #46) +//│ let x$4 = Pair.y(pair$0) in -- #44 +//│ let x$5 = Pair.x(pair$0) in -- #43 +//│ case pair$0 of -- #42 +//│ Pair => +//│ let x$7 = Pair.y(pair$0) in -- #41 +//│ let x$8 = Pair.x(pair$0) in -- #40 +//│ let x$9 = +(x$8,1) in -- #39 +//│ jump j$1(x$9) -- #38 +//│ def j$0(x$2) = +//│ let x$3 = +(x$2,1) in -- #12 +//│ x$3 -- #11 +//│ def j$1(x$6) = +//│ jump j$0(x$6) -- #23 +//│ def foo() = +//│ let x$10 = Pair(0,1) in -- #59 +//│ let* (x$11) = silly(x$10) in -- #58 +//│ x$11 -- #57 +//│ let* (x$0) = foo() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ 2 +//│ :interpIR -class Pair(x, y) fun inc_fst(pair) = let c = 2 if pair is @@ -147,40 +163,35 @@ fun foo() = let b = inc_fst(a) b foo() -//│ |#class| |Pair|(|x|,| |y|)|↵|#fun| |inc_fst|(|pair|)| |#=|→|#let| |c| |#=| |2|↵|#if| |pair| |is|→|Pair|(|x1|,| |x2|)| |#then| |x1| |+| |c|←|←|↵|#fun| |foo|(||)| |#=|→|#let| |a| |#=| |Pair|(|0|,| |1|)|↵|#let| |b| |#=| |inc_fst|(|a|)|↵|b|←|↵|foo|(||)| -//│ Parsed: {class Pair(x, y,) {}; fun inc_fst = (pair,) => {let c = 2; if pair is ‹(Pair(x1, x2,)) then +(x1,)(c,)›}; fun foo = () => {let a = Pair(0, 1,); let b = inc_fst(a,); b}; foo()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Pair, [x,y])}, { -//│ Def(0, inc_fst, [pair$0], -//│ 1, -//│ let x$0 = 2 in -- #15 -//│ case pair$0 of -- #14 -//│ Pair => -//│ let x$2 = pair$0.y in -- #13 -//│ let x$3 = pair$0.x in -- #12 -//│ let x$4 = +(x$3,x$0) in -- #11 -//│ jump j$0(x$4) -- #10 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #2 -//│ ) -//│ Def(2, foo, [], -//│ 1, -//│ let x$5 = Pair(0,1) in -- #29 -//│ let* (x$6) = inc_fst(x$5) in -- #28 -//│ x$6 -- #27 -//│ ) -//│ }, -//│ let* (x$7) = foo() in -- #33 -//│ x$7 -- #32) +//│ |#fun| |inc_fst|(|pair|)| |#=|→|#let| |c| |#=| |2|↵|#if| |pair| |is|→|Pair|(|x1|,| |x2|)| |#then| |x1| |+| |c|←|←|↵|#fun| |foo|(||)| |#=|→|#let| |a| |#=| |Pair|(|0|,| |1|)|↵|#let| |b| |#=| |inc_fst|(|a|)|↵|b|←|↵|foo|(||)| +//│ Parsed: {fun inc_fst = (pair,) => {let c = 2; if pair is ‹(Pair(x1, x2,)) then +(x1, c,)›}; fun foo = () => {let a = Pair(0, 1,); let b = inc_fst(a,); b}; foo()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def inc_fst(pair$0) = +//│ let x$1 = 2 in -- #25 +//│ case pair$0 of -- #24 +//│ Pair => +//│ let x$3 = Pair.y(pair$0) in -- #23 +//│ let x$4 = Pair.x(pair$0) in -- #22 +//│ let x$5 = +(x$4,x$1) in -- #21 +//│ jump j$0(x$5) -- #20 +//│ def j$0(x$2) = +//│ x$2 -- #5 +//│ def foo() = +//│ let x$6 = Pair(0,1) in -- #38 +//│ let* (x$7) = inc_fst(x$6) in -- #37 +//│ x$7 -- #36 +//│ let* (x$0) = foo() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ 2 +//│ :interpIR -class Pair(x, y) fun inc_fst(pair) = let _ = 0 if pair is @@ -189,41 +200,35 @@ fun foo() = let b = inc_fst(Pair(0, 1)) b foo() -//│ |#class| |Pair|(|x|,| |y|)|↵|#fun| |inc_fst|(|pair|)| |#=|→|#let| |_| |#=| |0|↵|#if| |pair| |is|→|Pair|(|x1|,| |x2|)| |#then| |x2| |+| |1|←|←|↵|#fun| |foo|(||)| |#=|→|#let| |b| |#=| |inc_fst|(|Pair|(|0|,| |1|)|)|↵|b|←|↵|foo|(||)| -//│ Parsed: {class Pair(x, y,) {}; fun inc_fst = (pair,) => {let _ = 0; if pair is ‹(Pair(x1, x2,)) then +(x2,)(1,)›}; fun foo = () => {let b = inc_fst(Pair(0, 1,),); b}; foo()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Pair, [x,y])}, { -//│ Def(0, inc_fst, [pair$0], -//│ 1, -//│ let x$0 = 0 in -- #15 -//│ case pair$0 of -- #14 -//│ Pair => -//│ let x$2 = pair$0.y in -- #13 -//│ let x$3 = pair$0.x in -- #12 -//│ let x$4 = +(x$2,1) in -- #11 -//│ jump j$0(x$4) -- #10 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #2 -//│ ) -//│ Def(2, foo, [], -//│ 1, -//│ let x$5 = Pair(0,1) in -- #28 -//│ let* (x$6) = inc_fst(x$5) in -- #27 -//│ x$6 -- #26 -//│ ) -//│ }, -//│ let* (x$7) = foo() in -- #32 -//│ x$7 -- #31) +//│ |#fun| |inc_fst|(|pair|)| |#=|→|#let| |_| |#=| |0|↵|#if| |pair| |is|→|Pair|(|x1|,| |x2|)| |#then| |x2| |+| |1|←|←|↵|#fun| |foo|(||)| |#=|→|#let| |b| |#=| |inc_fst|(|Pair|(|0|,| |1|)|)|↵|b|←|↵|foo|(||)| +//│ Parsed: {fun inc_fst = (pair,) => {let _ = 0; if pair is ‹(Pair(x1, x2,)) then +(x2, 1,)›}; fun foo = () => {let b = inc_fst(Pair(0, 1,),); b}; foo()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def inc_fst(pair$0) = +//│ let x$1 = 0 in -- #25 +//│ case pair$0 of -- #24 +//│ Pair => +//│ let x$3 = Pair.y(pair$0) in -- #23 +//│ let x$4 = Pair.x(pair$0) in -- #22 +//│ let x$5 = +(x$3,1) in -- #21 +//│ jump j$0(x$5) -- #20 +//│ def j$0(x$2) = +//│ x$2 -- #5 +//│ def foo() = +//│ let x$6 = Pair(0,1) in -- #37 +//│ let* (x$7) = inc_fst(x$6) in -- #36 +//│ x$7 -- #35 +//│ let* (x$0) = foo() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ 2 +//│ :interpIR -class Left(x) -class Right(y) fun foo(a, b) = let t = if a is Left(x) then Left(x + 1) @@ -234,132 +239,81 @@ fun foo(a, b) = fun bar() = foo(Right(2), 2) bar() -//│ |#class| |Left|(|x|)|↵|#class| |Right|(|y|)|↵|#fun| |foo|(|a|,| |b|)| |#=|→|#let| |t| |#=| |#if| |a| |is|→|Left|(|x|)| |#then| |Left|(|x| |+| |1|)|↵|Right|(|y|)| |#then| |Right|(|b|)|←|↵|#if| |t| |is|→|Left|(|x|)| |#then| |x|↵|Right|(|y|)| |#then| |y|←|←|↵|#fun| |bar|(||)| |#=|→|foo|(|Right|(|2|)|,| |2|)|←|↵|bar|(||)| -//│ Parsed: {class Left(x,) {}; class Right(y,) {}; fun foo = (a, b,) => {let t = if a is ‹(Left(x,)) then Left(+(x,)(1,),); (Right(y,)) then Right(b,)›; if t is ‹(Left(x,)) then x; (Right(y,)) then y›}; fun bar = () => {foo(Right(2,), 2,)}; bar()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Left, [x]),ClassInfo(3, Right, [y])}, { -//│ Def(0, foo, [a$0,b$0], -//│ 1, -//│ case a$0 of -- #36 -//│ Left => -//│ let x$4 = a$0.x in -- #26 -//│ let x$5 = +(x$4,1) in -- #25 -//│ let x$6 = Left(x$5) in -- #24 -//│ jump j$0(x$6) -- #23 -//│ Right => -//│ let x$7 = a$0.y in -- #35 -//│ let x$8 = Right(b$0) in -- #34 -//│ jump j$0(x$8) -- #33 -//│ ) -//│ Def(1, j$1, [x$1], -//│ 1, -//│ x$1 -- #3 -//│ ) -//│ Def(2, j$0, [x$0], -//│ 1, -//│ case x$0 of -- #14 -//│ Left => -//│ let x$2 = x$0.x in -- #8 -//│ jump j$1(x$2) -- #7 -//│ Right => -//│ let x$3 = x$0.y in -- #13 -//│ jump j$1(x$3) -- #12 -//│ ) -//│ Def(3, bar, [], -//│ 1, -//│ let x$9 = Right(2) in -- #48 -//│ let* (x$10) = foo(x$9,2) in -- #47 -//│ x$10 -- #46 -//│ ) -//│ }, -//│ let* (x$11) = bar() in -- #52 -//│ x$11 -- #51) +//│ |#fun| |foo|(|a|,| |b|)| |#=|→|#let| |t| |#=| |#if| |a| |is|→|Left|(|x|)| |#then| |Left|(|x| |+| |1|)|↵|Right|(|y|)| |#then| |Right|(|b|)|←|↵|#if| |t| |is|→|Left|(|x|)| |#then| |x|↵|Right|(|y|)| |#then| |y|←|←|↵|#fun| |bar|(||)| |#=|→|foo|(|Right|(|2|)|,| |2|)|←|↵|bar|(||)| +//│ Parsed: {fun foo = (a, b,) => {let t = if a is ‹(Left(x,)) then Left(+(x, 1,),); (Right(y,)) then Right(b,)›; if t is ‹(Left(x,)) then x; (Right(y,)) then y›}; fun bar = () => {foo(Right(2,), 2,)}; bar()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def foo(a$0,b$0) = +//│ case a$0 of -- #50 +//│ Left => +//│ let x$5 = Left.x(a$0) in -- #38 +//│ let x$6 = +(x$5,1) in -- #37 +//│ let x$7 = Left(x$6) in -- #36 +//│ jump j$0(x$7) -- #35 +//│ Right => +//│ let x$8 = Right.y(a$0) in -- #49 +//│ let x$9 = Right(b$0) in -- #48 +//│ jump j$0(x$9) -- #47 +//│ def j$1(x$2) = +//│ x$2 -- #6 +//│ def j$0(x$1) = +//│ case x$1 of -- #21 +//│ Left => +//│ let x$3 = Left.x(x$1) in -- #13 +//│ jump j$1(x$3) -- #12 +//│ Right => +//│ let x$4 = Right.y(x$1) in -- #20 +//│ jump j$1(x$4) -- #19 +//│ def bar() = +//│ let x$10 = Right(2) in -- #61 +//│ let* (x$11) = foo(x$10,2) in -- #60 +//│ x$11 -- #59 +//│ let* (x$0) = bar() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ 2 +//│ :interpIR -class Pair(x, y) -fun foo(a) = a.x + a.y +fun foo(a) = Pair.x(a) + Pair.y(a) fun bar() = foo(Pair(1, 0)) bar() -//│ |#class| |Pair|(|x|,| |y|)|↵|#fun| |foo|(|a|)| |#=| |a|.x| |+| |a|.y|↵|#fun| |bar|(||)| |#=|→|foo|(|Pair|(|1|,| |0|)|)|←|↵|bar|(||)| -//│ Parsed: {class Pair(x, y,) {}; fun foo = (a,) => +((a).x,)((a).y,); fun bar = () => {foo(Pair(1, 0,),)}; bar()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Pair, [x,y])}, { -//│ Def(0, foo, [a$0], -//│ 1, -//│ let x$0 = a$0.x in -- #7 -//│ let x$1 = a$0.y in -- #6 -//│ let x$2 = +(x$0,x$1) in -- #5 -//│ x$2 -- #4 -//│ ) -//│ Def(1, bar, [], -//│ 1, -//│ let x$3 = Pair(1,0) in -- #19 -//│ let* (x$4) = foo(x$3) in -- #18 -//│ x$4 -- #17 -//│ ) -//│ }, -//│ let* (x$5) = bar() in -- #23 -//│ x$5 -- #22) +//│ |#fun| |foo|(|a|)| |#=| |Pair|.x|(|a|)| |+| |Pair|.y|(|a|)|↵|#fun| |bar|(||)| |#=|→|foo|(|Pair|(|1|,| |0|)|)|←|↵|bar|(||)| +//│ Parsed: {fun foo = (a,) => +((Pair).x(a,), (Pair).y(a,),); fun bar = () => {foo(Pair(1, 0,),)}; bar()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def foo(a$0) = +//│ let x$1 = Pair.x(a$0) in -- #17 +//│ let x$2 = Pair.y(a$0) in -- #16 +//│ let x$3 = +(x$1,x$2) in -- #15 +//│ x$3 -- #14 +//│ def bar() = +//│ let x$4 = Pair(1,0) in -- #28 +//│ let* (x$5) = foo(x$4) in -- #27 +//│ x$5 -- #26 +//│ let* (x$0) = bar() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ 1 +//│ -:interpIR -class C1(x, y) -class C2(z) -fun foo(a) = if a is - C1(x, y) then x - C2(z) then z -fun bar() = - foo(C1(0, 1)) -bar() -//│ |#class| |C1|(|x|,| |y|)|↵|#class| |C2|(|z|)|↵|#fun| |foo|(|a|)| |#=| |#if| |a| |is|→|C1|(|x|,| |y|)| |#then| |x|↵|C2|(|z|)| |#then| |z|←|↵|#fun| |bar|(||)| |#=|→|foo|(|C1|(|0|,| |1|)|)|←|↵|bar|(||)| -//│ Parsed: {class C1(x, y,) {}; class C2(z,) {}; fun foo = (a,) => if a is ‹(C1(x, y,)) then x; (C2(z,)) then z›; fun bar = () => {foo(C1(0, 1,),)}; bar()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, C1, [x,y]),ClassInfo(3, C2, [z])}, { -//│ Def(0, foo, [a$0], -//│ 1, -//│ case a$0 of -- #15 -//│ C1 => -//│ let x$1 = a$0.y in -- #9 -//│ let x$2 = a$0.x in -- #8 -//│ jump j$0(x$2) -- #7 -//│ C2 => -//│ let x$3 = a$0.z in -- #14 -//│ jump j$0(x$3) -- #13 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, bar, [], -//│ 1, -//│ let x$4 = C1(0,1) in -- #27 -//│ let* (x$5) = foo(x$4) in -- #26 -//│ x$5 -- #25 -//│ ) -//│ }, -//│ let* (x$6) = bar() in -- #31 -//│ x$6 -- #30) -//│ -//│ Interpreted: -//│ 0 :interpIR -class Pair(x, y) fun foo(a, b) = - let x1 = a.x - let y1 = a.y - let x2 = b.x - let y2 = b.y + let x1 = Pair.x(a) + let y1 = Pair.y(a) + let x2 = Pair.x(b) + let y2 = Pair.y(b) x1 + y1 + x2 + y2 fun bar(c) = foo(Pair(0, 1), c) @@ -368,74 +322,67 @@ fun bar(c) = fun baz() = bar(Pair(4,5)) baz() -//│ |#class| |Pair|(|x|,| |y|)|↵|#fun| |foo|(|a|,| |b|)| |#=|→|#let| |x1| |#=| |a|.x|↵|#let| |y1| |#=| |a|.y|↵|#let| |x2| |#=| |b|.x|↵|#let| |y2| |#=| |b|.y|↵|x1| |+| |y1| |+| |x2| |+| |y2|←|↵|#fun| |bar|(|c|)| |#=|→|foo|(|Pair|(|0|,| |1|)|,| |c|)|↵|foo|(|c|,| |Pair|(|2|,| |3|)|)|↵|foo|(|Pair|(|0|,| |1|)|,| |Pair|(|2|,| |3|)|)|←|↵|#fun| |baz|(||)| |#=|→|bar|(|Pair|(|4|,|5|)|)|←|↵|baz|(||)| -//│ Parsed: {class Pair(x, y,) {}; fun foo = (a, b,) => {let x1 = (a).x; let y1 = (a).y; let x2 = (b).x; let y2 = (b).y; +(+(+(x1,)(y1,),)(x2,),)(y2,)}; fun bar = (c,) => {foo(Pair(0, 1,), c,); foo(c, Pair(2, 3,),); foo(Pair(0, 1,), Pair(2, 3,),)}; fun baz = () => {bar(Pair(4, 5,),)}; baz()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Pair, [x,y])}, { -//│ Def(0, foo, [a$0,b$0], -//│ 1, -//│ let x$0 = a$0.x in -- #21 -//│ let x$1 = a$0.y in -- #20 -//│ let x$2 = b$0.x in -- #19 -//│ let x$3 = b$0.y in -- #18 -//│ let x$4 = +(x$0,x$1) in -- #17 -//│ let x$5 = +(x$4,x$2) in -- #16 -//│ let x$6 = +(x$5,x$3) in -- #15 -//│ x$6 -- #14 -//│ ) -//│ Def(1, bar, [c$0], -//│ 1, -//│ let x$7 = Pair(0,1) in -- #69 -//│ let* (x$8) = foo(x$7,c$0) in -- #68 -//│ let x$9 = Pair(2,3) in -- #67 -//│ let* (x$10) = foo(c$0,x$9) in -- #66 -//│ let x$11 = Pair(0,1) in -- #65 -//│ let x$12 = Pair(2,3) in -- #64 -//│ let* (x$13) = foo(x$11,x$12) in -- #63 -//│ x$13 -- #62 -//│ ) -//│ Def(2, baz, [], -//│ 1, -//│ let x$14 = Pair(4,5) in -- #81 -//│ let* (x$15) = bar(x$14) in -- #80 -//│ x$15 -- #79 -//│ ) -//│ }, -//│ let* (x$16) = baz() in -- #85 -//│ x$16 -- #84) +//│ |#fun| |foo|(|a|,| |b|)| |#=|→|#let| |x1| |#=| |Pair|.x|(|a|)|↵|#let| |y1| |#=| |Pair|.y|(|a|)|↵|#let| |x2| |#=| |Pair|.x|(|b|)|↵|#let| |y2| |#=| |Pair|.y|(|b|)|↵|x1| |+| |y1| |+| |x2| |+| |y2|←|↵|#fun| |bar|(|c|)| |#=|→|foo|(|Pair|(|0|,| |1|)|,| |c|)|↵|foo|(|c|,| |Pair|(|2|,| |3|)|)|↵|foo|(|Pair|(|0|,| |1|)|,| |Pair|(|2|,| |3|)|)|←|↵|#fun| |baz|(||)| |#=|→|bar|(|Pair|(|4|,|5|)|)|←|↵|baz|(||)| +//│ Parsed: {fun foo = (a, b,) => {let x1 = (Pair).x(a,); let y1 = (Pair).y(a,); let x2 = (Pair).x(b,); let y2 = (Pair).y(b,); +(+(+(x1, y1,), x2,), y2,)}; fun bar = (c,) => {foo(Pair(0, 1,), c,); foo(c, Pair(2, 3,),); foo(Pair(0, 1,), Pair(2, 3,),)}; fun baz = () => {bar(Pair(4, 5,),)}; baz()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def foo(a$0,b$0) = +//│ let x$1 = Pair.x(a$0) in -- #41 +//│ let x$2 = Pair.y(a$0) in -- #40 +//│ let x$3 = Pair.x(b$0) in -- #39 +//│ let x$4 = Pair.y(b$0) in -- #38 +//│ let x$5 = +(x$1,x$2) in -- #37 +//│ let x$6 = +(x$5,x$3) in -- #36 +//│ let x$7 = +(x$6,x$4) in -- #35 +//│ x$7 -- #34 +//│ def bar(c$0) = +//│ let x$8 = Pair(0,1) in -- #86 +//│ let* (x$9) = foo(x$8,c$0) in -- #85 +//│ let x$10 = Pair(2,3) in -- #84 +//│ let* (x$11) = foo(c$0,x$10) in -- #83 +//│ let x$12 = Pair(0,1) in -- #82 +//│ let x$13 = Pair(2,3) in -- #81 +//│ let* (x$14) = foo(x$12,x$13) in -- #80 +//│ x$14 -- #79 +//│ def baz() = +//│ let x$15 = Pair(4,5) in -- #97 +//│ let* (x$16) = bar(x$15) in -- #96 +//│ x$16 -- #95 +//│ let* (x$0) = baz() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ 6 +//│ :interpIR -class Pair(x, y) fun foo() = let p = Pair(0, 1) - let b = p.x + let b = Pair.x(p) b foo() -//│ |#class| |Pair|(|x|,| |y|)|↵|#fun| |foo|(||)| |#=|→|#let| |p| |#=| |Pair|(|0|,| |1|)|↵|#let| |b| |#=| |p|.x|↵|b|←|↵|foo|(||)| -//│ Parsed: {class Pair(x, y,) {}; fun foo = () => {let p = Pair(0, 1,); let b = (p).x; b}; foo()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Pair, [x,y])}, { -//│ Def(0, foo, [], -//│ 1, -//│ let x$0 = Pair(0,1) in -- #10 -//│ let x$1 = x$0.x in -- #9 -//│ x$1 -- #8 -//│ ) -//│ }, -//│ let* (x$2) = foo() in -- #14 -//│ x$2 -- #13) +//│ |#fun| |foo|(||)| |#=|→|#let| |p| |#=| |Pair|(|0|,| |1|)|↵|#let| |b| |#=| |Pair|.x|(|p|)|↵|b|←|↵|foo|(||)| +//│ Parsed: {fun foo = () => {let p = Pair(0, 1,); let b = (Pair).x(p,); b}; foo()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def foo() = +//│ let x$1 = Pair(0,1) in -- #15 +//│ let x$2 = Pair.x(x$1) in -- #14 +//│ x$2 -- #13 +//│ let* (x$0) = foo() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ 0 +//│ :interpIR -class S(s) -class O fun foo() = bar(S(O)) fun bar(x) = @@ -445,39 +392,33 @@ fun baz(x) = S(s) then s O then x foo() -//│ |#class| |S|(|s|)|↵|#class| |O|↵|#fun| |foo|(||)| |#=|→|bar|(|S|(|O|)|)|←|↵|#fun| |bar|(|x|)| |#=|→|baz|(|x|)|←|↵|#fun| |baz|(|x|)| |#=|→|#if| |x| |is|→|S|(|s|)| |#then| |s|↵|O| |#then| |x|←|←|↵|foo|(||)| -//│ Parsed: {class S(s,) {}; class O {}; fun foo = () => {bar(S(O,),)}; fun bar = (x,) => {baz(x,)}; fun baz = (x,) => {if x is ‹(S(s,)) then s; (O) then x›}; foo()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, S, [s]),ClassInfo(3, O, [])}, { -//│ Def(0, foo, [], -//│ 1, -//│ let x$0 = O() in -- #10 -//│ let x$1 = S(x$0) in -- #9 -//│ let* (x$2) = bar(x$1) in -- #8 -//│ x$2 -- #7 -//│ ) -//│ Def(1, bar, [x$3], -//│ 1, -//│ let* (x$4) = baz(x$3) in -- #16 -//│ x$4 -- #15 -//│ ) -//│ Def(2, baz, [x$5], -//│ 1, -//│ case x$5 of -- #26 -//│ S => -//│ let x$7 = x$5.s in -- #23 -//│ jump j$0(x$7) -- #22 -//│ O => -//│ jump j$0(x$5) -- #25 -//│ ) -//│ Def(3, j$0, [x$6], -//│ 1, -//│ x$6 -- #18 -//│ ) -//│ }, -//│ let* (x$8) = foo() in -- #30 -//│ x$8 -- #29) +//│ |#fun| |foo|(||)| |#=|→|bar|(|S|(|O|)|)|←|↵|#fun| |bar|(|x|)| |#=|→|baz|(|x|)|←|↵|#fun| |baz|(|x|)| |#=|→|#if| |x| |is|→|S|(|s|)| |#then| |s|↵|O| |#then| |x|←|←|↵|foo|(||)| +//│ Parsed: {fun foo = () => {bar(S(O,),)}; fun bar = (x,) => {baz(x,)}; fun baz = (x,) => {if x is ‹(S(s,)) then s; (O) then x›}; foo()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def foo() = +//│ let x$1 = O() in -- #12 +//│ let x$2 = S(x$1) in -- #11 +//│ let* (x$3) = bar(x$2) in -- #10 +//│ x$3 -- #9 +//│ def bar(x$4) = +//│ let* (x$5) = baz(x$4) in -- #17 +//│ x$5 -- #16 +//│ def baz(x$6) = +//│ case x$6 of -- #29 +//│ S => +//│ let x$8 = S.s(x$6) in -- #26 +//│ jump j$0(x$8) -- #25 +//│ O => +//│ jump j$0(x$6) -- #28 +//│ def j$0(x$7) = +//│ x$7 -- #19 +//│ let* (x$0) = foo() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ O() +//│ diff --git a/compiler/shared/test/diff-ir/IRComplex.mls b/compiler/shared/test/diff-ir/IRComplex.mls index e6df8a88ec..5e270c3d18 100644 --- a/compiler/shared/test/diff-ir/IRComplex.mls +++ b/compiler/shared/test/diff-ir/IRComplex.mls @@ -1,8 +1,38 @@ -:NewParser +:NewDefs :ParseOnly :UseIR :NoTailRec +:prelude +module True +module False +module Callable { + fun apply0() = 0 + fun apply1(x0) = 0 + fun apply2(x0,x1) = 0 + fun apply3(x0,x1,x2) = 0 + fun apply4(x0,x1,x2,x3) = 0 + fun apply5(x0,x1,x2,x3,x4) = 0 +} +module List[A, B] +class Cons[A, B](h: A, t: Cons[A, B]) extends List[A, B] +module Nil[A, B] extends List[A, B] +module Option[A] +class Some[A](x: A) extends Option[A] +module None[A] extends Option[A] +class Pair[A, B](x: A, y: B) +class Tuple2[A, B](x: A, y: B) +class Tuple3[A, B, C](x: A, y: B, z: C) +module Nat +class S(s: Nat) extends Nat +module O extends Nat +class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O) +//│ |#module| |True|↵|#module| |False|↵|#module| |Callable| |{|→|#fun| |apply0|(||)| |#=| |0|↵|#fun| |apply1|(|x0|)| |#=| |0|↵|#fun| |apply2|(|x0|,|x1|)| |#=| |0|↵|#fun| |apply3|(|x0|,|x1|,|x2|)| |#=| |0|↵|#fun| |apply4|(|x0|,|x1|,|x2|,|x3|)| |#=| |0|↵|#fun| |apply5|(|x0|,|x1|,|x2|,|x3|,|x4|)| |#=| |0|←|↵|}|↵|#module| |List|[|A|,| |B|]|↵|#class| |Cons|[|A|,| |B|]|(|h|#:| |A|,| |t|#:| |Cons|[|A|,| |B|]|)| |#extends| |List|[|A|,| |B|]|↵|#module| |Nil|[|A|,| |B|]| |#extends| |List|[|A|,| |B|]|↵|#module| |Option|[|A|]|↵|#class| |Some|[|A|]|(|x|#:| |A|)| |#extends| |Option|[|A|]|↵|#module| |None|[|A|]| |#extends| |Option|[|A|]|↵|#class| |Pair|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple2|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple3|[|A|,| |B|,| |C|]|(|x|#:| |A|,| |y|#:| |B|,| |z|#:| |C|)|↵|#module| |Nat|↵|#class| |S|(|s|#:| |Nat|)| |#extends| |Nat|↵|#module| |O| |#extends| |Nat|↵|#class| |HiddenTheseEntities|(|_0|#:| |HiddenTheseEntities|,| |_1|#:| |True|,| |_2|#:| |False|,| |_3|#:| |Callable|,| |_4|#:| |List|,| |_5|#:| |Cons|,| |_6|#:| |Nil|,| |_7|#:| |Option|,| |_8|#:| |Some|,| |_9|#:| |None|,| |_10|#:| |Pair|,| |_11|#:| |Tuple2|,| |_12|#:| |Tuple3|,| |_13|#:| |Nat|,| |_14|#:| |S|,| |_15|#:| |O|)| +//│ Parsed: {module True {}; module False {}; module Callable {fun apply0 = () => 0; fun apply1 = (x0,) => 0; fun apply2 = (x0, x1,) => 0; fun apply3 = (x0, x1, x2,) => 0; fun apply4 = (x0, x1, x2, x3,) => 0; fun apply5 = (x0, x1, x2, x3, x4,) => 0}; module List‹A, B› {}; class Cons‹A, B›(h: A, t: Cons‹A, B›,): List‹A, B› {}; module Nil‹A, B›: List‹A, B› {}; module Option‹A› {}; class Some‹A›(x: A,): Option‹A› {}; module None‹A›: Option‹A› {}; class Pair‹A, B›(x: A, y: B,) {}; class Tuple2‹A, B›(x: A, y: B,) {}; class Tuple3‹A, B, C›(x: A, y: B, z: C,) {}; module Nat {}; class S(s: Nat,): Nat {}; module O: Nat {}; class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O,) {}} +//│ +//│ Preluded. +//│ + :interpIR class A(x, y, z) class B(m, n) @@ -20,59 +50,54 @@ fun bar() = complex_foo(B(9, 10)) bar() //│ |#class| |A|(|x|,| |y|,| |z|)|↵|#class| |B|(|m|,| |n|)|↵|#fun| |complex_foo|(|t|)| |#=|→|#let| |r| |#=| |#if| |t| |is|→|A|(|x|,| |y|,| |z|)| |#then| |x| |+| |y| |*| |z|↵|B|(|m|,| |n|)| |#then| |m| |-| |n|←|↵|#let| |s| |#=| |B|(|1|,| |2|)|↵|#let| |u| |#=| |#if| |s| |is|→|A|(|x|,| |y|,| |z|)| |#then| |3|↵|B|(|m|,| |n|)| |#then| |4|←|↵|r| |+| |u|←|↵|#fun| |bar|(||)| |#=|→|complex_foo|(|A|(|6|,| |7|,| |8|)|)|↵|complex_foo|(|B|(|9|,| |10|)|)|←|↵|bar|(||)| -//│ Parsed: {class A(x, y, z,) {}; class B(m, n,) {}; fun complex_foo = (t,) => {let r = if t is ‹(A(x, y, z,)) then +(x,)(*(y,)(z,),); (B(m, n,)) then -(m,)(n,)›; let s = B(1, 2,); let u = if s is ‹(A(x, y, z,)) then 3; (B(m, n,)) then 4›; +(r,)(u,)}; fun bar = () => {complex_foo(A(6, 7, 8,),); complex_foo(B(9, 10,),)}; bar()} +//│ Parsed: {class A(x, y, z,) {}; class B(m, n,) {}; fun complex_foo = (t,) => {let r = if t is ‹(A(x, y, z,)) then +(x, *(y, z,),); (B(m, n,)) then -(m, n,)›; let s = B(1, 2,); let u = if s is ‹(A(x, y, z,)) then 3; (B(m, n,)) then 4›; +(r, u,)}; fun bar = () => {complex_foo(A(6, 7, 8,),); complex_foo(B(9, 10,),)}; bar()} //│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, A, [x,y,z]),ClassInfo(3, B, [m,n])}, { -//│ Def(0, complex_foo, [t$0], -//│ 1, -//│ case t$0 of -- #63 -//│ A => -//│ let x$9 = t$0.z in -- #51 -//│ let x$10 = t$0.y in -- #50 -//│ let x$11 = t$0.x in -- #49 -//│ let x$12 = *(x$10,x$9) in -- #48 -//│ let x$13 = +(x$11,x$12) in -- #47 -//│ jump j$0(x$13) -- #46 -//│ B => -//│ let x$14 = t$0.n in -- #62 -//│ let x$15 = t$0.m in -- #61 -//│ let x$16 = -(x$15,x$14) in -- #60 -//│ jump j$0(x$16) -- #59 -//│ ) -//│ Def(1, j$1, [x$2,x$0], -//│ 1, -//│ let x$3 = +(x$0,x$2) in -- #13 -//│ x$3 -- #12 -//│ ) -//│ Def(2, j$0, [x$0], -//│ 1, -//│ let x$1 = B(1,2) in -- #34 -//│ case x$1 of -- #33 -//│ A => -//│ let x$4 = x$1.z in -- #24 -//│ let x$5 = x$1.y in -- #23 -//│ let x$6 = x$1.x in -- #22 -//│ jump j$1(3,x$0) -- #21 -//│ B => -//│ let x$7 = x$1.n in -- #32 -//│ let x$8 = x$1.m in -- #31 -//│ jump j$1(4,x$0) -- #30 -//│ ) -//│ Def(3, bar, [], -//│ 1, -//│ let x$17 = A(6,7,8) in -- #89 -//│ let* (x$18) = complex_foo(x$17) in -- #88 -//│ let x$19 = B(9,10) in -- #87 -//│ let* (x$20) = complex_foo(x$19) in -- #86 -//│ x$20 -- #85 -//│ ) -//│ }, -//│ let* (x$21) = bar() in -- #93 -//│ x$21 -- #92) +//│ +//│ IR: +//│ Program: +//│ class A(x,y,z) +//│ class B(m,n) +//│ def complex_foo(t$0) = +//│ case t$0 of -- #98 +//│ A => +//│ let x$10 = A.z(t$0) in -- #79 +//│ let x$11 = A.y(t$0) in -- #78 +//│ let x$12 = A.x(t$0) in -- #77 +//│ let x$13 = *(x$11,x$10) in -- #76 +//│ let x$14 = +(x$12,x$13) in -- #75 +//│ jump j$0(x$14) -- #74 +//│ B => +//│ let x$15 = B.n(t$0) in -- #97 +//│ let x$16 = B.m(t$0) in -- #96 +//│ let x$17 = -(x$16,x$15) in -- #95 +//│ jump j$0(x$17) -- #94 +//│ def j$1(x$3,x$1) = +//│ let x$4 = +(x$1,x$3) in -- #19 +//│ x$4 -- #18 +//│ def j$0(x$1) = +//│ let x$2 = B(1,2) in -- #50 +//│ case x$2 of -- #49 +//│ A => +//│ let x$5 = A.z(x$2) in -- #36 +//│ let x$6 = A.y(x$2) in -- #35 +//│ let x$7 = A.x(x$2) in -- #34 +//│ jump j$1(3,x$1) -- #33 +//│ B => +//│ let x$8 = B.n(x$2) in -- #48 +//│ let x$9 = B.m(x$2) in -- #47 +//│ jump j$1(4,x$1) -- #46 +//│ def bar() = +//│ let x$18 = A(6,7,8) in -- #122 +//│ let* (x$19) = complex_foo(x$18) in -- #121 +//│ let x$20 = B(9,10) in -- #120 +//│ let* (x$21) = complex_foo(x$20) in -- #119 +//│ x$21 -- #118 +//│ let* (x$0) = bar() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ 3 +//│ :interpIR class A(w, x) @@ -108,107 +133,97 @@ fun bar() = complex_foo(A(10, A(9, B(10)))) bar() //│ |#class| |A|(|w|,| |x|)|↵|#class| |B|(|y|)|↵|#class| |C|(|z|)|↵|#fun| |complex_foo|(|t|)| |#=|→|#let| |a| |#=| |1| |+| |2|↵|#let| |b| |#=| |1| |*| |2|↵|#let| |x| |#=| |#if| |t| |is|→|A|(|x|,| |y|)| |#then| |y|↵|B|(|x|)| |#then| |B|(|x| |+| |b|)|↵|C|(|x|)| |#then| |C|(|0|)|←|↵|#let| |z| |#=| |A|(|5|,| |x|)|↵|#let| |v| |#=| |B|(|6|)|↵|#let| |y| |#=| |#if| |x| |is|→|A|(|x|,| |y|)| |#then|→|#let| |m| |#=| |x| |+| |a| |+| |b|↵|#if| |y| |is|→|A|(|x|,| |y|)| |#then| |x|↵|B|(|x|)| |#then| |m|↵|C|(|x|)| |#then| |0|←|←|↵|B|(|x|)| |#then| |2|↵|C|(|x|)| |#then| |3|←|↵|#if| |z| |is|→|A|(|x|,| |y|)| |#then| |x|↵|B|(|x|)| |#then| |4|↵|C|(|x|)| |#then|→|#if| |v| |is|→|A|(|x|,| |y|)| |#then| |x|↵|B|(|x|)| |#then| |7|↵|C|(|x|)| |#then| |8|←|←|←|←|↵|#fun| |bar|(||)| |#=|→|complex_foo|(|A|(|10|,| |A|(|9|,| |B|(|10|)|)|)|)|←|↵|bar|(||)| -//│ Parsed: {class A(w, x,) {}; class B(y,) {}; class C(z,) {}; fun complex_foo = (t,) => {let a = +(1,)(2,); let b = *(1,)(2,); let x = if t is ‹(A(x, y,)) then y; (B(x,)) then B(+(x,)(b,),); (C(x,)) then C(0,)›; let z = A(5, x,); let v = B(6,); let y = if x is ‹(A(x, y,)) then {let m = +(+(x,)(a,),)(b,); if y is ‹(A(x, y,)) then x; (B(x,)) then m; (C(x,)) then 0›}; (B(x,)) then 2; (C(x,)) then 3›; if z is ‹(A(x, y,)) then x; (B(x,)) then 4; (C(x,)) then {if v is ‹(A(x, y,)) then x; (B(x,)) then 7; (C(x,)) then 8›}›}; fun bar = () => {complex_foo(A(10, A(9, B(10,),),),)}; bar()} +//│ Parsed: {class A(w, x,) {}; class B(y,) {}; class C(z,) {}; fun complex_foo = (t,) => {let a = +(1, 2,); let b = *(1, 2,); let x = if t is ‹(A(x, y,)) then y; (B(x,)) then B(+(x, b,),); (C(x,)) then C(0,)›; let z = A(5, x,); let v = B(6,); let y = if x is ‹(A(x, y,)) then {let m = +(+(x, a,), b,); if y is ‹(A(x, y,)) then x; (B(x,)) then m; (C(x,)) then 0›}; (B(x,)) then 2; (C(x,)) then 3›; if z is ‹(A(x, y,)) then x; (B(x,)) then 4; (C(x,)) then {if v is ‹(A(x, y,)) then x; (B(x,)) then 7; (C(x,)) then 8›}›}; fun bar = () => {complex_foo(A(10, A(9, B(10,),),),)}; bar()} +//│ //│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, A, [w,x]),ClassInfo(3, B, [y]),ClassInfo(4, C, [z])}, { -//│ Def(0, complex_foo, [t$0], -//│ 1, -//│ let x$0 = +(1,2) in -- #140 -//│ let x$1 = *(1,2) in -- #139 -//│ case t$0 of -- #138 -//│ A => -//│ let x$27 = t$0.x in -- #116 -//│ let x$28 = t$0.w in -- #115 -//│ jump j$0(x$27,x$0,x$1) -- #114 -//│ B => -//│ let x$29 = t$0.y in -- #128 -//│ let x$30 = +(x$29,x$1) in -- #127 -//│ let x$31 = B(x$30) in -- #126 -//│ jump j$0(x$31,x$0,x$1) -- #125 -//│ C => -//│ let x$32 = t$0.z in -- #137 -//│ let x$33 = C(0) in -- #136 -//│ jump j$0(x$33,x$0,x$1) -- #135 -//│ ) -//│ Def(1, j$2, [x$6], -//│ 1, -//│ x$6 -- #21 -//│ ) -//│ Def(2, j$3, [x$11], -//│ 1, -//│ jump j$2(x$11) -- #39 -//│ ) -//│ Def(3, j$1, [x$5,x$3,x$4], -//│ 1, -//│ case x$3 of -- #60 -//│ A => -//│ let x$7 = x$3.x in -- #29 -//│ let x$8 = x$3.w in -- #28 -//│ jump j$2(x$8) -- #27 -//│ B => -//│ let x$9 = x$3.y in -- #34 -//│ jump j$2(4) -- #33 -//│ C => -//│ let x$10 = x$3.z in -- #59 -//│ case x$4 of -- #58 +//│ IR: +//│ Program: +//│ class A(w,x) +//│ class B(y) +//│ class C(z) +//│ def complex_foo(t$0) = +//│ let x$1 = +(1,2) in -- #198 +//│ let x$2 = *(1,2) in -- #197 +//│ case t$0 of -- #196 //│ A => -//│ let x$12 = x$4.x in -- #47 -//│ let x$13 = x$4.w in -- #46 -//│ jump j$3(x$13) -- #45 +//│ let x$28 = A.x(t$0) in -- #167 +//│ let x$29 = A.w(t$0) in -- #166 +//│ jump j$0(x$28,x$1,x$2) -- #165 //│ B => -//│ let x$14 = x$4.y in -- #52 -//│ jump j$3(7) -- #51 +//│ let x$30 = B.y(t$0) in -- #184 +//│ let x$31 = +(x$30,x$2) in -- #183 +//│ let x$32 = B(x$31) in -- #182 +//│ jump j$0(x$32,x$1,x$2) -- #181 //│ C => -//│ let x$15 = x$4.z in -- #57 -//│ jump j$3(8) -- #56 -//│ ) -//│ Def(4, j$4, [x$20,x$3,x$4], -//│ 1, -//│ jump j$1(x$20,x$3,x$4) -- #72 -//│ ) -//│ Def(5, j$0, [x$2,x$0,x$1], -//│ 1, -//│ let x$3 = A(5,x$2) in -- #108 -//│ let x$4 = B(6) in -- #107 -//│ case x$2 of -- #106 -//│ A => -//│ let x$16 = x$2.x in -- #95 -//│ let x$17 = x$2.w in -- #94 -//│ let x$18 = +(x$17,x$0) in -- #93 -//│ let x$19 = +(x$18,x$1) in -- #92 -//│ case x$16 of -- #91 +//│ let x$33 = C.z(t$0) in -- #195 +//│ let x$34 = C(0) in -- #194 +//│ jump j$0(x$34,x$1,x$2) -- #193 +//│ def j$2(x$7) = +//│ x$7 -- #30 +//│ def j$3(x$12) = +//│ jump j$2(x$12) -- #56 +//│ def j$1(x$6,x$4,x$5) = +//│ case x$4 of -- #85 //│ A => -//│ let x$21 = x$16.x in -- #80 -//│ let x$22 = x$16.w in -- #79 -//│ jump j$4(x$22,x$3,x$4) -- #78 +//│ let x$8 = A.x(x$4) in -- #42 +//│ let x$9 = A.w(x$4) in -- #41 +//│ jump j$2(x$9) -- #40 //│ B => -//│ let x$23 = x$16.y in -- #85 -//│ jump j$4(x$19,x$3,x$4) -- #84 +//│ let x$10 = B.y(x$4) in -- #49 +//│ jump j$2(4) -- #48 //│ C => -//│ let x$24 = x$16.z in -- #90 -//│ jump j$4(0,x$3,x$4) -- #89 -//│ B => -//│ let x$25 = x$2.y in -- #100 -//│ jump j$1(2,x$3,x$4) -- #99 -//│ C => -//│ let x$26 = x$2.z in -- #105 -//│ jump j$1(3,x$3,x$4) -- #104 -//│ ) -//│ Def(6, bar, [], -//│ 1, -//│ let x$34 = B(10) in -- #162 -//│ let x$35 = A(9,x$34) in -- #161 -//│ let x$36 = A(10,x$35) in -- #160 -//│ let* (x$37) = complex_foo(x$36) in -- #159 -//│ x$37 -- #158 -//│ ) -//│ }, -//│ let* (x$38) = bar() in -- #166 -//│ x$38 -- #165) +//│ let x$11 = C.z(x$4) in -- #84 +//│ case x$5 of -- #83 +//│ A => +//│ let x$13 = A.x(x$5) in -- #68 +//│ let x$14 = A.w(x$5) in -- #67 +//│ jump j$3(x$14) -- #66 +//│ B => +//│ let x$15 = B.y(x$5) in -- #75 +//│ jump j$3(7) -- #74 +//│ C => +//│ let x$16 = C.z(x$5) in -- #82 +//│ jump j$3(8) -- #81 +//│ def j$4(x$21,x$4,x$5) = +//│ jump j$1(x$21,x$4,x$5) -- #107 +//│ def j$0(x$3,x$1,x$2) = +//│ let x$4 = A(5,x$3) in -- #155 +//│ let x$5 = B(6) in -- #154 +//│ case x$3 of -- #153 +//│ A => +//│ let x$17 = A.x(x$3) in -- #138 +//│ let x$18 = A.w(x$3) in -- #137 +//│ let x$19 = +(x$18,x$1) in -- #136 +//│ let x$20 = +(x$19,x$2) in -- #135 +//│ case x$17 of -- #134 +//│ A => +//│ let x$22 = A.x(x$17) in -- #119 +//│ let x$23 = A.w(x$17) in -- #118 +//│ jump j$4(x$23,x$4,x$5) -- #117 +//│ B => +//│ let x$24 = B.y(x$17) in -- #126 +//│ jump j$4(x$20,x$4,x$5) -- #125 +//│ C => +//│ let x$25 = C.z(x$17) in -- #133 +//│ jump j$4(0,x$4,x$5) -- #132 +//│ B => +//│ let x$26 = B.y(x$3) in -- #145 +//│ jump j$1(2,x$4,x$5) -- #144 +//│ C => +//│ let x$27 = C.z(x$3) in -- #152 +//│ jump j$1(3,x$4,x$5) -- #151 +//│ def bar() = +//│ let x$35 = B(10) in -- #219 +//│ let x$36 = A(9,x$35) in -- #218 +//│ let x$37 = A(10,x$36) in -- #217 +//│ let* (x$38) = complex_foo(x$37) in -- #216 +//│ x$38 -- #215 +//│ let* (x$0) = bar() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ 5 +//│ :interpIR class A(w, x) @@ -244,106 +259,96 @@ fun bar() = complex_foo(A(10, A(9, B(10)))) bar() //│ |#class| |A|(|w|,| |x|)|↵|#class| |B|(|y|)|↵|#class| |C|(|z|)|↵|#fun| |complex_foo|(|t|)| |#=|→|#let| |a| |#=| |1| |+| |2|↵|#let| |b| |#=| |1| |*| |2|↵|#let| |x| |#=| |#if| |t| |is|→|A|(|x|,| |y|)| |#then| |A|(|x|,| |C|(|0|)|)|↵|B|(|x|)| |#then| |B|(|x| |+| |b|)|↵|C|(|x|)| |#then| |C|(|0|)|←|↵|#let| |z| |#=| |A|(|5|,| |x|)|↵|#let| |v| |#=| |B|(|6|)|↵|#let| |y| |#=| |#if| |x| |is|→|A|(|x|,| |y|)| |#then|→|#let| |m| |#=| |x| |+| |a| |+| |b|↵|#if| |y| |is|→|A|(|x|,| |y|)| |#then| |x|↵|B|(|x|)| |#then| |m|↵|C|(|x|)| |#then| |0|←|←|↵|B|(|x|)| |#then| |2|↵|C|(|x|)| |#then| |3|←|↵|#if| |z| |is|→|A|(|x|,| |y|)| |#then| |x|↵|B|(|x|)| |#then| |4|↵|C|(|x|)| |#then|→|#if| |v| |is|→|A|(|x|,| |y|)| |#then| |x|↵|B|(|x|)| |#then| |7|↵|C|(|x|)| |#then| |8|←|←|←|←|↵|#fun| |bar|(||)| |#=|→|complex_foo|(|A|(|10|,| |A|(|9|,| |B|(|10|)|)|)|)|←|↵|bar|(||)| -//│ Parsed: {class A(w, x,) {}; class B(y,) {}; class C(z,) {}; fun complex_foo = (t,) => {let a = +(1,)(2,); let b = *(1,)(2,); let x = if t is ‹(A(x, y,)) then A(x, C(0,),); (B(x,)) then B(+(x,)(b,),); (C(x,)) then C(0,)›; let z = A(5, x,); let v = B(6,); let y = if x is ‹(A(x, y,)) then {let m = +(+(x,)(a,),)(b,); if y is ‹(A(x, y,)) then x; (B(x,)) then m; (C(x,)) then 0›}; (B(x,)) then 2; (C(x,)) then 3›; if z is ‹(A(x, y,)) then x; (B(x,)) then 4; (C(x,)) then {if v is ‹(A(x, y,)) then x; (B(x,)) then 7; (C(x,)) then 8›}›}; fun bar = () => {complex_foo(A(10, A(9, B(10,),),),)}; bar()} +//│ Parsed: {class A(w, x,) {}; class B(y,) {}; class C(z,) {}; fun complex_foo = (t,) => {let a = +(1, 2,); let b = *(1, 2,); let x = if t is ‹(A(x, y,)) then A(x, C(0,),); (B(x,)) then B(+(x, b,),); (C(x,)) then C(0,)›; let z = A(5, x,); let v = B(6,); let y = if x is ‹(A(x, y,)) then {let m = +(+(x, a,), b,); if y is ‹(A(x, y,)) then x; (B(x,)) then m; (C(x,)) then 0›}; (B(x,)) then 2; (C(x,)) then 3›; if z is ‹(A(x, y,)) then x; (B(x,)) then 4; (C(x,)) then {if v is ‹(A(x, y,)) then x; (B(x,)) then 7; (C(x,)) then 8›}›}; fun bar = () => {complex_foo(A(10, A(9, B(10,),),),)}; bar()} +//│ //│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, A, [w,x]),ClassInfo(3, B, [y]),ClassInfo(4, C, [z])}, { -//│ Def(0, complex_foo, [t$0], -//│ 1, -//│ let x$0 = +(1,2) in -- #150 -//│ let x$1 = *(1,2) in -- #149 -//│ case t$0 of -- #148 -//│ A => -//│ let x$27 = t$0.x in -- #126 -//│ let x$28 = t$0.w in -- #125 -//│ let x$29 = C(0) in -- #124 -//│ let x$30 = A(x$28,x$29) in -- #123 -//│ jump j$0(x$30,x$0,x$1) -- #122 -//│ B => -//│ let x$31 = t$0.y in -- #138 -//│ let x$32 = +(x$31,x$1) in -- #137 -//│ let x$33 = B(x$32) in -- #136 -//│ jump j$0(x$33,x$0,x$1) -- #135 -//│ C => -//│ let x$34 = t$0.z in -- #147 -//│ let x$35 = C(0) in -- #146 -//│ jump j$0(x$35,x$0,x$1) -- #145 -//│ ) -//│ Def(1, j$2, [x$6], -//│ 1, -//│ x$6 -- #21 -//│ ) -//│ Def(2, j$3, [x$11], -//│ 1, -//│ jump j$2(x$11) -- #39 -//│ ) -//│ Def(3, j$1, [x$5,x$3,x$4], -//│ 1, -//│ case x$3 of -- #60 -//│ A => -//│ let x$7 = x$3.x in -- #29 -//│ let x$8 = x$3.w in -- #28 -//│ jump j$2(x$8) -- #27 -//│ B => -//│ let x$9 = x$3.y in -- #34 -//│ jump j$2(4) -- #33 -//│ C => -//│ let x$10 = x$3.z in -- #59 -//│ case x$4 of -- #58 +//│ IR: +//│ Program: +//│ class A(w,x) +//│ class B(y) +//│ class C(z) +//│ def complex_foo(t$0) = +//│ let x$1 = +(1,2) in -- #208 +//│ let x$2 = *(1,2) in -- #207 +//│ case t$0 of -- #206 //│ A => -//│ let x$12 = x$4.x in -- #47 -//│ let x$13 = x$4.w in -- #46 -//│ jump j$3(x$13) -- #45 +//│ let x$28 = A.x(t$0) in -- #177 +//│ let x$29 = A.w(t$0) in -- #176 +//│ let x$30 = C(0) in -- #175 +//│ let x$31 = A(x$29,x$30) in -- #174 +//│ jump j$0(x$31,x$1,x$2) -- #173 //│ B => -//│ let x$14 = x$4.y in -- #52 -//│ jump j$3(7) -- #51 +//│ let x$32 = B.y(t$0) in -- #194 +//│ let x$33 = +(x$32,x$2) in -- #193 +//│ let x$34 = B(x$33) in -- #192 +//│ jump j$0(x$34,x$1,x$2) -- #191 //│ C => -//│ let x$15 = x$4.z in -- #57 -//│ jump j$3(8) -- #56 -//│ ) -//│ Def(4, j$4, [x$20,x$3,x$4], -//│ 1, -//│ jump j$1(x$20,x$3,x$4) -- #72 -//│ ) -//│ Def(5, j$0, [x$2,x$0,x$1], -//│ 1, -//│ let x$3 = A(5,x$2) in -- #108 -//│ let x$4 = B(6) in -- #107 -//│ case x$2 of -- #106 -//│ A => -//│ let x$16 = x$2.x in -- #95 -//│ let x$17 = x$2.w in -- #94 -//│ let x$18 = +(x$17,x$0) in -- #93 -//│ let x$19 = +(x$18,x$1) in -- #92 -//│ case x$16 of -- #91 +//│ let x$35 = C.z(t$0) in -- #205 +//│ let x$36 = C(0) in -- #204 +//│ jump j$0(x$36,x$1,x$2) -- #203 +//│ def j$2(x$7) = +//│ x$7 -- #30 +//│ def j$3(x$12) = +//│ jump j$2(x$12) -- #56 +//│ def j$1(x$6,x$4,x$5) = +//│ case x$4 of -- #85 //│ A => -//│ let x$21 = x$16.x in -- #80 -//│ let x$22 = x$16.w in -- #79 -//│ jump j$4(x$22,x$3,x$4) -- #78 +//│ let x$8 = A.x(x$4) in -- #42 +//│ let x$9 = A.w(x$4) in -- #41 +//│ jump j$2(x$9) -- #40 //│ B => -//│ let x$23 = x$16.y in -- #85 -//│ jump j$4(x$19,x$3,x$4) -- #84 +//│ let x$10 = B.y(x$4) in -- #49 +//│ jump j$2(4) -- #48 //│ C => -//│ let x$24 = x$16.z in -- #90 -//│ jump j$4(0,x$3,x$4) -- #89 -//│ B => -//│ let x$25 = x$2.y in -- #100 -//│ jump j$1(2,x$3,x$4) -- #99 -//│ C => -//│ let x$26 = x$2.z in -- #105 -//│ jump j$1(3,x$3,x$4) -- #104 -//│ ) -//│ Def(6, bar, [], -//│ 1, -//│ let x$36 = B(10) in -- #172 -//│ let x$37 = A(9,x$36) in -- #171 -//│ let x$38 = A(10,x$37) in -- #170 -//│ let* (x$39) = complex_foo(x$38) in -- #169 -//│ x$39 -- #168 -//│ ) -//│ }, -//│ let* (x$40) = bar() in -- #176 -//│ x$40 -- #175) +//│ let x$11 = C.z(x$4) in -- #84 +//│ case x$5 of -- #83 +//│ A => +//│ let x$13 = A.x(x$5) in -- #68 +//│ let x$14 = A.w(x$5) in -- #67 +//│ jump j$3(x$14) -- #66 +//│ B => +//│ let x$15 = B.y(x$5) in -- #75 +//│ jump j$3(7) -- #74 +//│ C => +//│ let x$16 = C.z(x$5) in -- #82 +//│ jump j$3(8) -- #81 +//│ def j$4(x$21,x$4,x$5) = +//│ jump j$1(x$21,x$4,x$5) -- #107 +//│ def j$0(x$3,x$1,x$2) = +//│ let x$4 = A(5,x$3) in -- #155 +//│ let x$5 = B(6) in -- #154 +//│ case x$3 of -- #153 +//│ A => +//│ let x$17 = A.x(x$3) in -- #138 +//│ let x$18 = A.w(x$3) in -- #137 +//│ let x$19 = +(x$18,x$1) in -- #136 +//│ let x$20 = +(x$19,x$2) in -- #135 +//│ case x$17 of -- #134 +//│ A => +//│ let x$22 = A.x(x$17) in -- #119 +//│ let x$23 = A.w(x$17) in -- #118 +//│ jump j$4(x$23,x$4,x$5) -- #117 +//│ B => +//│ let x$24 = B.y(x$17) in -- #126 +//│ jump j$4(x$20,x$4,x$5) -- #125 +//│ C => +//│ let x$25 = C.z(x$17) in -- #133 +//│ jump j$4(0,x$4,x$5) -- #132 +//│ B => +//│ let x$26 = B.y(x$3) in -- #145 +//│ jump j$1(2,x$4,x$5) -- #144 +//│ C => +//│ let x$27 = C.z(x$3) in -- #152 +//│ jump j$1(3,x$4,x$5) -- #151 +//│ def bar() = +//│ let x$37 = B(10) in -- #229 +//│ let x$38 = A(9,x$37) in -- #228 +//│ let x$39 = A(10,x$38) in -- #227 +//│ let* (x$40) = complex_foo(x$39) in -- #226 +//│ x$40 -- #225 +//│ let* (x$0) = bar() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ 5 +//│ diff --git a/compiler/shared/test/diff-ir/IRRec.mls b/compiler/shared/test/diff-ir/IRRec.mls index a56f53a9e7..45aaa77e0d 100644 --- a/compiler/shared/test/diff-ir/IRRec.mls +++ b/compiler/shared/test/diff-ir/IRRec.mls @@ -1,164 +1,168 @@ -:NewParser +:NewDefs :ParseOnly :UseIR :NoTailRec +:prelude +module True +module False +module Callable { + fun apply0() = 0 + fun apply1(x0) = 0 + fun apply2(x0,x1) = 0 + fun apply3(x0,x1,x2) = 0 + fun apply4(x0,x1,x2,x3) = 0 + fun apply5(x0,x1,x2,x3,x4) = 0 +} +module List[A, B] +class Cons[A, B](h: A, t: Cons[A, B]) extends List[A, B] +module Nil[A, B] extends List[A, B] +module Option[A] +class Some[A](x: A) extends Option[A] +module None[A] extends Option[A] +class Pair[A, B](x: A, y: B) +class Tuple2[A, B](x: A, y: B) +class Tuple3[A, B, C](x: A, y: B, z: C) +module Nat +class S(s: Nat) extends Nat +module O extends Nat +class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O) +//│ |#module| |True|↵|#module| |False|↵|#module| |Callable| |{|→|#fun| |apply0|(||)| |#=| |0|↵|#fun| |apply1|(|x0|)| |#=| |0|↵|#fun| |apply2|(|x0|,|x1|)| |#=| |0|↵|#fun| |apply3|(|x0|,|x1|,|x2|)| |#=| |0|↵|#fun| |apply4|(|x0|,|x1|,|x2|,|x3|)| |#=| |0|↵|#fun| |apply5|(|x0|,|x1|,|x2|,|x3|,|x4|)| |#=| |0|←|↵|}|↵|#module| |List|[|A|,| |B|]|↵|#class| |Cons|[|A|,| |B|]|(|h|#:| |A|,| |t|#:| |Cons|[|A|,| |B|]|)| |#extends| |List|[|A|,| |B|]|↵|#module| |Nil|[|A|,| |B|]| |#extends| |List|[|A|,| |B|]|↵|#module| |Option|[|A|]|↵|#class| |Some|[|A|]|(|x|#:| |A|)| |#extends| |Option|[|A|]|↵|#module| |None|[|A|]| |#extends| |Option|[|A|]|↵|#class| |Pair|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple2|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple3|[|A|,| |B|,| |C|]|(|x|#:| |A|,| |y|#:| |B|,| |z|#:| |C|)|↵|#module| |Nat|↵|#class| |S|(|s|#:| |Nat|)| |#extends| |Nat|↵|#module| |O| |#extends| |Nat|↵|#class| |HiddenTheseEntities|(|_0|#:| |HiddenTheseEntities|,| |_1|#:| |True|,| |_2|#:| |False|,| |_3|#:| |Callable|,| |_4|#:| |List|,| |_5|#:| |Cons|,| |_6|#:| |Nil|,| |_7|#:| |Option|,| |_8|#:| |Some|,| |_9|#:| |None|,| |_10|#:| |Pair|,| |_11|#:| |Tuple2|,| |_12|#:| |Tuple3|,| |_13|#:| |Nat|,| |_14|#:| |S|,| |_15|#:| |O|)| +//│ Parsed: {module True {}; module False {}; module Callable {fun apply0 = () => 0; fun apply1 = (x0,) => 0; fun apply2 = (x0, x1,) => 0; fun apply3 = (x0, x1, x2,) => 0; fun apply4 = (x0, x1, x2, x3,) => 0; fun apply5 = (x0, x1, x2, x3, x4,) => 0}; module List‹A, B› {}; class Cons‹A, B›(h: A, t: Cons‹A, B›,): List‹A, B› {}; module Nil‹A, B›: List‹A, B› {}; module Option‹A› {}; class Some‹A›(x: A,): Option‹A› {}; module None‹A›: Option‹A› {}; class Pair‹A, B›(x: A, y: B,) {}; class Tuple2‹A, B›(x: A, y: B,) {}; class Tuple3‹A, B, C›(x: A, y: B, z: C,) {}; module Nat {}; class S(s: Nat,): Nat {}; module O: Nat {}; class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O,) {}} +//│ +//│ Preluded. +//│ + :interpIR -class True -class False +:genCpp fun fib(n) = if n < 2 then n else fib(n-1) + fib(n-2) fib(20) -//│ |#class| |True|↵|#class| |False|↵|#fun| |fib|(|n|)| |#=| |#if| |n| |<| |2| |#then| |n| |#else| |fib|(|n|-|1|)| |+| |fib|(|n|-|2|)|↵|fib|(|20|)| -//│ Parsed: {class True {}; class False {}; fun fib = (n,) => if (<(n,)(2,)) then n else +(fib(-(n,)(1,),),)(fib(-(n,)(2,),),); fib(20,)} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, True, []),ClassInfo(3, False, [])}, { -//│ Def(0, fib, [n$0], -//│ 1, -//│ let x$0 = <(n$0,2) in -- #28 -//│ if x$0 -- #27 -//│ true => -//│ jump j$0(n$0) -- #5 -//│ false => -//│ let x$2 = -(n$0,1) in -- #26 -//│ let* (x$3) = fib(x$2) in -- #25 -//│ let x$4 = -(n$0,2) in -- #24 -//│ let* (x$5) = fib(x$4) in -- #23 -//│ let x$6 = +(x$3,x$5) in -- #22 -//│ jump j$0(x$6) -- #21 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #3 -//│ ) -//│ }, -//│ let* (x$7) = fib(20) in -- #34 -//│ x$7 -- #33) +//│ |#fun| |fib|(|n|)| |#=| |#if| |n| |<| |2| |#then| |n| |#else| |fib|(|n|-|1|)| |+| |fib|(|n|-|2|)|↵|fib|(|20|)| +//│ Parsed: {fun fib = (n,) => if (<(n, 2,)) then n else +(fib(-(n, 1,),), fib(-(n, 2,),),); fib(20,)} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def fib(n$0) = +//│ let x$1 = <(n$0,2) in -- #43 +//│ if x$1 -- #42 +//│ true => +//│ jump j$0(n$0) -- #13 +//│ false => +//│ let x$3 = -(n$0,1) in -- #41 +//│ let* (x$4) = fib(x$3) in -- #40 +//│ let x$5 = -(n$0,2) in -- #39 +//│ let* (x$6) = fib(x$5) in -- #38 +//│ let x$7 = +(x$4,x$6) in -- #37 +//│ jump j$0(x$7) -- #36 +//│ def j$0(x$2) = +//│ x$2 -- #11 +//│ let* (x$0) = fib(20) in -- #4 +//│ x$0 -- #3 //│ //│ Interpreted: //│ 6765 +//│ :interpIR -class True -class False +:genCpp fun odd(x) = if x == 0 then False else even(x-1) fun even(x) = if x == 0 then True else odd(x-1) fun foo() = odd(10) foo() -//│ |#class| |True|↵|#class| |False|↵|#fun| |odd|(|x|)| |#=| |#if| |x| |==| |0| |#then| |False| |#else| |even|(|x|-|1|)|↵|#fun| |even|(|x|)| |#=| |#if| |x| |==| |0| |#then| |True| |#else| |odd|(|x|-|1|)|↵|#fun| |foo|(||)| |#=| |odd|(|10|)|↵|foo|(||)| -//│ Parsed: {class True {}; class False {}; fun odd = (x,) => if (==(x,)(0,)) then False else even(-(x,)(1,),); fun even = (x,) => if (==(x,)(0,)) then True else odd(-(x,)(1,),); fun foo = () => odd(10,); foo()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, True, []),ClassInfo(3, False, [])}, { -//│ Def(0, odd, [x$0], -//│ 1, -//│ let x$1 = ==(x$0,0) in -- #18 -//│ if x$1 -- #17 -//│ true => -//│ let x$3 = False() in -- #6 -//│ jump j$0(x$3) -- #5 -//│ false => -//│ let x$4 = -(x$0,1) in -- #16 -//│ let* (x$5) = even(x$4) in -- #15 -//│ jump j$0(x$5) -- #14 -//│ ) -//│ Def(1, j$0, [x$2], -//│ 1, -//│ x$2 -- #3 -//│ ) -//│ Def(2, even, [x$6], -//│ 1, -//│ let x$7 = ==(x$6,0) in -- #37 -//│ if x$7 -- #36 -//│ true => -//│ let x$9 = True() in -- #25 -//│ jump j$1(x$9) -- #24 -//│ false => -//│ let x$10 = -(x$6,1) in -- #35 -//│ let* (x$11) = odd(x$10) in -- #34 -//│ jump j$1(x$11) -- #33 -//│ ) -//│ Def(3, j$1, [x$8], -//│ 1, -//│ x$8 -- #22 -//│ ) -//│ Def(4, foo, [], -//│ 1, -//│ let* (x$12) = odd(10) in -- #43 -//│ x$12 -- #42 -//│ ) -//│ }, -//│ let* (x$13) = foo() in -- #47 -//│ x$13 -- #46) +//│ |#fun| |odd|(|x|)| |#=| |#if| |x| |==| |0| |#then| |False| |#else| |even|(|x|-|1|)|↵|#fun| |even|(|x|)| |#=| |#if| |x| |==| |0| |#then| |True| |#else| |odd|(|x|-|1|)|↵|#fun| |foo|(||)| |#=| |odd|(|10|)|↵|foo|(||)| +//│ Parsed: {fun odd = (x,) => if (==(x, 0,)) then False else even(-(x, 1,),); fun even = (x,) => if (==(x, 0,)) then True else odd(-(x, 1,),); fun foo = () => odd(10,); foo()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def odd(x$1) = +//│ let x$2 = ==(x$1,0) in -- #26 +//│ if x$2 -- #25 +//│ true => +//│ let x$4 = False() in -- #12 +//│ jump j$0(x$4) -- #11 +//│ false => +//│ let x$5 = -(x$1,1) in -- #24 +//│ let* (x$6) = even(x$5) in -- #23 +//│ jump j$0(x$6) -- #22 +//│ def j$0(x$3) = +//│ x$3 -- #9 +//│ def even(x$7) = +//│ let x$8 = ==(x$7,0) in -- #50 +//│ if x$8 -- #49 +//│ true => +//│ let x$10 = True() in -- #36 +//│ jump j$1(x$10) -- #35 +//│ false => +//│ let x$11 = -(x$7,1) in -- #48 +//│ let* (x$12) = odd(x$11) in -- #47 +//│ jump j$1(x$12) -- #46 +//│ def j$1(x$9) = +//│ x$9 -- #33 +//│ def foo() = +//│ let* (x$13) = odd(10) in -- #55 +//│ x$13 -- #54 +//│ let* (x$0) = foo() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ False() +//│ :interpIR -class True -class False -class A -class B(b) +:genCpp fun not(x) = if x then False else True fun foo(x) = - if x then A - else B(foo(not(x))) + if x then None + else Some(foo(not(x))) fun main() = foo(False) main() -//│ |#class| |True|↵|#class| |False|↵|#class| |A|↵|#class| |B|(|b|)|↵|#fun| |not|(|x|)| |#=|→|#if| |x| |#then| |False| |#else| |True|←|↵|#fun| |foo|(|x|)| |#=|→|#if| |x| |#then| |A|→|#else| |B|(|foo|(|not|(|x|)|)|)|←|←|↵|#fun| |main|(||)| |#=| |foo|(|False|)|↵|main|(||)| -//│ Parsed: {class True {}; class False {}; class A {}; class B(b,) {}; fun not = (x,) => {if (x) then False else True}; fun foo = (x,) => {if (x) then A else B(foo(not(x,),),)}; fun main = () => foo(False,); main()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, True, []),ClassInfo(3, False, []),ClassInfo(4, A, []),ClassInfo(5, B, [b])}, { -//│ Def(0, not, [x$0], -//│ 1, -//│ if x$0 -- #8 -//│ true => -//│ let x$2 = False() in -- #4 -//│ jump j$0(x$2) -- #3 -//│ false => -//│ let x$3 = True() in -- #7 -//│ jump j$0(x$3) -- #6 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #1 -//│ ) -//│ Def(2, foo, [x$4], -//│ 1, -//│ if x$4 -- #30 -//│ true => -//│ let x$6 = A() in -- #13 -//│ jump j$1(x$6) -- #12 -//│ false => -//│ let* (x$7) = not(x$4) in -- #29 -//│ let* (x$8) = foo(x$7) in -- #28 -//│ let x$9 = B(x$8) in -- #27 -//│ jump j$1(x$9) -- #26 -//│ ) -//│ Def(3, j$1, [x$5], -//│ 1, -//│ x$5 -- #10 -//│ ) -//│ Def(4, main, [], -//│ 1, -//│ let x$10 = False() in -- #37 -//│ let* (x$11) = foo(x$10) in -- #36 -//│ x$11 -- #35 -//│ ) -//│ }, -//│ let* (x$12) = main() in -- #41 -//│ x$12 -- #40) +//│ |#fun| |not|(|x|)| |#=|→|#if| |x| |#then| |False| |#else| |True|←|↵|#fun| |foo|(|x|)| |#=|→|#if| |x| |#then| |None|→|#else| |Some|(|foo|(|not|(|x|)|)|)|←|←|↵|#fun| |main|(||)| |#=| |foo|(|False|)|↵|main|(||)| +//│ Parsed: {fun not = (x,) => {if (x) then False else True}; fun foo = (x,) => {if (x) then None else Some(foo(not(x,),),)}; fun main = () => foo(False,); main()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def not(x$1) = +//│ if x$1 -- #11 +//│ true => +//│ let x$3 = False() in -- #7 +//│ jump j$0(x$3) -- #6 +//│ false => +//│ let x$4 = True() in -- #10 +//│ jump j$0(x$4) -- #9 +//│ def j$0(x$2) = +//│ x$2 -- #4 +//│ def foo(x$5) = +//│ if x$5 -- #31 +//│ true => +//│ let x$7 = None() in -- #16 +//│ jump j$1(x$7) -- #15 +//│ false => +//│ let* (x$8) = not(x$5) in -- #30 +//│ let* (x$9) = foo(x$8) in -- #29 +//│ let x$10 = Some(x$9) in -- #28 +//│ jump j$1(x$10) -- #27 +//│ def j$1(x$6) = +//│ x$6 -- #13 +//│ def main() = +//│ let x$11 = False() in -- #37 +//│ let* (x$12) = foo(x$11) in -- #36 +//│ x$12 -- #35 +//│ let* (x$0) = main() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: -//│ B(A()) +//│ Some(None()) +//│ :interpIR -class True -class False -class A() -class B(b) +:genCpp fun aaa() = let m = 1 let n = 2 @@ -171,97 +175,79 @@ fun bbb() = fun not(x) = if x then False else True fun foo(x) = - if x then A - else B(foo(not(x))) + if x then None + else Some(foo(not(x))) fun main() = let x = foo(False) if x is - A then aaa() - B(b1) then bbb() + None then aaa() + Some(b1) then bbb() main() -//│ |#class| |True|↵|#class| |False|↵|#class| |A|(||)|↵|#class| |B|(|b|)|↵|#fun| |aaa|(||)| |#=|→|#let| |m| |#=| |1|↵|#let| |n| |#=| |2|↵|#let| |p| |#=| |3|↵|#let| |q| |#=| |4|↵|m| |+| |n| |-| |p| |+| |q|←|↵|#fun| |bbb|(||)| |#=|→|#let| |x| |#=| |aaa|(||)|↵|x| |*| |100| |+| |4|←|↵|#fun| |not|(|x|)| |#=|→|#if| |x| |#then| |False| |#else| |True|←|↵|#fun| |foo|(|x|)| |#=|→|#if| |x| |#then| |A|→|#else| |B|(|foo|(|not|(|x|)|)|)|←|←|↵|#fun| |main|(||)| |#=|→|#let| |x| |#=| |foo|(|False|)|↵|#if| |x| |is|→|A| |#then| |aaa|(||)|↵|B|(|b1|)| |#then| |bbb|(||)|←|←|↵|main|(||)| -//│ Parsed: {class True {}; class False {}; class A() {}; class B(b,) {}; fun aaa = () => {let m = 1; let n = 2; let p = 3; let q = 4; +(-(+(m,)(n,),)(p,),)(q,)}; fun bbb = () => {let x = aaa(); +(*(x,)(100,),)(4,)}; fun not = (x,) => {if (x) then False else True}; fun foo = (x,) => {if (x) then A else B(foo(not(x,),),)}; fun main = () => {let x = foo(False,); if x is ‹(A) then aaa(); (B(b1,)) then bbb()›}; main()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, True, []),ClassInfo(3, False, []),ClassInfo(4, A, []),ClassInfo(5, B, [b])}, { -//│ Def(0, aaa, [], -//│ 1, -//│ let x$0 = 1 in -- #17 -//│ let x$1 = 2 in -- #16 -//│ let x$2 = 3 in -- #15 -//│ let x$3 = 4 in -- #14 -//│ let x$4 = +(x$0,x$1) in -- #13 -//│ let x$5 = -(x$4,x$2) in -- #12 -//│ let x$6 = +(x$5,x$3) in -- #11 -//│ x$6 -- #10 -//│ ) -//│ Def(1, bbb, [], -//│ 1, -//│ let* (x$7) = aaa() in -- #28 -//│ let x$8 = *(x$7,100) in -- #27 -//│ let x$9 = +(x$8,4) in -- #26 -//│ x$9 -- #25 -//│ ) -//│ Def(2, not, [x$10], -//│ 1, -//│ if x$10 -- #37 -//│ true => -//│ let x$12 = False() in -- #33 -//│ jump j$0(x$12) -- #32 -//│ false => -//│ let x$13 = True() in -- #36 -//│ jump j$0(x$13) -- #35 -//│ ) -//│ Def(3, j$0, [x$11], -//│ 1, -//│ x$11 -- #30 -//│ ) -//│ Def(4, foo, [x$14], -//│ 1, -//│ if x$14 -- #59 -//│ true => -//│ let x$16 = A() in -- #42 -//│ jump j$1(x$16) -- #41 -//│ false => -//│ let* (x$17) = not(x$14) in -- #58 -//│ let* (x$18) = foo(x$17) in -- #57 -//│ let x$19 = B(x$18) in -- #56 -//│ jump j$1(x$19) -- #55 -//│ ) -//│ Def(5, j$1, [x$15], -//│ 1, -//│ x$15 -- #39 -//│ ) -//│ Def(6, main, [], -//│ 1, -//│ let x$20 = False() in -- #82 -//│ let* (x$21) = foo(x$20) in -- #81 -//│ case x$21 of -- #80 -//│ A => -//│ let* (x$23) = aaa() in -- #71 -//│ jump j$2(x$23) -- #70 -//│ B => -//│ let x$24 = x$21.b in -- #79 -//│ let* (x$25) = bbb() in -- #78 -//│ jump j$2(x$25) -- #77 -//│ ) -//│ Def(7, j$2, [x$22], -//│ 1, -//│ x$22 -- #66 -//│ ) -//│ }, -//│ let* (x$26) = main() in -- #86 -//│ x$26 -- #85) +//│ |#fun| |aaa|(||)| |#=|→|#let| |m| |#=| |1|↵|#let| |n| |#=| |2|↵|#let| |p| |#=| |3|↵|#let| |q| |#=| |4|↵|m| |+| |n| |-| |p| |+| |q|←|↵|#fun| |bbb|(||)| |#=|→|#let| |x| |#=| |aaa|(||)|↵|x| |*| |100| |+| |4|←|↵|#fun| |not|(|x|)| |#=|→|#if| |x| |#then| |False| |#else| |True|←|↵|#fun| |foo|(|x|)| |#=|→|#if| |x| |#then| |None|→|#else| |Some|(|foo|(|not|(|x|)|)|)|←|←|↵|#fun| |main|(||)| |#=|→|#let| |x| |#=| |foo|(|False|)|↵|#if| |x| |is|→|None| |#then| |aaa|(||)|↵|Some|(|b1|)| |#then| |bbb|(||)|←|←|↵|main|(||)| +//│ Parsed: {fun aaa = () => {let m = 1; let n = 2; let p = 3; let q = 4; +(-(+(m, n,), p,), q,)}; fun bbb = () => {let x = aaa(); +(*(x, 100,), 4,)}; fun not = (x,) => {if (x) then False else True}; fun foo = (x,) => {if (x) then None else Some(foo(not(x,),),)}; fun main = () => {let x = foo(False,); if x is ‹(None) then aaa(); (Some(b1,)) then bbb()›}; main()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def aaa() = +//│ let x$1 = 1 in -- #29 +//│ let x$2 = 2 in -- #28 +//│ let x$3 = 3 in -- #27 +//│ let x$4 = 4 in -- #26 +//│ let x$5 = +(x$1,x$2) in -- #25 +//│ let x$6 = -(x$5,x$3) in -- #24 +//│ let x$7 = +(x$6,x$4) in -- #23 +//│ x$7 -- #22 +//│ def bbb() = +//│ let* (x$8) = aaa() in -- #45 +//│ let x$9 = *(x$8,100) in -- #44 +//│ let x$10 = +(x$9,4) in -- #43 +//│ x$10 -- #42 +//│ def not(x$11) = +//│ if x$11 -- #54 +//│ true => +//│ let x$13 = False() in -- #50 +//│ jump j$0(x$13) -- #49 +//│ false => +//│ let x$14 = True() in -- #53 +//│ jump j$0(x$14) -- #52 +//│ def j$0(x$12) = +//│ x$12 -- #47 +//│ def foo(x$15) = +//│ if x$15 -- #74 +//│ true => +//│ let x$17 = None() in -- #59 +//│ jump j$1(x$17) -- #58 +//│ false => +//│ let* (x$18) = not(x$15) in -- #73 +//│ let* (x$19) = foo(x$18) in -- #72 +//│ let x$20 = Some(x$19) in -- #71 +//│ jump j$1(x$20) -- #70 +//│ def j$1(x$16) = +//│ x$16 -- #56 +//│ def main() = +//│ let x$21 = False() in -- #96 +//│ let* (x$22) = foo(x$21) in -- #95 +//│ case x$22 of -- #94 +//│ None => +//│ let* (x$24) = aaa() in -- #84 +//│ jump j$2(x$24) -- #83 +//│ Some => +//│ let x$25 = Some.x(x$22) in -- #93 +//│ let* (x$26) = bbb() in -- #92 +//│ jump j$2(x$26) -- #91 +//│ def j$2(x$23) = +//│ x$23 -- #80 +//│ let* (x$0) = main() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ 404 +//│ :interpIR -class True -class False -class S(s) -class O fun odd(x) = if x is O then False @@ -272,62 +258,51 @@ fun even(x) = S(s) then odd(s) fun foo() = odd(S(S(S(O)))) foo() -//│ |#class| |True|↵|#class| |False|↵|#class| |S|(|s|)|↵|#class| |O|↵|#fun| |odd|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |False|↵|S|(|s|)| |#then| |even|(|s|)|←|←|↵|#fun| |even|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |True|↵|S|(|s|)| |#then| |odd|(|s|)|←|←|↵|#fun| |foo|(||)| |#=| |odd|(|S|(|S|(|S|(|O|)|)|)|)|↵|foo|(||)| -//│ Parsed: {class True {}; class False {}; class S(s,) {}; class O {}; fun odd = (x,) => {if x is ‹(O) then False; (S(s,)) then even(s,)›}; fun even = (x,) => {if x is ‹(O) then True; (S(s,)) then odd(s,)›}; fun foo = () => odd(S(S(S(O,),),),); foo()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, True, []),ClassInfo(3, False, []),ClassInfo(4, S, [s]),ClassInfo(5, O, [])}, { -//│ Def(0, odd, [x$0], -//│ 1, -//│ case x$0 of -- #15 -//│ O => -//│ let x$2 = False() in -- #4 -//│ jump j$0(x$2) -- #3 -//│ S => -//│ let x$3 = x$0.s in -- #14 -//│ let* (x$4) = even(x$3) in -- #13 -//│ jump j$0(x$4) -- #12 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #1 -//│ ) -//│ Def(2, even, [x$5], -//│ 1, -//│ case x$5 of -- #31 -//│ O => -//│ let x$7 = True() in -- #20 -//│ jump j$1(x$7) -- #19 -//│ S => -//│ let x$8 = x$5.s in -- #30 -//│ let* (x$9) = odd(x$8) in -- #29 -//│ jump j$1(x$9) -- #28 -//│ ) -//│ Def(3, j$1, [x$6], -//│ 1, -//│ x$6 -- #17 -//│ ) -//│ Def(4, foo, [], -//│ 1, -//│ let x$10 = O() in -- #50 -//│ let x$11 = S(x$10) in -- #49 -//│ let x$12 = S(x$11) in -- #48 -//│ let x$13 = S(x$12) in -- #47 -//│ let* (x$14) = odd(x$13) in -- #46 -//│ x$14 -- #45 -//│ ) -//│ }, -//│ let* (x$15) = foo() in -- #54 -//│ x$15 -- #53) +//│ |#fun| |odd|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |False|↵|S|(|s|)| |#then| |even|(|s|)|←|←|↵|#fun| |even|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |True|↵|S|(|s|)| |#then| |odd|(|s|)|←|←|↵|#fun| |foo|(||)| |#=| |odd|(|S|(|S|(|S|(|O|)|)|)|)|↵|foo|(||)| +//│ Parsed: {fun odd = (x,) => {if x is ‹(O) then False; (S(s,)) then even(s,)›}; fun even = (x,) => {if x is ‹(O) then True; (S(s,)) then odd(s,)›}; fun foo = () => odd(S(S(S(O,),),),); foo()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def odd(x$1) = +//│ case x$1 of -- #19 +//│ O => +//│ let x$3 = False() in -- #7 +//│ jump j$0(x$3) -- #6 +//│ S => +//│ let x$4 = S.s(x$1) in -- #18 +//│ let* (x$5) = even(x$4) in -- #17 +//│ jump j$0(x$5) -- #16 +//│ def j$0(x$2) = +//│ x$2 -- #4 +//│ def even(x$6) = +//│ case x$6 of -- #36 +//│ O => +//│ let x$8 = True() in -- #24 +//│ jump j$1(x$8) -- #23 +//│ S => +//│ let x$9 = S.s(x$6) in -- #35 +//│ let* (x$10) = odd(x$9) in -- #34 +//│ jump j$1(x$10) -- #33 +//│ def j$1(x$7) = +//│ x$7 -- #21 +//│ def foo() = +//│ let x$11 = O() in -- #54 +//│ let x$12 = S(x$11) in -- #53 +//│ let x$13 = S(x$12) in -- #52 +//│ let x$14 = S(x$13) in -- #51 +//│ let* (x$15) = odd(x$14) in -- #50 +//│ x$15 -- #49 +//│ let* (x$0) = foo() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ True() +//│ :interpIR -class True -class False -class S(s) -class O +:genCpp fun odd(x) = if x is O then False @@ -339,77 +314,61 @@ fun even(x) = fun mk(n) = if n > 0 then S(mk(n - 1)) else O fun foo() = odd(mk(10)) foo() -//│ |#class| |True|↵|#class| |False|↵|#class| |S|(|s|)|↵|#class| |O|↵|#fun| |odd|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |False|↵|S|(|s|)| |#then| |even|(|s|)|←|←|↵|#fun| |even|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |True|↵|S|(|s|)| |#then| |odd|(|s|)|←|←|↵|#fun| |mk|(|n|)| |#=| |#if| |n| |>| |0| |#then| |S|(|mk|(|n| |-| |1|)|)| |#else| |O|↵|#fun| |foo|(||)| |#=| |odd|(|mk|(|10|)|)|↵|foo|(||)| | -//│ Parsed: {class True {}; class False {}; class S(s,) {}; class O {}; fun odd = (x,) => {if x is ‹(O) then False; (S(s,)) then even(s,)›}; fun even = (x,) => {if x is ‹(O) then True; (S(s,)) then odd(s,)›}; fun mk = (n,) => if (>(n,)(0,)) then S(mk(-(n,)(1,),),) else O; fun foo = () => odd(mk(10,),); foo()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, True, []),ClassInfo(3, False, []),ClassInfo(4, S, [s]),ClassInfo(5, O, [])}, { -//│ Def(0, odd, [x$0], -//│ 1, -//│ case x$0 of -- #15 -//│ O => -//│ let x$2 = False() in -- #4 -//│ jump j$0(x$2) -- #3 -//│ S => -//│ let x$3 = x$0.s in -- #14 -//│ let* (x$4) = even(x$3) in -- #13 -//│ jump j$0(x$4) -- #12 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #1 -//│ ) -//│ Def(2, even, [x$5], -//│ 1, -//│ case x$5 of -- #31 -//│ O => -//│ let x$7 = True() in -- #20 -//│ jump j$1(x$7) -- #19 -//│ S => -//│ let x$8 = x$5.s in -- #30 -//│ let* (x$9) = odd(x$8) in -- #29 -//│ jump j$1(x$9) -- #28 -//│ ) -//│ Def(3, j$1, [x$6], -//│ 1, -//│ x$6 -- #17 -//│ ) -//│ Def(4, mk, [n$0], -//│ 1, -//│ let x$10 = >(n$0,0) in -- #54 -//│ if x$10 -- #53 -//│ true => -//│ let x$12 = -(n$0,1) in -- #49 -//│ let* (x$13) = mk(x$12) in -- #48 -//│ let x$14 = S(x$13) in -- #47 -//│ jump j$2(x$14) -- #46 -//│ false => -//│ let x$15 = O() in -- #52 -//│ jump j$2(x$15) -- #51 -//│ ) -//│ Def(5, j$2, [x$11], -//│ 1, -//│ x$11 -- #35 -//│ ) -//│ Def(6, foo, [], -//│ 1, -//│ let* (x$16) = mk(10) in -- #65 -//│ let* (x$17) = odd(x$16) in -- #64 -//│ x$17 -- #63 -//│ ) -//│ }, -//│ let* (x$18) = foo() in -- #69 -//│ x$18 -- #68) +//│ |#fun| |odd|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |False|↵|S|(|s|)| |#then| |even|(|s|)|←|←|↵|#fun| |even|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |True|↵|S|(|s|)| |#then| |odd|(|s|)|←|←|↵|#fun| |mk|(|n|)| |#=| |#if| |n| |>| |0| |#then| |S|(|mk|(|n| |-| |1|)|)| |#else| |O|↵|#fun| |foo|(||)| |#=| |odd|(|mk|(|10|)|)|↵|foo|(||)| | +//│ Parsed: {fun odd = (x,) => {if x is ‹(O) then False; (S(s,)) then even(s,)›}; fun even = (x,) => {if x is ‹(O) then True; (S(s,)) then odd(s,)›}; fun mk = (n,) => if (>(n, 0,)) then S(mk(-(n, 1,),),) else O; fun foo = () => odd(mk(10,),); foo()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def odd(x$1) = +//│ case x$1 of -- #19 +//│ O => +//│ let x$3 = False() in -- #7 +//│ jump j$0(x$3) -- #6 +//│ S => +//│ let x$4 = S.s(x$1) in -- #18 +//│ let* (x$5) = even(x$4) in -- #17 +//│ jump j$0(x$5) -- #16 +//│ def j$0(x$2) = +//│ x$2 -- #4 +//│ def even(x$6) = +//│ case x$6 of -- #36 +//│ O => +//│ let x$8 = True() in -- #24 +//│ jump j$1(x$8) -- #23 +//│ S => +//│ let x$9 = S.s(x$6) in -- #35 +//│ let* (x$10) = odd(x$9) in -- #34 +//│ jump j$1(x$10) -- #33 +//│ def j$1(x$7) = +//│ x$7 -- #21 +//│ def mk(n$0) = +//│ let x$11 = >(n$0,0) in -- #64 +//│ if x$11 -- #63 +//│ true => +//│ let x$13 = -(n$0,1) in -- #59 +//│ let* (x$14) = mk(x$13) in -- #58 +//│ let x$15 = S(x$14) in -- #57 +//│ jump j$2(x$15) -- #56 +//│ false => +//│ let x$16 = O() in -- #62 +//│ jump j$2(x$16) -- #61 +//│ def j$2(x$12) = +//│ x$12 -- #43 +//│ def foo() = +//│ let* (x$17) = mk(10) in -- #73 +//│ let* (x$18) = odd(x$17) in -- #72 +//│ x$18 -- #71 +//│ let* (x$0) = foo() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: +//│ False() //│ -//│ IR Processing Failed: can not find the matched case, ClassInfo(0, True, []) expected :interpIR -class True -class False -class S(s) -class O +:genCpp fun odd(x) = if x is O then False @@ -421,79 +380,63 @@ fun even(x) = fun mk(n) = if n > 0 then S(mk(n - 1)) else O fun foo() = odd(S(S(mk(10)))) foo() -//│ |#class| |True|↵|#class| |False|↵|#class| |S|(|s|)|↵|#class| |O|↵|#fun| |odd|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |False|↵|S|(|s|)| |#then| |even|(|s|)|←|←|↵|#fun| |even|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |True|↵|S|(|s|)| |#then| |odd|(|s|)|←|←|↵|#fun| |mk|(|n|)| |#=| |#if| |n| |>| |0| |#then| |S|(|mk|(|n| |-| |1|)|)| |#else| |O|↵|#fun| |foo|(||)| |#=| |odd|(|S|(|S|(|mk|(|10|)|)|)|)|↵|foo|(||)| -//│ Parsed: {class True {}; class False {}; class S(s,) {}; class O {}; fun odd = (x,) => {if x is ‹(O) then False; (S(s,)) then even(s,)›}; fun even = (x,) => {if x is ‹(O) then True; (S(s,)) then odd(s,)›}; fun mk = (n,) => if (>(n,)(0,)) then S(mk(-(n,)(1,),),) else O; fun foo = () => odd(S(S(mk(10,),),),); foo()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, True, []),ClassInfo(3, False, []),ClassInfo(4, S, [s]),ClassInfo(5, O, [])}, { -//│ Def(0, odd, [x$0], -//│ 1, -//│ case x$0 of -- #15 -//│ O => -//│ let x$2 = False() in -- #4 -//│ jump j$0(x$2) -- #3 -//│ S => -//│ let x$3 = x$0.s in -- #14 -//│ let* (x$4) = even(x$3) in -- #13 -//│ jump j$0(x$4) -- #12 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #1 -//│ ) -//│ Def(2, even, [x$5], -//│ 1, -//│ case x$5 of -- #31 -//│ O => -//│ let x$7 = True() in -- #20 -//│ jump j$1(x$7) -- #19 -//│ S => -//│ let x$8 = x$5.s in -- #30 -//│ let* (x$9) = odd(x$8) in -- #29 -//│ jump j$1(x$9) -- #28 -//│ ) -//│ Def(3, j$1, [x$6], -//│ 1, -//│ x$6 -- #17 -//│ ) -//│ Def(4, mk, [n$0], -//│ 1, -//│ let x$10 = >(n$0,0) in -- #54 -//│ if x$10 -- #53 -//│ true => -//│ let x$12 = -(n$0,1) in -- #49 -//│ let* (x$13) = mk(x$12) in -- #48 -//│ let x$14 = S(x$13) in -- #47 -//│ jump j$2(x$14) -- #46 -//│ false => -//│ let x$15 = O() in -- #52 -//│ jump j$2(x$15) -- #51 -//│ ) -//│ Def(5, j$2, [x$11], -//│ 1, -//│ x$11 -- #35 -//│ ) -//│ Def(6, foo, [], -//│ 1, -//│ let* (x$16) = mk(10) in -- #73 -//│ let x$17 = S(x$16) in -- #72 -//│ let x$18 = S(x$17) in -- #71 -//│ let* (x$19) = odd(x$18) in -- #70 -//│ x$19 -- #69 -//│ ) -//│ }, -//│ let* (x$20) = foo() in -- #77 -//│ x$20 -- #76) +//│ |#fun| |odd|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |False|↵|S|(|s|)| |#then| |even|(|s|)|←|←|↵|#fun| |even|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |True|↵|S|(|s|)| |#then| |odd|(|s|)|←|←|↵|#fun| |mk|(|n|)| |#=| |#if| |n| |>| |0| |#then| |S|(|mk|(|n| |-| |1|)|)| |#else| |O|↵|#fun| |foo|(||)| |#=| |odd|(|S|(|S|(|mk|(|10|)|)|)|)|↵|foo|(||)| +//│ Parsed: {fun odd = (x,) => {if x is ‹(O) then False; (S(s,)) then even(s,)›}; fun even = (x,) => {if x is ‹(O) then True; (S(s,)) then odd(s,)›}; fun mk = (n,) => if (>(n, 0,)) then S(mk(-(n, 1,),),) else O; fun foo = () => odd(S(S(mk(10,),),),); foo()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def odd(x$1) = +//│ case x$1 of -- #19 +//│ O => +//│ let x$3 = False() in -- #7 +//│ jump j$0(x$3) -- #6 +//│ S => +//│ let x$4 = S.s(x$1) in -- #18 +//│ let* (x$5) = even(x$4) in -- #17 +//│ jump j$0(x$5) -- #16 +//│ def j$0(x$2) = +//│ x$2 -- #4 +//│ def even(x$6) = +//│ case x$6 of -- #36 +//│ O => +//│ let x$8 = True() in -- #24 +//│ jump j$1(x$8) -- #23 +//│ S => +//│ let x$9 = S.s(x$6) in -- #35 +//│ let* (x$10) = odd(x$9) in -- #34 +//│ jump j$1(x$10) -- #33 +//│ def j$1(x$7) = +//│ x$7 -- #21 +//│ def mk(n$0) = +//│ let x$11 = >(n$0,0) in -- #64 +//│ if x$11 -- #63 +//│ true => +//│ let x$13 = -(n$0,1) in -- #59 +//│ let* (x$14) = mk(x$13) in -- #58 +//│ let x$15 = S(x$14) in -- #57 +//│ jump j$2(x$15) -- #56 +//│ false => +//│ let x$16 = O() in -- #62 +//│ jump j$2(x$16) -- #61 +//│ def j$2(x$12) = +//│ x$12 -- #43 +//│ def foo() = +//│ let* (x$17) = mk(10) in -- #81 +//│ let x$18 = S(x$17) in -- #80 +//│ let x$19 = S(x$18) in -- #79 +//│ let* (x$20) = odd(x$19) in -- #78 +//│ x$20 -- #77 +//│ let* (x$0) = foo() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: +//│ False() //│ -//│ IR Processing Failed: can not find the matched case, ClassInfo(0, True, []) expected :interpIR -class True -class False -class S(s) -class O +:genCpp fun odd(x) = if x is O then False @@ -508,95 +451,75 @@ fun main() = foo() bar() main() -//│ |#class| |True|↵|#class| |False|↵|#class| |S|(|s|)|↵|#class| |O|↵|#fun| |odd|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |False|↵|S|(|s|)| |#then| |even|(|s|)|←|←|↵|#fun| |even|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |True|↵|S|(|s|)| |#then| |odd|(|s|)|←|←|↵|#fun| |foo|(||)| |#=| |odd|(|#if| |10| |>| |0| |#then| |S|(|O|)| |#else| |O|)|↵|#fun| |bar|(||)| |#=| |#if| |10| |>| |0| |#then| |odd|(|S|(|O|)|)| |#else| |odd|(|O|)|↵|#fun| |main|(||)| |#=|→|foo|(||)|↵|bar|(||)|←|↵|main|(||)| -//│ Parsed: {class True {}; class False {}; class S(s,) {}; class O {}; fun odd = (x,) => {if x is ‹(O) then False; (S(s,)) then even(s,)›}; fun even = (x,) => {if x is ‹(O) then True; (S(s,)) then odd(s,)›}; fun foo = () => odd(if (>(10,)(0,)) then S(O,) else O,); fun bar = () => if (>(10,)(0,)) then odd(S(O,),) else odd(O,); fun main = () => {foo(); bar()}; main()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, True, []),ClassInfo(3, False, []),ClassInfo(4, S, [s]),ClassInfo(5, O, [])}, { -//│ Def(0, odd, [x$0], -//│ 1, -//│ case x$0 of -- #15 -//│ O => -//│ let x$2 = False() in -- #4 -//│ jump j$0(x$2) -- #3 -//│ S => -//│ let x$3 = x$0.s in -- #14 -//│ let* (x$4) = even(x$3) in -- #13 -//│ jump j$0(x$4) -- #12 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #1 -//│ ) -//│ Def(2, even, [x$5], -//│ 1, -//│ case x$5 of -- #31 -//│ O => -//│ let x$7 = True() in -- #20 -//│ jump j$1(x$7) -- #19 -//│ S => -//│ let x$8 = x$5.s in -- #30 -//│ let* (x$9) = odd(x$8) in -- #29 -//│ jump j$1(x$9) -- #28 -//│ ) -//│ Def(3, j$1, [x$6], -//│ 1, -//│ x$6 -- #17 -//│ ) -//│ Def(4, foo, [], -//│ 1, -//│ let x$10 = >(10,0) in -- #52 -//│ if x$10 -- #51 -//│ true => -//│ let x$13 = O() in -- #47 -//│ let x$14 = S(x$13) in -- #46 -//│ jump j$2(x$14) -- #45 -//│ false => -//│ let x$15 = O() in -- #50 -//│ jump j$2(x$15) -- #49 -//│ ) -//│ Def(5, j$2, [x$11], -//│ 1, -//│ let* (x$12) = odd(x$11) in -- #40 -//│ x$12 -- #39 -//│ ) -//│ Def(6, bar, [], -//│ 1, -//│ let x$16 = >(10,0) in -- #78 -//│ if x$16 -- #77 -//│ true => -//│ let x$18 = O() in -- #68 -//│ let x$19 = S(x$18) in -- #67 -//│ let* (x$20) = odd(x$19) in -- #66 -//│ jump j$3(x$20) -- #65 -//│ false => -//│ let x$21 = O() in -- #76 -//│ let* (x$22) = odd(x$21) in -- #75 -//│ jump j$3(x$22) -- #74 -//│ ) -//│ Def(7, j$3, [x$17], -//│ 1, -//│ x$17 -- #56 -//│ ) -//│ Def(8, main, [], -//│ 1, -//│ let* (x$23) = foo() in -- #86 -//│ let* (x$24) = bar() in -- #85 -//│ x$24 -- #84 -//│ ) -//│ }, -//│ let* (x$25) = main() in -- #90 -//│ x$25 -- #89) +//│ |#fun| |odd|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |False|↵|S|(|s|)| |#then| |even|(|s|)|←|←|↵|#fun| |even|(|x|)| |#=|→|#if| |x| |is|→|O| |#then| |True|↵|S|(|s|)| |#then| |odd|(|s|)|←|←|↵|#fun| |foo|(||)| |#=| |odd|(|#if| |10| |>| |0| |#then| |S|(|O|)| |#else| |O|)|↵|#fun| |bar|(||)| |#=| |#if| |10| |>| |0| |#then| |odd|(|S|(|O|)|)| |#else| |odd|(|O|)|↵|#fun| |main|(||)| |#=|→|foo|(||)|↵|bar|(||)|←|↵|main|(||)| +//│ Parsed: {fun odd = (x,) => {if x is ‹(O) then False; (S(s,)) then even(s,)›}; fun even = (x,) => {if x is ‹(O) then True; (S(s,)) then odd(s,)›}; fun foo = () => odd(if (>(10, 0,)) then S(O,) else O,); fun bar = () => if (>(10, 0,)) then odd(S(O,),) else odd(O,); fun main = () => {foo(); bar()}; main()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def odd(x$1) = +//│ case x$1 of -- #19 +//│ O => +//│ let x$3 = False() in -- #7 +//│ jump j$0(x$3) -- #6 +//│ S => +//│ let x$4 = S.s(x$1) in -- #18 +//│ let* (x$5) = even(x$4) in -- #17 +//│ jump j$0(x$5) -- #16 +//│ def j$0(x$2) = +//│ x$2 -- #4 +//│ def even(x$6) = +//│ case x$6 of -- #36 +//│ O => +//│ let x$8 = True() in -- #24 +//│ jump j$1(x$8) -- #23 +//│ S => +//│ let x$9 = S.s(x$6) in -- #35 +//│ let* (x$10) = odd(x$9) in -- #34 +//│ jump j$1(x$10) -- #33 +//│ def j$1(x$7) = +//│ x$7 -- #21 +//│ def foo() = +//│ let x$11 = >(10,0) in -- #59 +//│ if x$11 -- #58 +//│ true => +//│ let x$14 = O() in -- #54 +//│ let x$15 = S(x$14) in -- #53 +//│ jump j$2(x$15) -- #52 +//│ false => +//│ let x$16 = O() in -- #57 +//│ jump j$2(x$16) -- #56 +//│ def j$2(x$12) = +//│ let* (x$13) = odd(x$12) in -- #47 +//│ x$13 -- #46 +//│ def bar() = +//│ let x$17 = >(10,0) in -- #86 +//│ if x$17 -- #85 +//│ true => +//│ let x$19 = O() in -- #77 +//│ let x$20 = S(x$19) in -- #76 +//│ let* (x$21) = odd(x$20) in -- #75 +//│ jump j$3(x$21) -- #74 +//│ false => +//│ let x$22 = O() in -- #84 +//│ let* (x$23) = odd(x$22) in -- #83 +//│ jump j$3(x$23) -- #82 +//│ def j$3(x$18) = +//│ x$18 -- #66 +//│ def main() = +//│ let* (x$24) = foo() in -- #92 +//│ let* (x$25) = bar() in -- #91 +//│ x$25 -- #90 +//│ let* (x$0) = main() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: +//│ True() //│ -//│ IR Processing Failed: can not find the matched case, ClassInfo(0, True, []) expected :interpIR -class True -class False -class A() -class B(b) +:genCpp fun aaa() = let m = 1 let n = 2 @@ -609,98 +532,79 @@ fun bbb() = fun not(x) = if x then False else True fun foo(x) = - if x then A else B(foo(not(x))) + if x then None else Some(foo(not(x))) fun main(flag) = let x = foo(flag) if x is - A then aaa() - B(b1) then bbb() + None then aaa() + Some(b1) then bbb() main(False) -//│ |#class| |True|↵|#class| |False|↵|#class| |A|(||)|↵|#class| |B|(|b|)|↵|#fun| |aaa|(||)| |#=|→|#let| |m| |#=| |1|↵|#let| |n| |#=| |2|↵|#let| |p| |#=| |3|↵|#let| |q| |#=| |4|↵|m| |+| |n| |-| |p| |+| |q|←|↵|#fun| |bbb|(||)| |#=|→|#let| |x| |#=| |aaa|(||)|↵|x| |*| |100| |+| |4|←|↵|#fun| |not|(|x|)| |#=|→|#if| |x| |#then| |False| |#else| |True|←|↵|#fun| |foo|(|x|)| |#=|→|#if| |x| |#then| |A| |#else| |B|(|foo|(|not|(|x|)|)|)|←|↵|#fun| |main|(|flag|)| |#=|→|#let| |x| |#=| |foo|(|flag|)|↵|#if| |x| |is|→|A| |#then| |aaa|(||)|↵|B|(|b1|)| |#then| |bbb|(||)|←|←|↵|main|(|False|)| -//│ Parsed: {class True {}; class False {}; class A() {}; class B(b,) {}; fun aaa = () => {let m = 1; let n = 2; let p = 3; let q = 4; +(-(+(m,)(n,),)(p,),)(q,)}; fun bbb = () => {let x = aaa(); +(*(x,)(100,),)(4,)}; fun not = (x,) => {if (x) then False else True}; fun foo = (x,) => {if (x) then A else B(foo(not(x,),),)}; fun main = (flag,) => {let x = foo(flag,); if x is ‹(A) then aaa(); (B(b1,)) then bbb()›}; main(False,)} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, True, []),ClassInfo(3, False, []),ClassInfo(4, A, []),ClassInfo(5, B, [b])}, { -//│ Def(0, aaa, [], -//│ 1, -//│ let x$0 = 1 in -- #17 -//│ let x$1 = 2 in -- #16 -//│ let x$2 = 3 in -- #15 -//│ let x$3 = 4 in -- #14 -//│ let x$4 = +(x$0,x$1) in -- #13 -//│ let x$5 = -(x$4,x$2) in -- #12 -//│ let x$6 = +(x$5,x$3) in -- #11 -//│ x$6 -- #10 -//│ ) -//│ Def(1, bbb, [], -//│ 1, -//│ let* (x$7) = aaa() in -- #28 -//│ let x$8 = *(x$7,100) in -- #27 -//│ let x$9 = +(x$8,4) in -- #26 -//│ x$9 -- #25 -//│ ) -//│ Def(2, not, [x$10], -//│ 1, -//│ if x$10 -- #37 -//│ true => -//│ let x$12 = False() in -- #33 -//│ jump j$0(x$12) -- #32 -//│ false => -//│ let x$13 = True() in -- #36 -//│ jump j$0(x$13) -- #35 -//│ ) -//│ Def(3, j$0, [x$11], -//│ 1, -//│ x$11 -- #30 -//│ ) -//│ Def(4, foo, [x$14], -//│ 1, -//│ if x$14 -- #59 -//│ true => -//│ let x$16 = A() in -- #42 -//│ jump j$1(x$16) -- #41 -//│ false => -//│ let* (x$17) = not(x$14) in -- #58 -//│ let* (x$18) = foo(x$17) in -- #57 -//│ let x$19 = B(x$18) in -- #56 -//│ jump j$1(x$19) -- #55 -//│ ) -//│ Def(5, j$1, [x$15], -//│ 1, -//│ x$15 -- #39 -//│ ) -//│ Def(6, main, [flag$0], -//│ 1, -//│ let* (x$20) = foo(flag$0) in -- #81 -//│ case x$20 of -- #80 -//│ A => -//│ let* (x$22) = aaa() in -- #71 -//│ jump j$2(x$22) -- #70 -//│ B => -//│ let x$23 = x$20.b in -- #79 -//│ let* (x$24) = bbb() in -- #78 -//│ jump j$2(x$24) -- #77 -//│ ) -//│ Def(7, j$2, [x$21], -//│ 1, -//│ x$21 -- #66 -//│ ) -//│ }, -//│ let x$25 = False() in -- #88 -//│ let* (x$26) = main(x$25) in -- #87 -//│ x$26 -- #86) +//│ |#fun| |aaa|(||)| |#=|→|#let| |m| |#=| |1|↵|#let| |n| |#=| |2|↵|#let| |p| |#=| |3|↵|#let| |q| |#=| |4|↵|m| |+| |n| |-| |p| |+| |q|←|↵|#fun| |bbb|(||)| |#=|→|#let| |x| |#=| |aaa|(||)|↵|x| |*| |100| |+| |4|←|↵|#fun| |not|(|x|)| |#=|→|#if| |x| |#then| |False| |#else| |True|←|↵|#fun| |foo|(|x|)| |#=|→|#if| |x| |#then| |None| |#else| |Some|(|foo|(|not|(|x|)|)|)|←|↵|#fun| |main|(|flag|)| |#=|→|#let| |x| |#=| |foo|(|flag|)|↵|#if| |x| |is|→|None| |#then| |aaa|(||)|↵|Some|(|b1|)| |#then| |bbb|(||)|←|←|↵|main|(|False|)| +//│ Parsed: {fun aaa = () => {let m = 1; let n = 2; let p = 3; let q = 4; +(-(+(m, n,), p,), q,)}; fun bbb = () => {let x = aaa(); +(*(x, 100,), 4,)}; fun not = (x,) => {if (x) then False else True}; fun foo = (x,) => {if (x) then None else Some(foo(not(x,),),)}; fun main = (flag,) => {let x = foo(flag,); if x is ‹(None) then aaa(); (Some(b1,)) then bbb()›}; main(False,)} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def aaa() = +//│ let x$2 = 1 in -- #32 +//│ let x$3 = 2 in -- #31 +//│ let x$4 = 3 in -- #30 +//│ let x$5 = 4 in -- #29 +//│ let x$6 = +(x$2,x$3) in -- #28 +//│ let x$7 = -(x$6,x$4) in -- #27 +//│ let x$8 = +(x$7,x$5) in -- #26 +//│ x$8 -- #25 +//│ def bbb() = +//│ let* (x$9) = aaa() in -- #48 +//│ let x$10 = *(x$9,100) in -- #47 +//│ let x$11 = +(x$10,4) in -- #46 +//│ x$11 -- #45 +//│ def not(x$12) = +//│ if x$12 -- #57 +//│ true => +//│ let x$14 = False() in -- #53 +//│ jump j$0(x$14) -- #52 +//│ false => +//│ let x$15 = True() in -- #56 +//│ jump j$0(x$15) -- #55 +//│ def j$0(x$13) = +//│ x$13 -- #50 +//│ def foo(x$16) = +//│ if x$16 -- #77 +//│ true => +//│ let x$18 = None() in -- #62 +//│ jump j$1(x$18) -- #61 +//│ false => +//│ let* (x$19) = not(x$16) in -- #76 +//│ let* (x$20) = foo(x$19) in -- #75 +//│ let x$21 = Some(x$20) in -- #74 +//│ jump j$1(x$21) -- #73 +//│ def j$1(x$17) = +//│ x$17 -- #59 +//│ def main(flag$0) = +//│ let* (x$22) = foo(flag$0) in -- #98 +//│ case x$22 of -- #97 +//│ None => +//│ let* (x$24) = aaa() in -- #87 +//│ jump j$2(x$24) -- #86 +//│ Some => +//│ let x$25 = Some.x(x$22) in -- #96 +//│ let* (x$26) = bbb() in -- #95 +//│ jump j$2(x$26) -- #94 +//│ def j$2(x$23) = +//│ x$23 -- #83 +//│ let x$0 = False() in -- #5 +//│ let* (x$1) = main(x$0) in -- #4 +//│ x$1 -- #3 //│ //│ Interpreted: //│ 404 +//│ :interpIR -class True -class False -class Cons(h, t) -class Nil -class Some(x) -class None +:genCpp fun head_opt(l) = if l is Nil then None @@ -714,70 +618,55 @@ fun is_empty(l) = fun main() = is_empty(Cons(1, Cons(2, Nil))) main() -//│ |#class| |True|↵|#class| |False|↵|#class| |Cons|(|h|,| |t|)|↵|#class| |Nil|↵|#class| |Some|(|x|)|↵|#class| |None|↵|#fun| |head_opt|(|l|)| |#=|→|#if| |l| |is|→|Nil| |#then| |None|↵|Cons|(|h|,| |t|)| |#then| |Some|(|h|)|←|←|↵|#fun| |is_none|(|o|)| |#=|→|#if| |o| |is|→|None| |#then| |True|↵|Some|(|x|)| |#then| |False|←|←|↵|#fun| |is_empty|(|l|)| |#=|→|is_none|(|head_opt|(|l|)|)|←|↵|#fun| |main|(||)| |#=|→|is_empty|(|Cons|(|1|,| |Cons|(|2|,| |Nil|)|)|)|←|↵|main|(||)| -//│ Parsed: {class True {}; class False {}; class Cons(h, t,) {}; class Nil {}; class Some(x,) {}; class None {}; fun head_opt = (l,) => {if l is ‹(Nil) then None; (Cons(h, t,)) then Some(h,)›}; fun is_none = (o,) => {if o is ‹(None) then True; (Some(x,)) then False›}; fun is_empty = (l,) => {is_none(head_opt(l,),)}; fun main = () => {is_empty(Cons(1, Cons(2, Nil,),),)}; main()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, True, []),ClassInfo(3, False, []),ClassInfo(4, Cons, [h,t]),ClassInfo(5, Nil, []),ClassInfo(6, Some, [x]),ClassInfo(7, None, [])}, { -//│ Def(0, head_opt, [l$0], -//│ 1, -//│ case l$0 of -- #17 -//│ Nil => -//│ let x$1 = None() in -- #4 -//│ jump j$0(x$1) -- #3 -//│ Cons => -//│ let x$2 = l$0.t in -- #16 -//│ let x$3 = l$0.h in -- #15 -//│ let x$4 = Some(x$3) in -- #14 -//│ jump j$0(x$4) -- #13 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, is_none, [o$0], -//│ 1, -//│ case o$0 of -- #29 -//│ None => -//│ let x$6 = True() in -- #22 -//│ jump j$1(x$6) -- #21 -//│ Some => -//│ let x$7 = o$0.x in -- #28 -//│ let x$8 = False() in -- #27 -//│ jump j$1(x$8) -- #26 -//│ ) -//│ Def(3, j$1, [x$5], -//│ 1, -//│ x$5 -- #19 -//│ ) -//│ Def(4, is_empty, [l$1], -//│ 1, -//│ let* (x$9) = head_opt(l$1) in -- #40 -//│ let* (x$10) = is_none(x$9) in -- #39 -//│ x$10 -- #38 -//│ ) -//│ Def(5, main, [], -//│ 1, -//│ let x$11 = Nil() in -- #59 -//│ let x$12 = Cons(2,x$11) in -- #58 -//│ let x$13 = Cons(1,x$12) in -- #57 -//│ let* (x$14) = is_empty(x$13) in -- #56 -//│ x$14 -- #55 -//│ ) -//│ }, -//│ let* (x$15) = main() in -- #63 -//│ x$15 -- #62) +//│ |#fun| |head_opt|(|l|)| |#=|→|#if| |l| |is|→|Nil| |#then| |None|↵|Cons|(|h|,| |t|)| |#then| |Some|(|h|)|←|←|↵|#fun| |is_none|(|o|)| |#=|→|#if| |o| |is|→|None| |#then| |True|↵|Some|(|x|)| |#then| |False|←|←|↵|#fun| |is_empty|(|l|)| |#=|→|is_none|(|head_opt|(|l|)|)|←|↵|#fun| |main|(||)| |#=|→|is_empty|(|Cons|(|1|,| |Cons|(|2|,| |Nil|)|)|)|←|↵|main|(||)| +//│ Parsed: {fun head_opt = (l,) => {if l is ‹(Nil) then None; (Cons(h, t,)) then Some(h,)›}; fun is_none = (o,) => {if o is ‹(None) then True; (Some(x,)) then False›}; fun is_empty = (l,) => {is_none(head_opt(l,),)}; fun main = () => {is_empty(Cons(1, Cons(2, Nil,),),)}; main()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def head_opt(l$0) = +//│ case l$0 of -- #24 +//│ Nil => +//│ let x$2 = None() in -- #7 +//│ jump j$0(x$2) -- #6 +//│ Cons => +//│ let x$3 = Cons.t(l$0) in -- #23 +//│ let x$4 = Cons.h(l$0) in -- #22 +//│ let x$5 = Some(x$4) in -- #21 +//│ jump j$0(x$5) -- #20 +//│ def j$0(x$1) = +//│ x$1 -- #4 +//│ def is_none(o$0) = +//│ case o$0 of -- #38 +//│ None => +//│ let x$7 = True() in -- #29 +//│ jump j$1(x$7) -- #28 +//│ Some => +//│ let x$8 = Some.x(o$0) in -- #37 +//│ let x$9 = False() in -- #36 +//│ jump j$1(x$9) -- #35 +//│ def j$1(x$6) = +//│ x$6 -- #26 +//│ def is_empty(l$1) = +//│ let* (x$10) = head_opt(l$1) in -- #47 +//│ let* (x$11) = is_none(x$10) in -- #46 +//│ x$11 -- #45 +//│ def main() = +//│ let x$12 = Nil() in -- #65 +//│ let x$13 = Cons(2,x$12) in -- #64 +//│ let x$14 = Cons(1,x$13) in -- #63 +//│ let* (x$15) = is_empty(x$14) in -- #62 +//│ x$15 -- #61 +//│ let* (x$0) = main() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ False() +//│ :interpIR -class True -class False -class Cons(h, t) -class Nil -class Some(x) -class None +:genCpp fun mk_list(n) = if n == 0 then Nil else Cons(n, mk_list(n - 1)) fun head_opt(l) = @@ -793,86 +682,66 @@ fun is_empty(l) = fun main() = is_empty(mk_list(10)) main() -//│ |#class| |True|↵|#class| |False|↵|#class| |Cons|(|h|,| |t|)|↵|#class| |Nil|↵|#class| |Some|(|x|)|↵|#class| |None|↵|#fun| |mk_list|(|n|)| |#=|→|#if| |n| |==| |0| |#then| |Nil| |#else| |Cons|(|n|,| |mk_list|(|n| |-| |1|)|)|←|↵|#fun| |head_opt|(|l|)| |#=|→|#if| |l| |is|→|Nil| |#then| |None|↵|Cons|(|h|,| |t|)| |#then| |Some|(|h|)|←|←|↵|#fun| |is_none|(|o|)| |#=|→|#if| |o| |is|→|None| |#then| |True|↵|Some|(|x|)| |#then| |False|←|←|↵|#fun| |is_empty|(|l|)| |#=|→|is_none|(|head_opt|(|l|)|)|←|↵|#fun| |main|(||)| |#=|→|is_empty|(|mk_list|(|10|)|)|←|↵|main|(||)| -//│ Parsed: {class True {}; class False {}; class Cons(h, t,) {}; class Nil {}; class Some(x,) {}; class None {}; fun mk_list = (n,) => {if (==(n,)(0,)) then Nil else Cons(n, mk_list(-(n,)(1,),),)}; fun head_opt = (l,) => {if l is ‹(Nil) then None; (Cons(h, t,)) then Some(h,)›}; fun is_none = (o,) => {if o is ‹(None) then True; (Some(x,)) then False›}; fun is_empty = (l,) => {is_none(head_opt(l,),)}; fun main = () => {is_empty(mk_list(10,),)}; main()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, True, []),ClassInfo(3, False, []),ClassInfo(4, Cons, [h,t]),ClassInfo(5, Nil, []),ClassInfo(6, Some, [x]),ClassInfo(7, None, [])}, { -//│ Def(0, mk_list, [n$0], -//│ 1, -//│ let x$0 = ==(n$0,0) in -- #24 -//│ if x$0 -- #23 -//│ true => -//│ let x$2 = Nil() in -- #6 -//│ jump j$0(x$2) -- #5 -//│ false => -//│ let x$3 = -(n$0,1) in -- #22 -//│ let* (x$4) = mk_list(x$3) in -- #21 -//│ let x$5 = Cons(n$0,x$4) in -- #20 -//│ jump j$0(x$5) -- #19 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #3 -//│ ) -//│ Def(2, head_opt, [l$0], -//│ 1, -//│ case l$0 of -- #42 -//│ Nil => -//│ let x$7 = None() in -- #29 -//│ jump j$1(x$7) -- #28 -//│ Cons => -//│ let x$8 = l$0.t in -- #41 -//│ let x$9 = l$0.h in -- #40 -//│ let x$10 = Some(x$9) in -- #39 -//│ jump j$1(x$10) -- #38 -//│ ) -//│ Def(3, j$1, [x$6], -//│ 1, -//│ x$6 -- #26 -//│ ) -//│ Def(4, is_none, [o$0], -//│ 1, -//│ case o$0 of -- #54 -//│ None => -//│ let x$12 = True() in -- #47 -//│ jump j$2(x$12) -- #46 -//│ Some => -//│ let x$13 = o$0.x in -- #53 -//│ let x$14 = False() in -- #52 -//│ jump j$2(x$14) -- #51 -//│ ) -//│ Def(5, j$2, [x$11], -//│ 1, -//│ x$11 -- #44 -//│ ) -//│ Def(6, is_empty, [l$1], -//│ 1, -//│ let* (x$15) = head_opt(l$1) in -- #65 -//│ let* (x$16) = is_none(x$15) in -- #64 -//│ x$16 -- #63 -//│ ) -//│ Def(7, main, [], -//│ 1, -//│ let* (x$17) = mk_list(10) in -- #76 -//│ let* (x$18) = is_empty(x$17) in -- #75 -//│ x$18 -- #74 -//│ ) -//│ }, -//│ let* (x$19) = main() in -- #80 -//│ x$19 -- #79) +//│ |#fun| |mk_list|(|n|)| |#=|→|#if| |n| |==| |0| |#then| |Nil| |#else| |Cons|(|n|,| |mk_list|(|n| |-| |1|)|)|←|↵|#fun| |head_opt|(|l|)| |#=|→|#if| |l| |is|→|Nil| |#then| |None|↵|Cons|(|h|,| |t|)| |#then| |Some|(|h|)|←|←|↵|#fun| |is_none|(|o|)| |#=|→|#if| |o| |is|→|None| |#then| |True|↵|Some|(|x|)| |#then| |False|←|←|↵|#fun| |is_empty|(|l|)| |#=|→|is_none|(|head_opt|(|l|)|)|←|↵|#fun| |main|(||)| |#=|→|is_empty|(|mk_list|(|10|)|)|←|↵|main|(||)| +//│ Parsed: {fun mk_list = (n,) => {if (==(n, 0,)) then Nil else Cons(n, mk_list(-(n, 1,),),)}; fun head_opt = (l,) => {if l is ‹(Nil) then None; (Cons(h, t,)) then Some(h,)›}; fun is_none = (o,) => {if o is ‹(None) then True; (Some(x,)) then False›}; fun is_empty = (l,) => {is_none(head_opt(l,),)}; fun main = () => {is_empty(mk_list(10,),)}; main()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def mk_list(n$0) = +//│ let x$1 = ==(n$0,0) in -- #32 +//│ if x$1 -- #31 +//│ true => +//│ let x$3 = Nil() in -- #12 +//│ jump j$0(x$3) -- #11 +//│ false => +//│ let x$4 = -(n$0,1) in -- #30 +//│ let* (x$5) = mk_list(x$4) in -- #29 +//│ let x$6 = Cons(n$0,x$5) in -- #28 +//│ jump j$0(x$6) -- #27 +//│ def j$0(x$2) = +//│ x$2 -- #9 +//│ def head_opt(l$0) = +//│ case l$0 of -- #54 +//│ Nil => +//│ let x$8 = None() in -- #37 +//│ jump j$1(x$8) -- #36 +//│ Cons => +//│ let x$9 = Cons.t(l$0) in -- #53 +//│ let x$10 = Cons.h(l$0) in -- #52 +//│ let x$11 = Some(x$10) in -- #51 +//│ jump j$1(x$11) -- #50 +//│ def j$1(x$7) = +//│ x$7 -- #34 +//│ def is_none(o$0) = +//│ case o$0 of -- #68 +//│ None => +//│ let x$13 = True() in -- #59 +//│ jump j$2(x$13) -- #58 +//│ Some => +//│ let x$14 = Some.x(o$0) in -- #67 +//│ let x$15 = False() in -- #66 +//│ jump j$2(x$15) -- #65 +//│ def j$2(x$12) = +//│ x$12 -- #56 +//│ def is_empty(l$1) = +//│ let* (x$16) = head_opt(l$1) in -- #77 +//│ let* (x$17) = is_none(x$16) in -- #76 +//│ x$17 -- #75 +//│ def main() = +//│ let* (x$18) = mk_list(10) in -- #86 +//│ let* (x$19) = is_empty(x$18) in -- #85 +//│ x$19 -- #84 +//│ let* (x$0) = main() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: +//│ False() //│ -//│ IR Processing Failed: can not find the matched case, ClassInfo(1, False, []) expected :interpIR -class True -class False -class Cons(h, t) -class Nil -class Some(x) -class None +:genCpp fun mk_list(n) = if n == 0 then Nil else Cons(n, mk_list(n - 1)) fun last_opt(l) = @@ -885,76 +754,60 @@ fun last_opt(l) = fun main() = last_opt(mk_list(10)) main() -//│ |#class| |True|↵|#class| |False|↵|#class| |Cons|(|h|,| |t|)|↵|#class| |Nil|↵|#class| |Some|(|x|)|↵|#class| |None|↵|#fun| |mk_list|(|n|)| |#=|→|#if| |n| |==| |0| |#then| |Nil| |#else| |Cons|(|n|,| |mk_list|(|n| |-| |1|)|)|←|↵|#fun| |last_opt|(|l|)| |#=|→|#if| |l| |is|→|Nil| |#then| |None|↵|Cons|(|h|,| |t|)| |#then|→|#if| |t| |is|→|Nil| |#then| |Some|(|h|)|↵|Cons|(|h2|,| |t2|)| |#then| |last_opt|(|t|)|←|←|←|←|↵|#fun| |main|(||)| |#=|→|last_opt|(|mk_list|(|10|)|)|←|↵|main|(||)| -//│ Parsed: {class True {}; class False {}; class Cons(h, t,) {}; class Nil {}; class Some(x,) {}; class None {}; fun mk_list = (n,) => {if (==(n,)(0,)) then Nil else Cons(n, mk_list(-(n,)(1,),),)}; fun last_opt = (l,) => {if l is ‹(Nil) then None; (Cons(h, t,)) then {if t is ‹(Nil) then Some(h,); (Cons(h2, t2,)) then last_opt(t,)›}›}; fun main = () => {last_opt(mk_list(10,),)}; main()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, True, []),ClassInfo(3, False, []),ClassInfo(4, Cons, [h,t]),ClassInfo(5, Nil, []),ClassInfo(6, Some, [x]),ClassInfo(7, None, [])}, { -//│ Def(0, mk_list, [n$0], -//│ 1, -//│ let x$0 = ==(n$0,0) in -- #24 -//│ if x$0 -- #23 -//│ true => -//│ let x$2 = Nil() in -- #6 -//│ jump j$0(x$2) -- #5 -//│ false => -//│ let x$3 = -(n$0,1) in -- #22 -//│ let* (x$4) = mk_list(x$3) in -- #21 -//│ let x$5 = Cons(n$0,x$4) in -- #20 -//│ jump j$0(x$5) -- #19 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #3 -//│ ) -//│ Def(2, last_opt, [l$0], -//│ 1, -//│ case l$0 of -- #59 -//│ Nil => -//│ let x$7 = None() in -- #29 -//│ jump j$1(x$7) -- #28 -//│ Cons => -//│ let x$8 = l$0.t in -- #58 -//│ let x$9 = l$0.h in -- #57 -//│ case x$8 of -- #56 +//│ |#fun| |mk_list|(|n|)| |#=|→|#if| |n| |==| |0| |#then| |Nil| |#else| |Cons|(|n|,| |mk_list|(|n| |-| |1|)|)|←|↵|#fun| |last_opt|(|l|)| |#=|→|#if| |l| |is|→|Nil| |#then| |None|↵|Cons|(|h|,| |t|)| |#then|→|#if| |t| |is|→|Nil| |#then| |Some|(|h|)|↵|Cons|(|h2|,| |t2|)| |#then| |last_opt|(|t|)|←|←|←|←|↵|#fun| |main|(||)| |#=|→|last_opt|(|mk_list|(|10|)|)|←|↵|main|(||)| +//│ Parsed: {fun mk_list = (n,) => {if (==(n, 0,)) then Nil else Cons(n, mk_list(-(n, 1,),),)}; fun last_opt = (l,) => {if l is ‹(Nil) then None; (Cons(h, t,)) then {if t is ‹(Nil) then Some(h,); (Cons(h2, t2,)) then last_opt(t,)›}›}; fun main = () => {last_opt(mk_list(10,),)}; main()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def mk_list(n$0) = +//│ let x$1 = ==(n$0,0) in -- #32 +//│ if x$1 -- #31 +//│ true => +//│ let x$3 = Nil() in -- #12 +//│ jump j$0(x$3) -- #11 +//│ false => +//│ let x$4 = -(n$0,1) in -- #30 +//│ let* (x$5) = mk_list(x$4) in -- #29 +//│ let x$6 = Cons(n$0,x$5) in -- #28 +//│ jump j$0(x$6) -- #27 +//│ def j$0(x$2) = +//│ x$2 -- #9 +//│ def last_opt(l$0) = +//│ case l$0 of -- #74 //│ Nil => -//│ let x$11 = Some(x$9) in -- #42 -//│ jump j$2(x$11) -- #41 +//│ let x$8 = None() in -- #37 +//│ jump j$1(x$8) -- #36 //│ Cons => -//│ let x$12 = x$8.t in -- #55 -//│ let x$13 = x$8.h in -- #54 -//│ let* (x$14) = last_opt(x$8) in -- #53 -//│ jump j$2(x$14) -- #52 -//│ ) -//│ Def(3, j$1, [x$6], -//│ 1, -//│ x$6 -- #26 -//│ ) -//│ Def(4, j$2, [x$10], -//│ 1, -//│ jump j$1(x$10) -- #36 -//│ ) -//│ Def(5, main, [], -//│ 1, -//│ let* (x$15) = mk_list(10) in -- #70 -//│ let* (x$16) = last_opt(x$15) in -- #69 -//│ x$16 -- #68 -//│ ) -//│ }, -//│ let* (x$17) = main() in -- #74 -//│ x$17 -- #73) +//│ let x$9 = Cons.t(l$0) in -- #73 +//│ let x$10 = Cons.h(l$0) in -- #72 +//│ case x$9 of -- #71 +//│ Nil => +//│ let x$12 = Some(x$10) in -- #54 +//│ jump j$2(x$12) -- #53 +//│ Cons => +//│ let x$13 = Cons.t(x$9) in -- #70 +//│ let x$14 = Cons.h(x$9) in -- #69 +//│ let* (x$15) = last_opt(x$9) in -- #68 +//│ jump j$2(x$15) -- #67 +//│ def j$1(x$7) = +//│ x$7 -- #34 +//│ def j$2(x$11) = +//│ jump j$1(x$11) -- #48 +//│ def main() = +//│ let* (x$16) = mk_list(10) in -- #83 +//│ let* (x$17) = last_opt(x$16) in -- #82 +//│ x$17 -- #81 +//│ let* (x$0) = main() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: +//│ Some(1) //│ -//│ IR Processing Failed: can not find the matched case, ClassInfo(1, False, []) expected :interpIR -class True -class False -class Cons(h, t) -class Nil -class Some(x) -class None +:genCpp fun is_some(o) = if o is Some(x) then True @@ -981,111 +834,88 @@ fun f(x) = fun main() = f(Some(2)) + f(None) main() -//│ |#class| |True|↵|#class| |False|↵|#class| |Cons|(|h|,| |t|)|↵|#class| |Nil|↵|#class| |Some|(|x|)|↵|#class| |None|↵|#fun| |is_some|(|o|)| |#=|→|#if| |o| |is|→|Some|(|x|)| |#then| |True|↵|None| |#then| |False|←|←|↵|#fun| |e0|(|w|)| |#=|→|w| |+| |8| |+| |9| |+| |10|←|↵|#fun| |e1|(|a|,| |c|)| |#=|→|a| |+| |1| |+| |2| |+| |3| |+| |4|←|↵|#fun| |e3|(|c|)| |#=|→|#let| |m| |#=| |4|↵|#let| |n| |#=| |5|↵|#let| |p| |#=| |6|↵|#let| |q| |#=| |7|↵|#if| |c| |#then| |m| |+| |n| |+| |p| |+| |q| |#else| |m| |+| |n| |-| |p| |+| |q|←|↵|#fun| |e2|(|x|)| |#=|→|x| |+| |12| |+| |13| |+| |14|←|↵|#fun| |f|(|x|)| |#=|→|#let| |c1| |#=| |is_some|(|x|)|↵|#let| |z| |#=| |e3|(|c1|)|↵|#let| |w| |#=| |#if| |x| |is|→|Some|(|a|)| |#then| |e1|(|a|,| |z|)|↵|None| |#then| |e2|(|z|)|←|↵|e0|(|w|)|←|↵|#fun| |main|(||)| |#=|→|f|(|Some|(|2|)|)| |+| |f|(|None|)|←|↵|main|(||)| -//│ Parsed: {class True {}; class False {}; class Cons(h, t,) {}; class Nil {}; class Some(x,) {}; class None {}; fun is_some = (o,) => {if o is ‹(Some(x,)) then True; (None) then False›}; fun e0 = (w,) => {+(+(+(w,)(8,),)(9,),)(10,)}; fun e1 = (a, c,) => {+(+(+(+(a,)(1,),)(2,),)(3,),)(4,)}; fun e3 = (c,) => {let m = 4; let n = 5; let p = 6; let q = 7; if (c) then +(+(+(m,)(n,),)(p,),)(q,) else +(-(+(m,)(n,),)(p,),)(q,)}; fun e2 = (x,) => {+(+(+(x,)(12,),)(13,),)(14,)}; fun f = (x,) => {let c1 = is_some(x,); let z = e3(c1,); let w = if x is ‹(Some(a,)) then e1(a, z,); (None) then e2(z,)›; e0(w,)}; fun main = () => {+(f(Some(2,),),)(f(None,),)}; main()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, True, []),ClassInfo(3, False, []),ClassInfo(4, Cons, [h,t]),ClassInfo(5, Nil, []),ClassInfo(6, Some, [x]),ClassInfo(7, None, [])}, { -//│ Def(0, is_some, [o$0], -//│ 1, -//│ case o$0 of -- #11 -//│ Some => -//│ let x$1 = o$0.x in -- #7 -//│ let x$2 = True() in -- #6 -//│ jump j$0(x$2) -- #5 -//│ None => -//│ let x$3 = False() in -- #10 -//│ jump j$0(x$3) -- #9 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, e0, [w$0], -//│ 1, -//│ let x$4 = +(w$0,8) in -- #21 -//│ let x$5 = +(x$4,9) in -- #20 -//│ let x$6 = +(x$5,10) in -- #19 -//│ x$6 -- #18 -//│ ) -//│ Def(3, e1, [a$0,c$0], -//│ 1, -//│ let x$7 = +(a$0,1) in -- #34 -//│ let x$8 = +(x$7,2) in -- #33 -//│ let x$9 = +(x$8,3) in -- #32 -//│ let x$10 = +(x$9,4) in -- #31 -//│ x$10 -- #30 -//│ ) -//│ Def(4, e3, [c$1], -//│ 1, -//│ let x$11 = 4 in -- #67 -//│ let x$12 = 5 in -- #66 -//│ let x$13 = 6 in -- #65 -//│ let x$14 = 7 in -- #64 -//│ if c$1 -- #63 -//│ true => -//│ let x$16 = +(x$11,x$12) in -- #51 -//│ let x$17 = +(x$16,x$13) in -- #50 -//│ let x$18 = +(x$17,x$14) in -- #49 -//│ jump j$1(x$18) -- #48 -//│ false => -//│ let x$19 = +(x$11,x$12) in -- #62 -//│ let x$20 = -(x$19,x$13) in -- #61 -//│ let x$21 = +(x$20,x$14) in -- #60 -//│ jump j$1(x$21) -- #59 -//│ ) -//│ Def(5, j$1, [x$15], -//│ 1, -//│ x$15 -- #40 -//│ ) -//│ Def(6, e2, [x$22], -//│ 1, -//│ let x$23 = +(x$22,12) in -- #77 -//│ let x$24 = +(x$23,13) in -- #76 -//│ let x$25 = +(x$24,14) in -- #75 -//│ x$25 -- #74 -//│ ) -//│ Def(7, f, [x$26], -//│ 1, -//│ let* (x$27) = is_some(x$26) in -- #117 -//│ let* (x$28) = e3(x$27) in -- #116 -//│ case x$26 of -- #115 -//│ Some => -//│ let x$31 = x$26.x in -- #107 -//│ let* (x$32) = e1(x$31,x$28) in -- #106 -//│ jump j$2(x$32) -- #105 -//│ None => -//│ let* (x$33) = e2(x$28) in -- #114 -//│ jump j$2(x$33) -- #113 -//│ ) -//│ Def(8, j$2, [x$29], -//│ 1, -//│ let* (x$30) = e0(x$29) in -- #95 -//│ x$30 -- #94 -//│ ) -//│ Def(9, main, [], -//│ 1, -//│ let x$34 = Some(2) in -- #136 -//│ let* (x$35) = f(x$34) in -- #135 -//│ let x$36 = None() in -- #134 -//│ let* (x$37) = f(x$36) in -- #133 -//│ let x$38 = +(x$35,x$37) in -- #132 -//│ x$38 -- #131 -//│ ) -//│ }, -//│ let* (x$39) = main() in -- #140 -//│ x$39 -- #139) +//│ |#fun| |is_some|(|o|)| |#=|→|#if| |o| |is|→|Some|(|x|)| |#then| |True|↵|None| |#then| |False|←|←|↵|#fun| |e0|(|w|)| |#=|→|w| |+| |8| |+| |9| |+| |10|←|↵|#fun| |e1|(|a|,| |c|)| |#=|→|a| |+| |1| |+| |2| |+| |3| |+| |4|←|↵|#fun| |e3|(|c|)| |#=|→|#let| |m| |#=| |4|↵|#let| |n| |#=| |5|↵|#let| |p| |#=| |6|↵|#let| |q| |#=| |7|↵|#if| |c| |#then| |m| |+| |n| |+| |p| |+| |q| |#else| |m| |+| |n| |-| |p| |+| |q|←|↵|#fun| |e2|(|x|)| |#=|→|x| |+| |12| |+| |13| |+| |14|←|↵|#fun| |f|(|x|)| |#=|→|#let| |c1| |#=| |is_some|(|x|)|↵|#let| |z| |#=| |e3|(|c1|)|↵|#let| |w| |#=| |#if| |x| |is|→|Some|(|a|)| |#then| |e1|(|a|,| |z|)|↵|None| |#then| |e2|(|z|)|←|↵|e0|(|w|)|←|↵|#fun| |main|(||)| |#=|→|f|(|Some|(|2|)|)| |+| |f|(|None|)|←|↵|main|(||)| +//│ Parsed: {fun is_some = (o,) => {if o is ‹(Some(x,)) then True; (None) then False›}; fun e0 = (w,) => {+(+(+(w, 8,), 9,), 10,)}; fun e1 = (a, c,) => {+(+(+(+(a, 1,), 2,), 3,), 4,)}; fun e3 = (c,) => {let m = 4; let n = 5; let p = 6; let q = 7; if (c) then +(+(+(m, n,), p,), q,) else +(-(+(m, n,), p,), q,)}; fun e2 = (x,) => {+(+(+(x, 12,), 13,), 14,)}; fun f = (x,) => {let c1 = is_some(x,); let z = e3(c1,); let w = if x is ‹(Some(a,)) then e1(a, z,); (None) then e2(z,)›; e0(w,)}; fun main = () => {+(f(Some(2,),), f(None,),)}; main()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def is_some(o$0) = +//│ case o$0 of -- #16 +//│ Some => +//│ let x$2 = Some.x(o$0) in -- #12 +//│ let x$3 = True() in -- #11 +//│ jump j$0(x$3) -- #10 +//│ None => +//│ let x$4 = False() in -- #15 +//│ jump j$0(x$4) -- #14 +//│ def j$0(x$1) = +//│ x$1 -- #4 +//│ def e0(w$0) = +//│ let x$5 = +(w$0,8) in -- #35 +//│ let x$6 = +(x$5,9) in -- #34 +//│ let x$7 = +(x$6,10) in -- #33 +//│ x$7 -- #32 +//│ def e1(a$0,c$0) = +//│ let x$8 = +(a$0,1) in -- #60 +//│ let x$9 = +(x$8,2) in -- #59 +//│ let x$10 = +(x$9,3) in -- #58 +//│ let x$11 = +(x$10,4) in -- #57 +//│ x$11 -- #56 +//│ def e3(c$1) = +//│ let x$12 = 4 in -- #111 +//│ let x$13 = 5 in -- #110 +//│ let x$14 = 6 in -- #109 +//│ let x$15 = 7 in -- #108 +//│ if c$1 -- #107 +//│ true => +//│ let x$17 = +(x$12,x$13) in -- #86 +//│ let x$18 = +(x$17,x$14) in -- #85 +//│ let x$19 = +(x$18,x$15) in -- #84 +//│ jump j$1(x$19) -- #83 +//│ false => +//│ let x$20 = +(x$12,x$13) in -- #106 +//│ let x$21 = -(x$20,x$14) in -- #105 +//│ let x$22 = +(x$21,x$15) in -- #104 +//│ jump j$1(x$22) -- #103 +//│ def j$1(x$16) = +//│ x$16 -- #66 +//│ def e2(x$23) = +//│ let x$24 = +(x$23,12) in -- #130 +//│ let x$25 = +(x$24,13) in -- #129 +//│ let x$26 = +(x$25,14) in -- #128 +//│ x$26 -- #127 +//│ def f(x$27) = +//│ let* (x$28) = is_some(x$27) in -- #167 +//│ let* (x$29) = e3(x$28) in -- #166 +//│ case x$27 of -- #165 +//│ Some => +//│ let x$32 = Some.x(x$27) in -- #158 +//│ let* (x$33) = e1(x$32,x$29) in -- #157 +//│ jump j$2(x$33) -- #156 +//│ None => +//│ let* (x$34) = e2(x$29) in -- #164 +//│ jump j$2(x$34) -- #163 +//│ def j$2(x$30) = +//│ let* (x$31) = e0(x$30) in -- #145 +//│ x$31 -- #144 +//│ def main() = +//│ let x$35 = Some(2) in -- #187 +//│ let* (x$36) = f(x$35) in -- #186 +//│ let x$37 = None() in -- #185 +//│ let* (x$38) = f(x$37) in -- #184 +//│ let x$39 = +(x$36,x$38) in -- #183 +//│ x$39 -- #182 +//│ let* (x$0) = main() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: //│ 115 +//│ :interpIR -class True -class False -class Cons(h, t) -class Nil -class Some(x) -class None +:genCpp fun is_some(o) = if o is Some(x) then True @@ -1112,109 +942,198 @@ fun f(x) = fun main() = f(Some(2)) + f(None) main() -//│ |#class| |True|↵|#class| |False|↵|#class| |Cons|(|h|,| |t|)|↵|#class| |Nil|↵|#class| |Some|(|x|)|↵|#class| |None|↵|#fun| |is_some|(|o|)| |#=|→|#if| |o| |is|→|Some|(|x|)| |#then| |True|↵|None| |#then| |False|←|←|↵|#fun| |e0|(|w|)| |#=|→|w| |+| |8| |+| |9| |+| |10|←|↵|#fun| |e1|(|a|,| |z|)| |#=|→|#if| |a| |>| |0| |#then| |f|(|Some|(|a| |-| |1|)|)| |#else| |z|←|↵|#fun| |e3|(|c|)| |#=|→|#let| |m| |#=| |4|↵|#let| |n| |#=| |5|↵|#let| |p| |#=| |6|↵|#let| |q| |#=| |7|↵|#if| |c| |#then| |m| |+| |n| |+| |p| |+| |q| |#else| |m| |+| |n| |-| |p| |+| |q|←|↵|#fun| |e2|(|x|)| |#=|→|x| |+| |12| |+| |13| |+| |14|←|↵|#fun| |f|(|x|)| |#=|→|#let| |c1| |#=| |is_some|(|x|)|↵|#let| |z| |#=| |e3|(|c1|)|↵|#let| |w| |#=| |#if| |x| |is|→|Some|(|a|)| |#then| |e1|(|a|,| |z|)|↵|None| |#then| |e2|(|z|)|←|↵|e0|(|w|)|←|↵|#fun| |main|(||)| |#=|→|f|(|Some|(|2|)|)| |+| |f|(|None|)|←|↵|main|(||)| -//│ Parsed: {class True {}; class False {}; class Cons(h, t,) {}; class Nil {}; class Some(x,) {}; class None {}; fun is_some = (o,) => {if o is ‹(Some(x,)) then True; (None) then False›}; fun e0 = (w,) => {+(+(+(w,)(8,),)(9,),)(10,)}; fun e1 = (a, z,) => {if (>(a,)(0,)) then f(Some(-(a,)(1,),),) else z}; fun e3 = (c,) => {let m = 4; let n = 5; let p = 6; let q = 7; if (c) then +(+(+(m,)(n,),)(p,),)(q,) else +(-(+(m,)(n,),)(p,),)(q,)}; fun e2 = (x,) => {+(+(+(x,)(12,),)(13,),)(14,)}; fun f = (x,) => {let c1 = is_some(x,); let z = e3(c1,); let w = if x is ‹(Some(a,)) then e1(a, z,); (None) then e2(z,)›; e0(w,)}; fun main = () => {+(f(Some(2,),),)(f(None,),)}; main()} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, True, []),ClassInfo(3, False, []),ClassInfo(4, Cons, [h,t]),ClassInfo(5, Nil, []),ClassInfo(6, Some, [x]),ClassInfo(7, None, [])}, { -//│ Def(0, is_some, [o$0], -//│ 1, -//│ case o$0 of -- #11 -//│ Some => -//│ let x$1 = o$0.x in -- #7 -//│ let x$2 = True() in -- #6 -//│ jump j$0(x$2) -- #5 -//│ None => -//│ let x$3 = False() in -- #10 -//│ jump j$0(x$3) -- #9 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, e0, [w$0], -//│ 1, -//│ let x$4 = +(w$0,8) in -- #21 -//│ let x$5 = +(x$4,9) in -- #20 -//│ let x$6 = +(x$5,10) in -- #19 -//│ x$6 -- #18 -//│ ) -//│ Def(3, e1, [a$0,z$0], -//│ 1, -//│ let x$7 = >(a$0,0) in -- #43 -//│ if x$7 -- #42 -//│ true => -//│ let x$9 = -(a$0,1) in -- #39 -//│ let x$10 = Some(x$9) in -- #38 -//│ let* (x$11) = f(x$10) in -- #37 -//│ jump j$1(x$11) -- #36 -//│ false => -//│ jump j$1(z$0) -- #41 -//│ ) -//│ Def(4, j$1, [x$8], -//│ 1, -//│ x$8 -- #25 -//│ ) -//│ Def(5, e3, [c$0], -//│ 1, -//│ let x$12 = 4 in -- #76 -//│ let x$13 = 5 in -- #75 -//│ let x$14 = 6 in -- #74 -//│ let x$15 = 7 in -- #73 -//│ if c$0 -- #72 -//│ true => -//│ let x$17 = +(x$12,x$13) in -- #60 -//│ let x$18 = +(x$17,x$14) in -- #59 -//│ let x$19 = +(x$18,x$15) in -- #58 -//│ jump j$2(x$19) -- #57 -//│ false => -//│ let x$20 = +(x$12,x$13) in -- #71 -//│ let x$21 = -(x$20,x$14) in -- #70 -//│ let x$22 = +(x$21,x$15) in -- #69 -//│ jump j$2(x$22) -- #68 -//│ ) -//│ Def(6, j$2, [x$16], -//│ 1, -//│ x$16 -- #49 -//│ ) -//│ Def(7, e2, [x$23], -//│ 1, -//│ let x$24 = +(x$23,12) in -- #86 -//│ let x$25 = +(x$24,13) in -- #85 -//│ let x$26 = +(x$25,14) in -- #84 -//│ x$26 -- #83 -//│ ) -//│ Def(8, f, [x$27], -//│ 1, -//│ let* (x$28) = is_some(x$27) in -- #126 -//│ let* (x$29) = e3(x$28) in -- #125 -//│ case x$27 of -- #124 -//│ Some => -//│ let x$32 = x$27.x in -- #116 -//│ let* (x$33) = e1(x$32,x$29) in -- #115 -//│ jump j$3(x$33) -- #114 -//│ None => -//│ let* (x$34) = e2(x$29) in -- #123 -//│ jump j$3(x$34) -- #122 -//│ ) -//│ Def(9, j$3, [x$30], -//│ 1, -//│ let* (x$31) = e0(x$30) in -- #104 -//│ x$31 -- #103 -//│ ) -//│ Def(10, main, [], -//│ 1, -//│ let x$35 = Some(2) in -- #145 -//│ let* (x$36) = f(x$35) in -- #144 -//│ let x$37 = None() in -- #143 -//│ let* (x$38) = f(x$37) in -- #142 -//│ let x$39 = +(x$36,x$38) in -- #141 -//│ x$39 -- #140 -//│ ) -//│ }, -//│ let* (x$40) = main() in -- #149 -//│ x$40 -- #148) +//│ |#fun| |is_some|(|o|)| |#=|→|#if| |o| |is|→|Some|(|x|)| |#then| |True|↵|None| |#then| |False|←|←|↵|#fun| |e0|(|w|)| |#=|→|w| |+| |8| |+| |9| |+| |10|←|↵|#fun| |e1|(|a|,| |z|)| |#=|→|#if| |a| |>| |0| |#then| |f|(|Some|(|a| |-| |1|)|)| |#else| |z|←|↵|#fun| |e3|(|c|)| |#=|→|#let| |m| |#=| |4|↵|#let| |n| |#=| |5|↵|#let| |p| |#=| |6|↵|#let| |q| |#=| |7|↵|#if| |c| |#then| |m| |+| |n| |+| |p| |+| |q| |#else| |m| |+| |n| |-| |p| |+| |q|←|↵|#fun| |e2|(|x|)| |#=|→|x| |+| |12| |+| |13| |+| |14|←|↵|#fun| |f|(|x|)| |#=|→|#let| |c1| |#=| |is_some|(|x|)|↵|#let| |z| |#=| |e3|(|c1|)|↵|#let| |w| |#=| |#if| |x| |is|→|Some|(|a|)| |#then| |e1|(|a|,| |z|)|↵|None| |#then| |e2|(|z|)|←|↵|e0|(|w|)|←|↵|#fun| |main|(||)| |#=|→|f|(|Some|(|2|)|)| |+| |f|(|None|)|←|↵|main|(||)| +//│ Parsed: {fun is_some = (o,) => {if o is ‹(Some(x,)) then True; (None) then False›}; fun e0 = (w,) => {+(+(+(w, 8,), 9,), 10,)}; fun e1 = (a, z,) => {if (>(a, 0,)) then f(Some(-(a, 1,),),) else z}; fun e3 = (c,) => {let m = 4; let n = 5; let p = 6; let q = 7; if (c) then +(+(+(m, n,), p,), q,) else +(-(+(m, n,), p,), q,)}; fun e2 = (x,) => {+(+(+(x, 12,), 13,), 14,)}; fun f = (x,) => {let c1 = is_some(x,); let z = e3(c1,); let w = if x is ‹(Some(a,)) then e1(a, z,); (None) then e2(z,)›; e0(w,)}; fun main = () => {+(f(Some(2,),), f(None,),)}; main()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def is_some(o$0) = +//│ case o$0 of -- #16 +//│ Some => +//│ let x$2 = Some.x(o$0) in -- #12 +//│ let x$3 = True() in -- #11 +//│ jump j$0(x$3) -- #10 +//│ None => +//│ let x$4 = False() in -- #15 +//│ jump j$0(x$4) -- #14 +//│ def j$0(x$1) = +//│ x$1 -- #4 +//│ def e0(w$0) = +//│ let x$5 = +(w$0,8) in -- #35 +//│ let x$6 = +(x$5,9) in -- #34 +//│ let x$7 = +(x$6,10) in -- #33 +//│ x$7 -- #32 +//│ def e1(a$0,z$0) = +//│ let x$8 = >(a$0,0) in -- #62 +//│ if x$8 -- #61 +//│ true => +//│ let x$10 = -(a$0,1) in -- #58 +//│ let x$11 = Some(x$10) in -- #57 +//│ let* (x$12) = f(x$11) in -- #56 +//│ jump j$1(x$12) -- #55 +//│ false => +//│ jump j$1(z$0) -- #60 +//│ def j$1(x$9) = +//│ x$9 -- #42 +//│ def e3(c$0) = +//│ let x$13 = 4 in -- #113 +//│ let x$14 = 5 in -- #112 +//│ let x$15 = 6 in -- #111 +//│ let x$16 = 7 in -- #110 +//│ if c$0 -- #109 +//│ true => +//│ let x$18 = +(x$13,x$14) in -- #88 +//│ let x$19 = +(x$18,x$15) in -- #87 +//│ let x$20 = +(x$19,x$16) in -- #86 +//│ jump j$2(x$20) -- #85 +//│ false => +//│ let x$21 = +(x$13,x$14) in -- #108 +//│ let x$22 = -(x$21,x$15) in -- #107 +//│ let x$23 = +(x$22,x$16) in -- #106 +//│ jump j$2(x$23) -- #105 +//│ def j$2(x$17) = +//│ x$17 -- #68 +//│ def e2(x$24) = +//│ let x$25 = +(x$24,12) in -- #132 +//│ let x$26 = +(x$25,13) in -- #131 +//│ let x$27 = +(x$26,14) in -- #130 +//│ x$27 -- #129 +//│ def f(x$28) = +//│ let* (x$29) = is_some(x$28) in -- #169 +//│ let* (x$30) = e3(x$29) in -- #168 +//│ case x$28 of -- #167 +//│ Some => +//│ let x$33 = Some.x(x$28) in -- #160 +//│ let* (x$34) = e1(x$33,x$30) in -- #159 +//│ jump j$3(x$34) -- #158 +//│ None => +//│ let* (x$35) = e2(x$30) in -- #166 +//│ jump j$3(x$35) -- #165 +//│ def j$3(x$31) = +//│ let* (x$32) = e0(x$31) in -- #147 +//│ x$32 -- #146 +//│ def main() = +//│ let x$36 = Some(2) in -- #189 +//│ let* (x$37) = f(x$36) in -- #188 +//│ let x$38 = None() in -- #187 +//│ let* (x$39) = f(x$38) in -- #186 +//│ let x$40 = +(x$37,x$39) in -- #185 +//│ x$40 -- #184 +//│ let* (x$0) = main() in -- #2 +//│ x$0 -- #1 //│ //│ Interpreted: +//│ 179 +//│ + +:genCpp +fun pred(n) = + if n is + S(p) then p + O then O +fun plus(n1, n2) = + if n1 is + O then n2 + S(p) then S(plus(p, n2)) +fun fib(n) = + if n is + O then S(O) + S(p) then + if p is + O then S(O) + S(q) then plus(fib(p), fib(q)) +fun to_int(n) = + if n is + O then 0 + S(p) then 1 + to_int(p) +fun to_nat(n) = + if n == 0 then O + else S(to_nat(n - 1)) +fun main() = + to_int(fib(to_nat(30))) +main() +//│ |#fun| |pred|(|n|)| |#=|→|#if| |n| |is|→|S|(|p|)| |#then| |p|↵|O| |#then| |O|←|←|↵|#fun| |plus|(|n1|,| |n2|)| |#=|→|#if| |n1| |is|→|O| |#then| |n2|↵|S|(|p|)| |#then| |S|(|plus|(|p|,| |n2|)|)|←|←|↵|#fun| |fib|(|n|)| |#=|→|#if| |n| |is|→|O| |#then| |S|(|O|)|↵|S|(|p|)| |#then|→|#if| |p| |is|→|O| |#then| |S|(|O|)|↵|S|(|q|)| |#then| |plus|(|fib|(|p|)|,| |fib|(|q|)|)|←|←|←|←|↵|#fun| |to_int|(|n|)| |#=|→|#if| |n| |is|→|O| |#then| |0|↵|S|(|p|)| |#then| |1| |+| |to_int|(|p|)|←|←|↵|#fun| |to_nat|(|n|)| |#=|→|#if| |n| |==| |0| |#then| |O|↵|#else| |S|(|to_nat|(|n| |-| |1|)|)|←|↵|#fun| |main|(||)| |#=|→|to_int|(|fib|(|to_nat|(|30|)|)|)|←|↵|main|(||)| +//│ Parsed: {fun pred = (n,) => {if n is ‹(S(p,)) then p; (O) then O›}; fun plus = (n1, n2,) => {if n1 is ‹(O) then n2; (S(p,)) then S(plus(p, n2,),)›}; fun fib = (n,) => {if n is ‹(O) then S(O,); (S(p,)) then {if p is ‹(O) then S(O,); (S(q,)) then plus(fib(p,), fib(q,),)›}›}; fun to_int = (n,) => {if n is ‹(O) then 0; (S(p,)) then +(1, to_int(p,),)›}; fun to_nat = (n,) => {if (==(n, 0,)) then O else S(to_nat(-(n, 1,),),)}; fun main = () => {to_int(fib(to_nat(30,),),)}; main()} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def pred(n$0) = +//│ case n$0 of -- #15 +//│ S => +//│ let x$2 = S.s(n$0) in -- #11 +//│ jump j$0(x$2) -- #10 +//│ O => +//│ let x$3 = O() in -- #14 +//│ jump j$0(x$3) -- #13 +//│ def j$0(x$1) = +//│ x$1 -- #4 +//│ def plus(n1$0,n2$0) = +//│ case n1$0 of -- #37 +//│ O => +//│ jump j$1(n2$0) -- #19 +//│ S => +//│ let x$5 = S.s(n1$0) in -- #36 +//│ let* (x$6) = plus(x$5,n2$0) in -- #35 +//│ let x$7 = S(x$6) in -- #34 +//│ jump j$1(x$7) -- #33 +//│ def j$1(x$4) = +//│ x$4 -- #17 +//│ def fib(n$1) = +//│ case n$1 of -- #84 +//│ O => +//│ let x$9 = O() in -- #46 +//│ let x$10 = S(x$9) in -- #45 +//│ jump j$2(x$10) -- #44 +//│ S => +//│ let x$11 = S.s(n$1) in -- #83 +//│ case x$11 of -- #82 +//│ O => +//│ let x$13 = O() in -- #60 +//│ let x$14 = S(x$13) in -- #59 +//│ jump j$3(x$14) -- #58 +//│ S => +//│ let x$15 = S.s(x$11) in -- #81 +//│ let* (x$16) = fib(x$11) in -- #80 +//│ let* (x$17) = fib(x$15) in -- #79 +//│ let* (x$18) = plus(x$16,x$17) in -- #78 +//│ jump j$3(x$18) -- #77 +//│ def j$2(x$8) = +//│ x$8 -- #39 +//│ def j$3(x$12) = +//│ jump j$2(x$12) -- #53 +//│ def to_int(n$2) = +//│ case n$2 of -- #106 +//│ O => +//│ jump j$4(0) -- #88 +//│ S => +//│ let x$20 = S.s(n$2) in -- #105 +//│ let* (x$21) = to_int(x$20) in -- #104 +//│ let x$22 = +(1,x$21) in -- #103 +//│ jump j$4(x$22) -- #102 +//│ def j$4(x$19) = +//│ x$19 -- #86 +//│ def to_nat(n$3) = +//│ let x$23 = ==(n$3,0) in -- #134 +//│ if x$23 -- #133 +//│ true => +//│ let x$25 = O() in -- #116 +//│ jump j$5(x$25) -- #115 +//│ false => +//│ let x$26 = -(n$3,1) in -- #132 +//│ let* (x$27) = to_nat(x$26) in -- #131 +//│ let x$28 = S(x$27) in -- #130 +//│ jump j$5(x$28) -- #129 +//│ def j$5(x$24) = +//│ x$24 -- #113 +//│ def main() = +//│ let* (x$29) = to_nat(30) in -- #147 +//│ let* (x$30) = fib(x$29) in -- #146 +//│ let* (x$31) = to_int(x$30) in -- #145 +//│ x$31 -- #144 +//│ let* (x$0) = main() in -- #2 +//│ x$0 -- #1 //│ -//│ IR Processing Failed: can not find the matched case, ClassInfo(0, True, []) expected diff --git a/compiler/shared/test/diff-ir/IRTailRec.mls b/compiler/shared/test/diff-ir/IRTailRec.mls index de30850804..4fb0b7e8cc 100644 --- a/compiler/shared/test/diff-ir/IRTailRec.mls +++ b/compiler/shared/test/diff-ir/IRTailRec.mls @@ -2,6 +2,35 @@ :ParseOnly :UseIR +:prelude +module True +module False +module Callable { + fun apply0() = 0 + fun apply1(x0) = 0 + fun apply2(x0,x1) = 0 + fun apply3(x0,x1,x2) = 0 + fun apply4(x0,x1,x2,x3) = 0 + fun apply5(x0,x1,x2,x3,x4) = 0 +} +module List[A, B] +class Cons[A, B](h: A, t: Cons[A, B]) extends List[A, B] +module Nil[A, B] extends List[A, B] +module Option[A] +class Some[A](x: A) extends Option[A] +module None[A] extends Option[A] +class Pair[A, B](x: A, y: B) +class Tuple2[A, B](x: A, y: B) +class Tuple3[A, B, C](x: A, y: B, z: C) +module Nat +class S(s: Nat) extends Nat +module O extends Nat +class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O) +//│ |#module| |True|↵|#module| |False|↵|#module| |Callable| |{|→|#fun| |apply0|(||)| |#=| |0|↵|#fun| |apply1|(|x0|)| |#=| |0|↵|#fun| |apply2|(|x0|,|x1|)| |#=| |0|↵|#fun| |apply3|(|x0|,|x1|,|x2|)| |#=| |0|↵|#fun| |apply4|(|x0|,|x1|,|x2|,|x3|)| |#=| |0|↵|#fun| |apply5|(|x0|,|x1|,|x2|,|x3|,|x4|)| |#=| |0|←|↵|}|↵|#module| |List|[|A|,| |B|]|↵|#class| |Cons|[|A|,| |B|]|(|h|#:| |A|,| |t|#:| |Cons|[|A|,| |B|]|)| |#extends| |List|[|A|,| |B|]|↵|#module| |Nil|[|A|,| |B|]| |#extends| |List|[|A|,| |B|]|↵|#module| |Option|[|A|]|↵|#class| |Some|[|A|]|(|x|#:| |A|)| |#extends| |Option|[|A|]|↵|#module| |None|[|A|]| |#extends| |Option|[|A|]|↵|#class| |Pair|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple2|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple3|[|A|,| |B|,| |C|]|(|x|#:| |A|,| |y|#:| |B|,| |z|#:| |C|)|↵|#module| |Nat|↵|#class| |S|(|s|#:| |Nat|)| |#extends| |Nat|↵|#module| |O| |#extends| |Nat|↵|#class| |HiddenTheseEntities|(|_0|#:| |HiddenTheseEntities|,| |_1|#:| |True|,| |_2|#:| |False|,| |_3|#:| |Callable|,| |_4|#:| |List|,| |_5|#:| |Cons|,| |_6|#:| |Nil|,| |_7|#:| |Option|,| |_8|#:| |Some|,| |_9|#:| |None|,| |_10|#:| |Pair|,| |_11|#:| |Tuple2|,| |_12|#:| |Tuple3|,| |_13|#:| |Nat|,| |_14|#:| |S|,| |_15|#:| |O|)| +//│ Parsed: {module True {}; module False {}; module Callable {fun apply0 = () => 0; fun apply1 = (x0,) => 0; fun apply2 = (x0, x1,) => 0; fun apply3 = (x0, x1, x2,) => 0; fun apply4 = (x0, x1, x2, x3,) => 0; fun apply5 = (x0, x1, x2, x3, x4,) => 0}; module List‹A, B› {}; class Cons‹A, B›(h: A, t: Cons‹A, B›,): List‹A, B› {}; module Nil‹A, B›: List‹A, B› {}; module Option‹A› {}; class Some‹A›(x: A,): Option‹A› {}; module None‹A›: Option‹A› {}; class Pair‹A, B›(x: A, y: B,) {}; class Tuple2‹A, B›(x: A, y: B,) {}; class Tuple3‹A, B, C›(x: A, y: B, z: C,) {}; module Nat {}; class S(s: Nat,): Nat {}; module O: Nat {}; class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O,) {}} +//│ +//│ Preluded. + :noTailRec :interpIR fun fact(acc, n) = @@ -11,27 +40,24 @@ fact(1, 5) //│ |#fun| |fact|(|acc|,| |n|)| |#=|→|#if| |n| |==| |0| |#then| |acc|↵|#else| |fact|(|acc| |*| |n|,| |n| |-| |1|)|←|↵|fact|(|1|,| |5|)| //│ Parsed: {fun fact = (acc, n,) => {if (==(n,)(0,)) then acc else fact(*(acc,)(n,), -(n,)(1,),)}; fact(1, 5,)} //│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, [])}, { -//│ Def(0, fact, [acc$0,n$0], -//│ 1, -//│ let x$0 = ==(n$0,0) in -- #22 -//│ if x$0 -- #21 -//│ true => -//│ jump j$0(acc$0) -- #5 -//│ false => -//│ let x$2 = *(acc$0,n$0) in -- #20 -//│ let x$3 = -(n$0,1) in -- #19 -//│ let* (x$4) = fact(x$2,x$3) in -- #18 -//│ jump j$0(x$4) -- #17 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #3 -//│ ) -//│ }, -//│ let* (x$5) = fact(1,5) in -- #30 -//│ x$5 -- #29) +//│ +//│ IR: +//│ Program: +//│ +//│ def fact(acc$0,n$0) = +//│ let x$1 = ==(n$0,0) in -- #28 +//│ if x$1 -- #27 +//│ true => +//│ jump j$0(acc$0) -- #12 +//│ false => +//│ let x$3 = *(acc$0,n$0) in -- #26 +//│ let x$4 = -(n$0,1) in -- #25 +//│ let* (x$5) = fact(x$3,x$4) in -- #24 +//│ jump j$0(x$5) -- #23 +//│ def j$0(x$2) = +//│ x$2 -- #10 +//│ let* (x$0) = fact(1,5) in -- #6 +//│ x$0 -- #5 //│ //│ Interpreted: //│ 120 @@ -45,80 +71,47 @@ fact(1, 5) //│ |@|tailrec|↵|#fun| |fact|(|acc|,| |n|)| |#=|→|#if| |n| |==| |0| |#then| |acc|↵|#else| |fact|(|acc| |*| |n|,| |n| |-| |1|)|←|↵|fact|(|1|,| |5|)| //│ Parsed: {fun fact = (acc, n,) => {if (==(n,)(0,)) then acc else fact(*(acc,)(n,), -(n,)(1,),)}; fact(1, 5,)} //│ +//│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, [])}, { -//│ Def(0, fact, [acc$0,n$0], -//│ 1, -//│ let x$0 = ==(n$0,0) in -- #22 -//│ if x$0 -- #21 -//│ true => -//│ jump j$0(acc$0) -- #5 -//│ false => -//│ let x$2 = *(acc$0,n$0) in -- #20 -//│ let x$3 = -(n$0,1) in -- #19 -//│ let* (x$4) = fact(x$2,x$3) in -- #18 -//│ jump j$0(x$4) -- #17 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #3 -//│ ) -//│ }, -//│ let* (x$5) = fact(1,5) in -- #30 -//│ x$5 -- #29) +//│ Program: +//│ +//│ def fact(acc$0,n$0) = +//│ let x$1 = ==(n$0,0) in -- #28 +//│ if x$1 -- #27 +//│ true => +//│ jump j$0(acc$0) -- #12 +//│ false => +//│ let x$3 = *(acc$0,n$0) in -- #26 +//│ let x$4 = -(n$0,1) in -- #25 +//│ let* (x$5) = fact(x$3,x$4) in -- #24 +//│ jump j$0(x$5) -- #23 +//│ def j$0(x$2) = +//│ x$2 -- #10 +//│ let* (x$0) = fact(1,5) in -- #6 +//│ x$0 -- #5 +//│ //│ //│ Strongly Connected Tail Calls: //│ List(Set(j$0), Set(fact)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #3 -//│ ) -//│ Def(2, fact_jp, [acc$0,n$0], -//│ 1, -//│ let x$0 = ==(n$0,0) in -- #36 -//│ if x$0 -- #35 -//│ true => -//│ jump j$0(acc$0) -- #31 -//│ false => -//│ let x$2 = *(acc$0,n$0) in -- #34 -//│ let x$3 = -(n$0,1) in -- #33 -//│ jump fact_jp(x$2,x$3) -- #32 -//│ ) -//│ Def(3, fact, [acc$0,n$0], -//│ 1, -//│ let* (r0) = fact_jp(acc$0,n$0) in -- #38 -//│ r0 -- #37 -//│ ) -//│ }, -//│ let* (x$5) = fact(1,5) in -- #30 -//│ x$5 -- #29) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #3 -//│ ) -//│ Def(2, fact_jp, [acc$0,n$0], -//│ 1, -//│ let x$0 = ==(n$0,0) in -- #36 -//│ if x$0 -- #35 -//│ true => -//│ jump j$0(acc$0) -- #31 -//│ false => -//│ let x$2 = *(acc$0,n$0) in -- #34 -//│ let x$3 = -(n$0,1) in -- #33 -//│ jump fact_jp(x$2,x$3) -- #32 -//│ ) -//│ Def(3, fact, [acc$0,n$0], -//│ 1, -//│ let* (r0) = fact_jp(acc$0,n$0) in -- #38 -//│ r0 -- #37 -//│ ) -//│ }, -//│ let* (x$5) = fact(1,5) in -- #30 -//│ x$5 -- #29) +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def j$0(x$2) = +//│ x$2 -- #10 +//│ def fact_jp(acc$0,n$0) = +//│ let x$1 = ==(n$0,0) in -- #40 +//│ if x$1 -- #39 +//│ true => +//│ jump j$0(acc$0) -- #35 +//│ false => +//│ let x$3 = *(acc$0,n$0) in -- #38 +//│ let x$4 = -(n$0,1) in -- #37 +//│ jump fact_jp(x$3,x$4) -- #36 +//│ def fact(acc$0,n$0) = +//│ let* (r0) = fact_jp(acc$0,n$0) in -- #42 +//│ r0 -- #41 +//│ let* (x$0) = fact(1,5) in -- #6 +//│ x$0 -- #5 //│ //│ Interpreted: //│ 120 @@ -136,117 +129,66 @@ fact(1, 5) //│ |@|tailrec|↵|#fun| |fact|(|acc|,| |n|)| |#=|→|#val| |x| |#=| |#if| |n| |>| |0| |#then| |n| |-| |1|→|#else| |0|←|↵|#if| |x| |<=| |0| |#then|→|acc|←|↵|#else| |→|@|tailcall| |fact|(|n| |*| |acc|,| |x|)| |←|←|↵|fact|(|1|,| |5|)| //│ Parsed: {fun fact = (acc, n,) => {let x = if (>(n,)(0,)) then -(n,)(1,) else 0; if (<=(x,)(0,)) then {acc} else {@tailcall fact(*(n,)(acc,), x,)}}; fact(1, 5,)} //│ +//│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, [])}, { -//│ Def(0, fact, [acc$0,n$0], -//│ 1, -//│ let x$0 = >(n$0,0) in -- #32 -//│ if x$0 -- #31 -//│ true => -//│ let x$6 = -(n$0,1) in -- #28 -//│ jump j$0(x$6,acc$0,n$0) -- #27 -//│ false => -//│ jump j$0(0,acc$0,n$0) -- #30 -//│ ) -//│ Def(1, j$1, [x$3], -//│ 1, -//│ x$3 -- #7 -//│ ) -//│ Def(2, j$0, [x$1,acc$0,n$0], -//│ 1, -//│ let x$2 = <=(x$1,0) in -- #23 -//│ if x$2 -- #22 -//│ true => -//│ jump j$1(acc$0) -- #9 -//│ false => -//│ let x$4 = *(n$0,acc$0) in -- #21 -//│ let* (x$5) = @tailcall fact(x$4,x$1) in -- #20 -//│ jump j$1(x$5) -- #19 -//│ ) -//│ }, -//│ let* (x$7) = fact(1,5) in -- #40 -//│ x$7 -- #39) +//│ Program: //│ -//│ Strongly Connected Tail Calls: -//│ List(Set(j$1), Set(fact)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(0, fact, [acc$0,n$0], -//│ 1, -//│ let* (r0) = _fact_j$0_opt$3(0,acc$0,n$0,undefined,undefined,undefined) in -- #60 -//│ r0 -- #59 -//│ ) -//│ Def(1, j$1, [x$3], -//│ 1, -//│ x$3 -- #7 -//│ ) -//│ Def(3, _fact_j$0_opt$3, [tailrecBranch$,fact_acc$0,fact_n$0,j$0_x$1,j$0_acc$0,j$0_n$0], -//│ 1, -//│ jump _fact_j$0_opt_jp$4(tailrecBranch$,fact_acc$0,fact_n$0,j$0_x$1,j$0_acc$0,j$0_n$0) -- #58 -//│ ) -//│ Def(4, _fact_j$0_opt_jp$4, [tailrecBranch$,fact_acc$0,fact_n$0,j$0_x$1,j$0_acc$0,j$0_n$0], -//│ 1, -//│ let scrut = ==(2,tailrecBranch$) in -- #57 -//│ if scrut -- #56 -//│ true => -//│ let x$2 = <=(j$0_x$1,0) in -- #55 -//│ if x$2 -- #54 -//│ true => -//│ jump j$1(j$0_acc$0) -- #51 -//│ false => -//│ let x$4 = *(j$0_n$0,j$0_acc$0) in -- #53 -//│ jump _fact_j$0_opt_jp$4(0,x$4,j$0_x$1,j$0_x$1,j$0_acc$0,j$0_n$0) -- #52 -//│ false => -//│ let x$0 = >(fact_n$0,0) in -- #50 -//│ if x$0 -- #49 +//│ def fact(acc$0,n$0) = +//│ let x$1 = >(n$0,0) in -- #38 +//│ if x$1 -- #37 //│ true => -//│ let x$6 = -(fact_n$0,1) in -- #47 -//│ jump _fact_j$0_opt_jp$4(2,fact_acc$0,fact_n$0,x$6,fact_acc$0,fact_n$0) -- #46 +//│ let x$7 = -(n$0,1) in -- #34 +//│ jump j$0(x$7,acc$0,n$0) -- #33 //│ false => -//│ jump _fact_j$0_opt_jp$4(2,fact_acc$0,fact_n$0,0,fact_acc$0,fact_n$0) -- #48 -//│ ) -//│ }, -//│ let* (x$7) = fact(1,5) in -- #40 -//│ x$7 -- #39) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(0, fact, [acc$0,n$0], -//│ 1, -//│ let* (r0) = _fact_j$0_opt$3(0,acc$0,n$0,undefined,undefined,undefined) in -- #60 -//│ r0 -- #59 -//│ ) -//│ Def(1, j$1, [x$3], -//│ 1, -//│ x$3 -- #7 -//│ ) -//│ Def(3, _fact_j$0_opt$3, [tailrecBranch$,fact_acc$0,fact_n$0,j$0_x$1,j$0_acc$0,j$0_n$0], -//│ 1, -//│ jump _fact_j$0_opt_jp$4(tailrecBranch$,fact_acc$0,fact_n$0,j$0_x$1,j$0_acc$0,j$0_n$0) -- #58 -//│ ) -//│ Def(4, _fact_j$0_opt_jp$4, [tailrecBranch$,fact_acc$0,fact_n$0,j$0_x$1,j$0_acc$0,j$0_n$0], -//│ 1, -//│ let scrut = ==(2,tailrecBranch$) in -- #57 -//│ if scrut -- #56 -//│ true => -//│ let x$2 = <=(j$0_x$1,0) in -- #55 -//│ if x$2 -- #54 +//│ jump j$0(0,acc$0,n$0) -- #36 +//│ def j$1(x$4) = +//│ x$4 -- #14 +//│ def j$0(x$2,acc$0,n$0) = +//│ let x$3 = <=(x$2,0) in -- #29 +//│ if x$3 -- #28 //│ true => -//│ jump j$1(j$0_acc$0) -- #51 +//│ jump j$1(acc$0) -- #16 //│ false => -//│ let x$4 = *(j$0_n$0,j$0_acc$0) in -- #53 -//│ jump _fact_j$0_opt_jp$4(0,x$4,j$0_x$1,j$0_x$1,j$0_acc$0,j$0_n$0) -- #52 -//│ false => -//│ let x$0 = >(fact_n$0,0) in -- #50 -//│ if x$0 -- #49 +//│ let x$5 = *(n$0,acc$0) in -- #27 +//│ let* (x$6) = @tailcall fact(x$5,x$2) in -- #26 +//│ jump j$1(x$6) -- #25 +//│ let* (x$0) = fact(1,5) in -- #6 +//│ x$0 -- #5 +//│ +//│ +//│ Strongly Connected Tail Calls: +//│ List(Set(j$1), Set(fact)) +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def fact(acc$0,n$0) = +//│ let* (r0) = _fact_j$0_opt$9(0,acc$0,n$0,true,true,true) in -- #64 +//│ r0 -- #63 +//│ def j$1(x$4) = +//│ x$4 -- #14 +//│ def _fact_j$0_opt$9(tailrecBranch$,fact_acc$0,fact_n$0,j$0_x$2,j$0_acc$0,j$0_n$0) = +//│ jump _fact_j$0_opt_jp$10(tailrecBranch$,fact_acc$0,fact_n$0,j$0_x$2,j$0_acc$0,j$0_n$0) -- #62 +//│ def _fact_j$0_opt_jp$10(tailrecBranch$,fact_acc$0,fact_n$0,j$0_x$2,j$0_acc$0,j$0_n$0) = +//│ let scrut = ==(2,tailrecBranch$) in -- #61 +//│ if scrut -- #60 //│ true => -//│ let x$6 = -(fact_n$0,1) in -- #47 -//│ jump _fact_j$0_opt_jp$4(2,fact_acc$0,fact_n$0,x$6,fact_acc$0,fact_n$0) -- #46 +//│ let x$3 = <=(j$0_x$2,0) in -- #59 +//│ if x$3 -- #58 +//│ true => +//│ jump j$1(j$0_acc$0) -- #55 +//│ false => +//│ let x$5 = *(j$0_n$0,j$0_acc$0) in -- #57 +//│ jump _fact_j$0_opt_jp$10(0,x$5,j$0_x$2,j$0_x$2,j$0_acc$0,j$0_n$0) -- #56 //│ false => -//│ jump _fact_j$0_opt_jp$4(2,fact_acc$0,fact_n$0,0,fact_acc$0,fact_n$0) -- #48 -//│ ) -//│ }, -//│ let* (x$7) = fact(1,5) in -- #40 -//│ x$7 -- #39) +//│ let x$1 = >(fact_n$0,0) in -- #54 +//│ if x$1 -- #53 +//│ true => +//│ let x$7 = -(fact_n$0,1) in -- #51 +//│ jump _fact_j$0_opt_jp$10(2,fact_acc$0,fact_n$0,x$7,fact_acc$0,fact_n$0) -- #50 +//│ false => +//│ jump _fact_j$0_opt_jp$10(2,fact_acc$0,fact_n$0,0,fact_acc$0,fact_n$0) -- #52 +//│ let* (x$0) = fact(1,5) in -- #6 +//│ x$0 -- #5 //│ //│ Interpreted: //│ 120 @@ -260,51 +202,42 @@ g(6, 0) //│ |#fun| |double|(|x|)| |#=| |x| |*| |2|↵|#fun| |f|(|n|,| |acc|)| |#=| |#if| |n| |==| |0| |#then| |double|(|acc|)| |#else| |g|(|n| |-| |1|,| |acc| |+| |1|)|↵|#fun| |g|(|m|,| |acc|)| |#=| |#if| |m| |==| |0| |#then| |-|double|(|acc|)| |#else| |f|(|m| |-| |1|,| |acc| |+| |1|)|↵|g|(|6|,| |0|)| //│ Parsed: {fun double = (x,) => *(x,)(2,); fun f = (n, acc,) => if (==(n,)(0,)) then double(acc,) else g(-(n,)(1,), +(acc,)(1,),); fun g = (m, acc,) => if (==(m,)(0,)) then -(0,)(double(acc,),) else f(-(m,)(1,), +(acc,)(1,),); g(6, 0,)} //│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, [])}, { -//│ Def(0, double, [x$0], -//│ 1, -//│ let x$1 = *(x$0,2) in -- #3 -//│ x$1 -- #2 -//│ ) -//│ Def(1, f, [n$0,acc$0], -//│ 1, -//│ let x$2 = ==(n$0,0) in -- #31 -//│ if x$2 -- #30 -//│ true => -//│ let* (x$4) = double(acc$0) in -- #14 -//│ jump j$0(x$4) -- #13 -//│ false => -//│ let x$5 = -(n$0,1) in -- #29 -//│ let x$6 = +(acc$0,1) in -- #28 -//│ let* (x$7) = g(x$5,x$6) in -- #27 -//│ jump j$0(x$7) -- #26 -//│ ) -//│ Def(2, j$0, [x$3], -//│ 1, -//│ x$3 -- #7 -//│ ) -//│ Def(3, g, [m$0,acc$1], -//│ 1, -//│ let x$8 = ==(m$0,0) in -- #62 -//│ if x$8 -- #61 -//│ true => -//│ let* (x$10) = double(acc$1) in -- #45 -//│ let x$11 = -(0,x$10) in -- #44 -//│ jump j$1(x$11) -- #43 -//│ false => -//│ let x$12 = -(m$0,1) in -- #60 -//│ let x$13 = +(acc$1,1) in -- #59 -//│ let* (x$14) = f(x$12,x$13) in -- #58 -//│ jump j$1(x$14) -- #57 -//│ ) -//│ Def(4, j$1, [x$9], -//│ 1, -//│ x$9 -- #35 -//│ ) -//│ }, -//│ let* (x$15) = g(6,0) in -- #70 -//│ x$15 -- #69) +//│ +//│ IR: +//│ Program: +//│ +//│ def double(x$1) = +//│ let x$2 = *(x$1,2) in -- #10 +//│ x$2 -- #9 +//│ def f(n$0,acc$0) = +//│ let x$3 = ==(n$0,0) in -- #36 +//│ if x$3 -- #35 +//│ true => +//│ let* (x$5) = double(acc$0) in -- #20 +//│ jump j$0(x$5) -- #19 +//│ false => +//│ let x$6 = -(n$0,1) in -- #34 +//│ let x$7 = +(acc$0,1) in -- #33 +//│ let* (x$8) = g(x$6,x$7) in -- #32 +//│ jump j$0(x$8) -- #31 +//│ def j$0(x$4) = +//│ x$4 -- #14 +//│ def g(m$0,acc$1) = +//│ let x$9 = ==(m$0,0) in -- #65 +//│ if x$9 -- #64 +//│ true => +//│ let* (x$11) = double(acc$1) in -- #49 +//│ let x$12 = -(0,x$11) in -- #48 +//│ jump j$1(x$12) -- #47 +//│ false => +//│ let x$13 = -(m$0,1) in -- #63 +//│ let x$14 = +(acc$1,1) in -- #62 +//│ let* (x$15) = f(x$13,x$14) in -- #61 +//│ jump j$1(x$15) -- #60 +//│ def j$1(x$10) = +//│ x$10 -- #40 +//│ let* (x$0) = g(6,0) in -- #6 +//│ x$0 -- #5 //│ //│ Interpreted: //│ -12 @@ -317,170 +250,90 @@ g(6, 0) //│ |#fun| |double|(|x|)| |#=| |x| |*| |2|↵|@|tailrec| |#fun| |f|(|n|,| |acc|)| |#=| |#if| |n| |==| |0| |#then| |double|(|acc|)| |#else| |g|(|n| |-| |1|,| |acc| |+| |1|)|↵|@|tailrec| |#fun| |g|(|m|,| |acc|)| |#=| |#if| |m| |==| |0| |#then| |-|double|(|acc|)| |#else| |f|(|m| |-| |1|,| |acc| |+| |1|)|↵|g|(|6|,| |0|)| //│ Parsed: {fun double = (x,) => *(x,)(2,); fun f = (n, acc,) => if (==(n,)(0,)) then double(acc,) else g(-(n,)(1,), +(acc,)(1,),); fun g = (m, acc,) => if (==(m,)(0,)) then -(0,)(double(acc,),) else f(-(m,)(1,), +(acc,)(1,),); g(6, 0,)} //│ -//│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, [])}, { -//│ Def(0, double, [x$0], -//│ 1, -//│ let x$1 = *(x$0,2) in -- #3 -//│ x$1 -- #2 -//│ ) -//│ Def(1, f, [n$0,acc$0], -//│ 1, -//│ let x$2 = ==(n$0,0) in -- #31 -//│ if x$2 -- #30 -//│ true => -//│ let* (x$4) = double(acc$0) in -- #14 -//│ jump j$0(x$4) -- #13 -//│ false => -//│ let x$5 = -(n$0,1) in -- #29 -//│ let x$6 = +(acc$0,1) in -- #28 -//│ let* (x$7) = g(x$5,x$6) in -- #27 -//│ jump j$0(x$7) -- #26 -//│ ) -//│ Def(2, j$0, [x$3], -//│ 1, -//│ x$3 -- #7 -//│ ) -//│ Def(3, g, [m$0,acc$1], -//│ 1, -//│ let x$8 = ==(m$0,0) in -- #62 -//│ if x$8 -- #61 -//│ true => -//│ let* (x$10) = double(acc$1) in -- #45 -//│ let x$11 = -(0,x$10) in -- #44 -//│ jump j$1(x$11) -- #43 -//│ false => -//│ let x$12 = -(m$0,1) in -- #60 -//│ let x$13 = +(acc$1,1) in -- #59 -//│ let* (x$14) = f(x$12,x$13) in -- #58 -//│ jump j$1(x$14) -- #57 -//│ ) -//│ Def(4, j$1, [x$9], -//│ 1, -//│ x$9 -- #35 -//│ ) -//│ }, -//│ let* (x$15) = g(6,0) in -- #70 -//│ x$15 -- #69) //│ -//│ Strongly Connected Tail Calls: -//│ List(Set(j$1), Set(j$0), Set(g, f), Set(double)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(0, double, [x$0], -//│ 1, -//│ let x$1 = *(x$0,2) in -- #3 -//│ x$1 -- #2 -//│ ) -//│ Def(1, f, [n$0,acc$0], -//│ 1, -//│ let* (r0) = _g_f_opt$5(1,undefined,undefined,n$0,acc$0) in -- #100 -//│ r0 -- #99 -//│ ) -//│ Def(2, j$0, [x$3], -//│ 1, -//│ x$3 -- #7 -//│ ) -//│ Def(3, g, [m$0,acc$1], -//│ 1, -//│ let* (r0) = _g_f_opt$5(3,m$0,acc$1,undefined,undefined) in -- #98 -//│ r0 -- #97 -//│ ) -//│ Def(4, j$1, [x$9], -//│ 1, -//│ x$9 -- #35 -//│ ) -//│ Def(5, _g_f_opt$5, [tailrecBranch$,g_m$0,g_acc$1,f_n$0,f_acc$0], -//│ 1, -//│ jump _g_f_opt_jp$6(tailrecBranch$,g_m$0,g_acc$1,f_n$0,f_acc$0) -- #96 -//│ ) -//│ Def(6, _g_f_opt_jp$6, [tailrecBranch$,g_m$0,g_acc$1,f_n$0,f_acc$0], -//│ 1, -//│ let scrut = ==(1,tailrecBranch$) in -- #95 -//│ if scrut -- #94 -//│ true => -//│ let x$2 = ==(f_n$0,0) in -- #93 -//│ if x$2 -- #92 -//│ true => -//│ let* (x$4) = double(f_acc$0) in -- #88 -//│ jump j$0(x$4) -- #87 -//│ false => -//│ let x$5 = -(f_n$0,1) in -- #91 -//│ let x$6 = +(f_acc$0,1) in -- #90 -//│ jump _g_f_opt_jp$6(3,x$5,x$6,f_n$0,f_acc$0) -- #89 -//│ false => -//│ let x$8 = ==(g_m$0,0) in -- #86 -//│ if x$8 -- #85 +//│ IR: +//│ Program: +//│ +//│ def double(x$1) = +//│ let x$2 = *(x$1,2) in -- #10 +//│ x$2 -- #9 +//│ def f(n$0,acc$0) = +//│ let x$3 = ==(n$0,0) in -- #36 +//│ if x$3 -- #35 //│ true => -//│ let* (x$10) = double(g_acc$1) in -- #81 -//│ let x$11 = -(0,x$10) in -- #80 -//│ jump j$1(x$11) -- #79 +//│ let* (x$5) = double(acc$0) in -- #20 +//│ jump j$0(x$5) -- #19 //│ false => -//│ let x$12 = -(g_m$0,1) in -- #84 -//│ let x$13 = +(g_acc$1,1) in -- #83 -//│ jump _g_f_opt_jp$6(1,g_m$0,g_acc$1,x$12,x$13) -- #82 -//│ ) -//│ }, -//│ let* (x$15) = g(6,0) in -- #70 -//│ x$15 -- #69) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(0, double, [x$0], -//│ 1, -//│ let x$1 = *(x$0,2) in -- #3 -//│ x$1 -- #2 -//│ ) -//│ Def(1, f, [n$0,acc$0], -//│ 1, -//│ let* (r0) = _g_f_opt$5(1,undefined,undefined,n$0,acc$0) in -- #100 -//│ r0 -- #99 -//│ ) -//│ Def(2, j$0, [x$3], -//│ 1, -//│ x$3 -- #7 -//│ ) -//│ Def(3, g, [m$0,acc$1], -//│ 1, -//│ let* (r0) = _g_f_opt$5(3,m$0,acc$1,undefined,undefined) in -- #98 -//│ r0 -- #97 -//│ ) -//│ Def(4, j$1, [x$9], -//│ 1, -//│ x$9 -- #35 -//│ ) -//│ Def(5, _g_f_opt$5, [tailrecBranch$,g_m$0,g_acc$1,f_n$0,f_acc$0], -//│ 1, -//│ jump _g_f_opt_jp$6(tailrecBranch$,g_m$0,g_acc$1,f_n$0,f_acc$0) -- #96 -//│ ) -//│ Def(6, _g_f_opt_jp$6, [tailrecBranch$,g_m$0,g_acc$1,f_n$0,f_acc$0], -//│ 1, -//│ let scrut = ==(1,tailrecBranch$) in -- #95 -//│ if scrut -- #94 -//│ true => -//│ let x$2 = ==(f_n$0,0) in -- #93 -//│ if x$2 -- #92 +//│ let x$6 = -(n$0,1) in -- #34 +//│ let x$7 = +(acc$0,1) in -- #33 +//│ let* (x$8) = g(x$6,x$7) in -- #32 +//│ jump j$0(x$8) -- #31 +//│ def j$0(x$4) = +//│ x$4 -- #14 +//│ def g(m$0,acc$1) = +//│ let x$9 = ==(m$0,0) in -- #65 +//│ if x$9 -- #64 //│ true => -//│ let* (x$4) = double(f_acc$0) in -- #88 -//│ jump j$0(x$4) -- #87 +//│ let* (x$11) = double(acc$1) in -- #49 +//│ let x$12 = -(0,x$11) in -- #48 +//│ jump j$1(x$12) -- #47 //│ false => -//│ let x$5 = -(f_n$0,1) in -- #91 -//│ let x$6 = +(f_acc$0,1) in -- #90 -//│ jump _g_f_opt_jp$6(3,x$5,x$6,f_n$0,f_acc$0) -- #89 -//│ false => -//│ let x$8 = ==(g_m$0,0) in -- #86 -//│ if x$8 -- #85 +//│ let x$13 = -(m$0,1) in -- #63 +//│ let x$14 = +(acc$1,1) in -- #62 +//│ let* (x$15) = f(x$13,x$14) in -- #61 +//│ jump j$1(x$15) -- #60 +//│ def j$1(x$10) = +//│ x$10 -- #40 +//│ let* (x$0) = g(6,0) in -- #6 +//│ x$0 -- #5 +//│ +//│ +//│ Strongly Connected Tail Calls: +//│ List(Set(j$1), Set(j$0), Set(g, f), Set(double)) +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def double(x$1) = +//│ let x$2 = *(x$1,2) in -- #10 +//│ x$2 -- #9 +//│ def f(n$0,acc$0) = +//│ let* (r0) = _g_f_opt$11(1,true,true,n$0,acc$0) in -- #101 +//│ r0 -- #100 +//│ def j$0(x$4) = +//│ x$4 -- #14 +//│ def g(m$0,acc$1) = +//│ let* (r0) = _g_f_opt$11(3,m$0,acc$1,true,true) in -- #99 +//│ r0 -- #98 +//│ def j$1(x$10) = +//│ x$10 -- #40 +//│ def _g_f_opt$11(tailrecBranch$,g_m$0,g_acc$1,f_n$0,f_acc$0) = +//│ jump _g_f_opt_jp$12(tailrecBranch$,g_m$0,g_acc$1,f_n$0,f_acc$0) -- #97 +//│ def _g_f_opt_jp$12(tailrecBranch$,g_m$0,g_acc$1,f_n$0,f_acc$0) = +//│ let scrut = ==(1,tailrecBranch$) in -- #96 +//│ if scrut -- #95 //│ true => -//│ let* (x$10) = double(g_acc$1) in -- #81 -//│ let x$11 = -(0,x$10) in -- #80 -//│ jump j$1(x$11) -- #79 +//│ let x$3 = ==(f_n$0,0) in -- #94 +//│ if x$3 -- #93 +//│ true => +//│ let* (x$5) = double(f_acc$0) in -- #89 +//│ jump j$0(x$5) -- #88 +//│ false => +//│ let x$6 = -(f_n$0,1) in -- #92 +//│ let x$7 = +(f_acc$0,1) in -- #91 +//│ jump _g_f_opt_jp$12(3,x$6,x$7,f_n$0,f_acc$0) -- #90 //│ false => -//│ let x$12 = -(g_m$0,1) in -- #84 -//│ let x$13 = +(g_acc$1,1) in -- #83 -//│ jump _g_f_opt_jp$6(1,g_m$0,g_acc$1,x$12,x$13) -- #82 -//│ ) -//│ }, -//│ let* (x$15) = g(6,0) in -- #70 -//│ x$15 -- #69) +//│ let x$9 = ==(g_m$0,0) in -- #87 +//│ if x$9 -- #86 +//│ true => +//│ let* (x$11) = double(g_acc$1) in -- #82 +//│ let x$12 = -(0,x$11) in -- #81 +//│ jump j$1(x$12) -- #80 +//│ false => +//│ let x$13 = -(g_m$0,1) in -- #85 +//│ let x$14 = +(g_acc$1,1) in -- #84 +//│ jump _g_f_opt_jp$12(1,g_m$0,g_acc$1,x$13,x$14) -- #83 +//│ let* (x$0) = g(6,0) in -- #6 +//│ x$0 -- #5 //│ //│ Interpreted: //│ -12 @@ -492,102 +345,51 @@ g(6, 0) //│ |@|tailrec| |#fun| |f|(|a|,| |b|,| |c|)| |#=| |g|(|0|,| |0|)|↵|@|tailrec| |#fun| |g|(|d|,| |e|)| |#=| |h|(|0|,| |0|,| |0|,| |0|)|↵|@|tailrec| |#fun| |h|(|p|,| |q|,| |r|,| |s|)| |#=| |f|(|0|,| |0|,| |0|)|↵|2| | //│ Parsed: {fun f = (a, b, c,) => g(0, 0,); fun g = (d, e,) => h(0, 0, 0, 0,); fun h = (p, q, r, s,) => f(0, 0, 0,); 2} //│ +//│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, [])}, { -//│ Def(0, f, [a$0,b$0,c$0], -//│ 1, -//│ let* (x$0) = g(0,0) in -- #7 -//│ x$0 -- #6 -//│ ) -//│ Def(1, g, [d$0,e$0], -//│ 1, -//│ let* (x$1) = h(0,0,0,0) in -- #19 -//│ x$1 -- #18 -//│ ) -//│ Def(2, h, [p$0,q$0,r$0,s$0], -//│ 1, -//│ let* (x$2) = f(0,0,0) in -- #29 -//│ x$2 -- #28 -//│ ) -//│ }, -//│ 2 -- #30) +//│ Program: +//│ +//│ def f(a$0,b$0,c$0) = +//│ let* (x$0) = g(0,0) in -- #7 +//│ x$0 -- #6 +//│ def g(d$0,e$0) = +//│ let* (x$1) = h(0,0,0,0) in -- #18 +//│ x$1 -- #17 +//│ def h(p$0,q$0,r$0,s$0) = +//│ let* (x$2) = f(0,0,0) in -- #27 +//│ x$2 -- #26 +//│ 2 -- #0 +//│ //│ //│ Strongly Connected Tail Calls: //│ List(Set(h, g, f)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(0, f, [a$0,b$0,c$0], -//│ 1, -//│ let* (r0) = _h_g_f_opt$3(0,undefined,undefined,undefined,undefined,undefined,undefined,a$0,b$0,c$0) in -- #45 -//│ r0 -- #44 -//│ ) -//│ Def(1, g, [d$0,e$0], -//│ 1, -//│ let* (r0) = _h_g_f_opt$3(1,undefined,undefined,undefined,undefined,d$0,e$0,undefined,undefined,undefined) in -- #43 -//│ r0 -- #42 -//│ ) -//│ Def(2, h, [p$0,q$0,r$0,s$0], -//│ 1, -//│ let* (r0) = _h_g_f_opt$3(2,p$0,q$0,r$0,s$0,undefined,undefined,undefined,undefined,undefined) in -- #41 -//│ r0 -- #40 -//│ ) -//│ Def(3, _h_g_f_opt$3, [tailrecBranch$,h_p$0,h_q$0,h_r$0,h_s$0,g_d$0,g_e$0,f_a$0,f_b$0,f_c$0], -//│ 1, -//│ jump _h_g_f_opt_jp$4(tailrecBranch$,h_p$0,h_q$0,h_r$0,h_s$0,g_d$0,g_e$0,f_a$0,f_b$0,f_c$0) -- #39 -//│ ) -//│ Def(4, _h_g_f_opt_jp$4, [tailrecBranch$,h_p$0,h_q$0,h_r$0,h_s$0,g_d$0,g_e$0,f_a$0,f_b$0,f_c$0], -//│ 1, -//│ let scrut = ==(0,tailrecBranch$) in -- #38 -//│ if scrut -- #37 -//│ true => -//│ jump _h_g_f_opt_jp$4(1,h_p$0,h_q$0,h_r$0,h_s$0,0,0,f_a$0,f_b$0,f_c$0) -- #34 -//│ false => -//│ let scrut = ==(1,tailrecBranch$) in -- #36 -//│ if scrut -- #35 -//│ true => -//│ jump _h_g_f_opt_jp$4(2,0,0,0,0,g_d$0,g_e$0,f_a$0,f_b$0,f_c$0) -- #33 -//│ false => -//│ jump _h_g_f_opt_jp$4(0,h_p$0,h_q$0,h_r$0,h_s$0,g_d$0,g_e$0,0,0,0) -- #32 -//│ ) -//│ }, -//│ 2 -- #30) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(0, f, [a$0,b$0,c$0], -//│ 1, -//│ let* (r0) = _h_g_f_opt$3(0,undefined,undefined,undefined,undefined,undefined,undefined,a$0,b$0,c$0) in -- #45 -//│ r0 -- #44 -//│ ) -//│ Def(1, g, [d$0,e$0], -//│ 1, -//│ let* (r0) = _h_g_f_opt$3(1,undefined,undefined,undefined,undefined,d$0,e$0,undefined,undefined,undefined) in -- #43 -//│ r0 -- #42 -//│ ) -//│ Def(2, h, [p$0,q$0,r$0,s$0], -//│ 1, -//│ let* (r0) = _h_g_f_opt$3(2,p$0,q$0,r$0,s$0,undefined,undefined,undefined,undefined,undefined) in -- #41 -//│ r0 -- #40 -//│ ) -//│ Def(3, _h_g_f_opt$3, [tailrecBranch$,h_p$0,h_q$0,h_r$0,h_s$0,g_d$0,g_e$0,f_a$0,f_b$0,f_c$0], -//│ 1, -//│ jump _h_g_f_opt_jp$4(tailrecBranch$,h_p$0,h_q$0,h_r$0,h_s$0,g_d$0,g_e$0,f_a$0,f_b$0,f_c$0) -- #39 -//│ ) -//│ Def(4, _h_g_f_opt_jp$4, [tailrecBranch$,h_p$0,h_q$0,h_r$0,h_s$0,g_d$0,g_e$0,f_a$0,f_b$0,f_c$0], -//│ 1, -//│ let scrut = ==(0,tailrecBranch$) in -- #38 -//│ if scrut -- #37 -//│ true => -//│ jump _h_g_f_opt_jp$4(1,h_p$0,h_q$0,h_r$0,h_s$0,0,0,f_a$0,f_b$0,f_c$0) -- #34 -//│ false => -//│ let scrut = ==(1,tailrecBranch$) in -- #36 -//│ if scrut -- #35 +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def f(a$0,b$0,c$0) = +//│ let* (r0) = _h_g_f_opt$9(0,true,true,true,true,true,true,a$0,b$0,c$0) in -- #48 +//│ r0 -- #47 +//│ def g(d$0,e$0) = +//│ let* (r0) = _h_g_f_opt$9(1,true,true,true,true,d$0,e$0,true,true,true) in -- #46 +//│ r0 -- #45 +//│ def h(p$0,q$0,r$0,s$0) = +//│ let* (r0) = _h_g_f_opt$9(2,p$0,q$0,r$0,s$0,true,true,true,true,true) in -- #44 +//│ r0 -- #43 +//│ def _h_g_f_opt$9(tailrecBranch$,h_p$0,h_q$0,h_r$0,h_s$0,g_d$0,g_e$0,f_a$0,f_b$0,f_c$0) = +//│ jump _h_g_f_opt_jp$10(tailrecBranch$,h_p$0,h_q$0,h_r$0,h_s$0,g_d$0,g_e$0,f_a$0,f_b$0,f_c$0) -- #42 +//│ def _h_g_f_opt_jp$10(tailrecBranch$,h_p$0,h_q$0,h_r$0,h_s$0,g_d$0,g_e$0,f_a$0,f_b$0,f_c$0) = +//│ let scrut = ==(0,tailrecBranch$) in -- #41 +//│ if scrut -- #40 //│ true => -//│ jump _h_g_f_opt_jp$4(2,0,0,0,0,g_d$0,g_e$0,f_a$0,f_b$0,f_c$0) -- #33 +//│ jump _h_g_f_opt_jp$10(1,h_p$0,h_q$0,h_r$0,h_s$0,0,0,f_a$0,f_b$0,f_c$0) -- #37 //│ false => -//│ jump _h_g_f_opt_jp$4(0,h_p$0,h_q$0,h_r$0,h_s$0,g_d$0,g_e$0,0,0,0) -- #32 -//│ ) -//│ }, -//│ 2 -- #30) +//│ let scrut = ==(1,tailrecBranch$) in -- #39 +//│ if scrut -- #38 +//│ true => +//│ jump _h_g_f_opt_jp$10(2,0,0,0,0,g_d$0,g_e$0,f_a$0,f_b$0,f_c$0) -- #36 +//│ false => +//│ jump _h_g_f_opt_jp$10(0,h_p$0,h_q$0,h_r$0,h_s$0,g_d$0,g_e$0,0,0,0) -- #35 +//│ 2 -- #0 :ce fun hello() = @@ -598,48 +400,35 @@ hello() //│ |#fun| |hello|(||)| |#=|→|@|tailcall| |hello|(||)|↵|@|tailcall| |hello|(||)|↵|2|←|↵|hello|(||)| | //│ Parsed: {fun hello = () => {@tailcall hello(); @tailcall hello(); 2}; hello()} //│ +//│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, [])}, { -//│ Def(0, hello, [], -//│ 1, -//│ let* (x$0) = @tailcall hello() in -- #8 -//│ let* (x$1) = @tailcall hello() in -- #7 -//│ 2 -- #6 -//│ ) -//│ }, -//│ let* (x$2) = hello() in -- #12 -//│ x$2 -- #11) +//│ Program: +//│ +//│ def hello() = +//│ let* (x$1) = @tailcall hello() in -- #9 +//│ let* (x$2) = @tailcall hello() in -- #8 +//│ 2 -- #7 +//│ let* (x$0) = hello() in -- #2 +//│ x$0 -- #1 //│ ╔══[COMPILATION ERROR] not a tail call, as the remaining functions may be impure -//│ ║ l.594: @tailcall hello() +//│ ║ l.396: @tailcall hello() //│ ╙── ^^^^^ //│ ╔══[COMPILATION ERROR] not a tail call -//│ ║ l.595: @tailcall hello() +//│ ║ l.397: @tailcall hello() //│ ╙── ^^^^^ //│ +//│ //│ Strongly Connected Tail Calls: //│ List(Set(hello)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(0, hello, [], -//│ 1, -//│ let* (x$0) = @tailcall hello() in -- #8 -//│ let* (x$1) = @tailcall hello() in -- #7 -//│ 2 -- #6 -//│ ) -//│ }, -//│ let* (x$2) = hello() in -- #12 -//│ x$2 -- #11) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(0, hello, [], -//│ 1, -//│ let* (x$0) = @tailcall hello() in -- #8 -//│ let* (x$1) = @tailcall hello() in -- #7 -//│ 2 -- #6 -//│ ) -//│ }, -//│ let* (x$2) = hello() in -- #12 -//│ x$2 -- #11) +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def hello() = +//│ let* (x$1) = @tailcall hello() in -- #9 +//│ let* (x$2) = @tailcall hello() in -- #8 +//│ 2 -- #7 +//│ let* (x$0) = hello() in -- #2 +//│ x$0 -- #1 :ce fun hello() = @@ -649,209 +438,120 @@ hello() //│ |#fun| |hello|(||)| |#=|→|@|tailcall| |hello|(||)|↵|2|←|↵|hello|(||)| | //│ Parsed: {fun hello = () => {@tailcall hello(); 2}; hello()} //│ +//│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, [])}, { -//│ Def(0, hello, [], -//│ 1, -//│ let* (x$0) = @tailcall hello() in -- #4 -//│ 2 -- #3 -//│ ) -//│ }, -//│ let* (x$1) = hello() in -- #8 -//│ x$1 -- #7) +//│ Program: +//│ +//│ def hello() = +//│ let* (x$1) = @tailcall hello() in -- #6 +//│ 2 -- #5 +//│ let* (x$0) = hello() in -- #2 +//│ x$0 -- #1 //│ ╔══[COMPILATION ERROR] not a tail call -//│ ║ l.646: @tailcall hello() +//│ ║ l.435: @tailcall hello() //│ ╙── ^^^^^ //│ +//│ //│ Strongly Connected Tail Calls: //│ List(Set(hello)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(0, hello, [], -//│ 1, -//│ let* (x$0) = @tailcall hello() in -- #4 -//│ 2 -- #3 -//│ ) -//│ }, -//│ let* (x$1) = hello() in -- #8 -//│ x$1 -- #7) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(0, hello, [], -//│ 1, -//│ let* (x$0) = @tailcall hello() in -- #4 -//│ 2 -- #3 -//│ ) -//│ }, -//│ let* (x$1) = hello() in -- #8 -//│ x$1 -- #7) +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def hello() = +//│ let* (x$1) = @tailcall hello() in -- #6 +//│ 2 -- #5 +//│ let* (x$0) = hello() in -- #2 +//│ x$0 -- #1 :interpIR -class Cons(h, t) -class Nil @tailrec fun addOne(xs) = if xs is Cons(h, t) then Cons(h + 1, @tailcall addOne(t)) Nil then Nil addOne(Cons(1, Cons(2, Cons(3, Nil)))) -//│ |#class| |Cons|(|h|,| |t|)|↵|#class| |Nil|↵|@|tailrec| |#fun| |addOne|(|xs|)| |#=|→|#if| |xs| |is|→|Cons|(|h|,| |t|)| |#then| |Cons|(|h| |+| |1|,| |@|tailcall| |addOne|(|t|)|)|↵|Nil| |#then| |Nil|←|←|↵|addOne|(|Cons|(|1|,| |Cons|(|2|,| |Cons|(|3|,| |Nil|)|)|)|)| -//│ Parsed: {class Cons(h, t,) {}; class Nil {}; fun addOne = (xs,) => {if xs is ‹(Cons(h, t,)) then Cons(+(h,)(1,), @tailcall addOne(t,),); (Nil) then Nil›}; addOne(Cons(1, Cons(2, Cons(3, Nil,),),),)} +//│ |@|tailrec| |#fun| |addOne|(|xs|)| |#=|→|#if| |xs| |is|→|Cons|(|h|,| |t|)| |#then| |Cons|(|h| |+| |1|,| |@|tailcall| |addOne|(|t|)|)|↵|Nil| |#then| |Nil|←|←|↵|addOne|(|Cons|(|1|,| |Cons|(|2|,| |Cons|(|3|,| |Nil|)|)|)|)| +//│ Parsed: {fun addOne = (xs,) => {if xs is ‹(Cons(h, t,)) then Cons(+(h,)(1,), @tailcall addOne(t,),); (Nil) then Nil›}; addOne(Cons(1, Cons(2, Cons(3, Nil,),),),)} +//│ //│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Cons, [h,t]),ClassInfo(3, Nil, [])}, { -//│ Def(0, addOne, [xs$0], -//│ 1, -//│ case xs$0 of -- #27 -//│ Cons => -//│ let x$1 = xs$0.t in -- #23 -//│ let x$2 = xs$0.h in -- #22 -//│ let x$3 = +(x$2,1) in -- #21 -//│ let* (x$4) = @tailcall addOne(x$1) in -- #20 -//│ let x$5 = Cons(x$3,x$4) in -- #19 -//│ jump j$0(x$5) -- #18 -//│ Nil => -//│ let x$6 = Nil() in -- #26 -//│ jump j$0(x$6) -- #25 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ }, -//│ let x$7 = Nil() in -- #52 -//│ let x$8 = Cons(3,x$7) in -- #51 -//│ let x$9 = Cons(2,x$8) in -- #50 -//│ let x$10 = Cons(1,x$9) in -- #49 -//│ let* (x$11) = addOne(x$10) in -- #48 -//│ x$11 -- #47) +//│ Program: +//│ +//│ def addOne(xs$0) = +//│ case xs$0 of -- #54 +//│ Cons => +//│ let x$6 = Cons.t(xs$0) in -- #50 +//│ let x$7 = Cons.h(xs$0) in -- #49 +//│ let x$8 = +(x$7,1) in -- #48 +//│ let* (x$9) = @tailcall addOne(x$6) in -- #47 +//│ let x$10 = Cons(x$8,x$9) in -- #46 +//│ jump j$0(x$10) -- #45 +//│ Nil => +//│ let x$11 = Nil() in -- #53 +//│ jump j$0(x$11) -- #52 +//│ def j$0(x$5) = +//│ x$5 -- #25 +//│ let x$0 = Nil() in -- #23 +//│ let x$1 = Cons(3,x$0) in -- #22 +//│ let x$2 = Cons(2,x$1) in -- #21 +//│ let x$3 = Cons(1,x$2) in -- #20 +//│ let* (x$4) = addOne(x$3) in -- #19 +//│ x$4 -- #18 +//│ //│ //│ Strongly Connected Tail Calls: //│ List(Set(j$0), Set(addOne)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Cons, [h,t]),ClassInfo(3, Nil, []),ClassInfo(4, _IdContext, []),ClassInfo(5, _Context, [acc,ptr,field])}, { -//│ Def(0, addOne, [xs$0], -//│ 1, -//│ let idCtx = _IdContext() in -- #80 -//│ let* (res) = addOne_modcons$4(idCtx,xs$0) in -- #79 -//│ res -- #78 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, _addOne_ctx_app$2, [ctx,x], -//│ 1, -//│ case ctx of -- #59 -//│ _IdContext => -//│ x -- #58 -//│ _Context => -//│ let field = ctx.field in -- #57 -//│ let ptr = ctx.ptr in -- #56 -//│ let _ = assign ptr.t := x in -- #55 -//│ let acc = ctx.acc in -- #54 -//│ acc -- #53 -//│ ) -//│ Def(3, _addOne_ctx_comp$3, [ctx1,ctx2], -//│ 1, -//│ let ctx2acc = ctx2.acc in -- #65 -//│ let ctx2ptr = ctx2.ptr in -- #64 -//│ let ctx2field = ctx2.field in -- #63 -//│ let* (newAcc) = _addOne_ctx_app$2(ctx1,ctx2acc) in -- #62 -//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #61 -//│ ret -- #60 -//│ ) -//│ Def(5, addOne_modcons$4_jp, [ctx,xs$0], -//│ 1, -//│ case xs$0 of -- #91 -//│ Cons => -//│ let x$1 = xs$0.t in -- #87 -//│ let x$2 = xs$0.h in -- #86 -//│ let x$3 = +(x$2,1) in -- #85 -//│ let x$5 = Cons(x$3,0) in -- #84 -//│ let ctx2 = _Context(x$5,x$5,0) in -- #83 -//│ let* (composed) = _addOne_ctx_comp$3(ctx,ctx2) in -- #82 -//│ jump addOne_modcons$4_jp(composed,x$1) -- #81 -//│ Nil => -//│ let x$6 = Nil() in -- #90 -//│ let* (res) = _addOne_ctx_app$2(ctx,x$6) in -- #89 -//│ res -- #88 -//│ ) -//│ Def(6, addOne_modcons$4, [ctx,xs$0], -//│ 1, -//│ let* (r0) = addOne_modcons$4_jp(ctx,xs$0) in -- #93 -//│ r0 -- #92 -//│ ) -//│ }, -//│ let x$7 = Nil() in -- #52 -//│ let x$8 = Cons(3,x$7) in -- #51 -//│ let x$9 = Cons(2,x$8) in -- #50 -//│ let x$10 = Cons(1,x$9) in -- #49 -//│ let* (x$11) = addOne(x$10) in -- #48 -//│ x$11 -- #47) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Cons, [h,t]),ClassInfo(3, Nil, []),ClassInfo(4, _IdContext, []),ClassInfo(5, _Context, [acc,ptr,field])}, { -//│ Def(0, addOne, [xs$0], -//│ 1, -//│ let idCtx = _IdContext() in -- #80 -//│ let* (res) = addOne_modcons$4(idCtx,xs$0) in -- #79 -//│ res -- #78 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, _addOne_ctx_app$2, [ctx,x], -//│ 1, -//│ case ctx of -- #59 -//│ _IdContext => -//│ x -- #58 -//│ _Context => -//│ let field = ctx.field in -- #57 -//│ let ptr = ctx.ptr in -- #56 -//│ let _ = assign ptr.t := x in -- #55 -//│ let acc = ctx.acc in -- #54 -//│ acc -- #53 -//│ ) -//│ Def(3, _addOne_ctx_comp$3, [ctx1,ctx2], -//│ 1, -//│ let ctx2acc = ctx2.acc in -- #65 -//│ let ctx2ptr = ctx2.ptr in -- #64 -//│ let ctx2field = ctx2.field in -- #63 -//│ let* (newAcc) = _addOne_ctx_app$2(ctx1,ctx2acc) in -- #62 -//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #61 -//│ ret -- #60 -//│ ) -//│ Def(5, addOne_modcons$4_jp, [ctx,xs$0], -//│ 1, -//│ case xs$0 of -- #91 -//│ Cons => -//│ let x$1 = xs$0.t in -- #87 -//│ let x$2 = xs$0.h in -- #86 -//│ let x$3 = +(x$2,1) in -- #85 -//│ let x$5 = Cons(x$3,0) in -- #84 -//│ let ctx2 = _Context(x$5,x$5,0) in -- #83 -//│ let* (composed) = _addOne_ctx_comp$3(ctx,ctx2) in -- #82 -//│ jump addOne_modcons$4_jp(composed,x$1) -- #81 -//│ Nil => -//│ let x$6 = Nil() in -- #90 -//│ let* (res) = _addOne_ctx_app$2(ctx,x$6) in -- #89 -//│ res -- #88 -//│ ) -//│ Def(6, addOne_modcons$4, [ctx,xs$0], -//│ 1, -//│ let* (r0) = addOne_modcons$4_jp(ctx,xs$0) in -- #93 -//│ r0 -- #92 -//│ ) -//│ }, -//│ let x$7 = Nil() in -- #52 -//│ let x$8 = Cons(3,x$7) in -- #51 -//│ let x$9 = Cons(2,x$8) in -- #50 -//│ let x$10 = Cons(1,x$9) in -- #49 -//│ let* (x$11) = addOne(x$10) in -- #48 -//│ x$11 -- #47) +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def addOne(xs$0) = +//│ let idCtx = _IdContext() in -- #88 +//│ let* (res) = addOne_modcons$10(idCtx,xs$0) in -- #87 +//│ res -- #86 +//│ def j$0(x$5) = +//│ x$5 -- #25 +//│ def _addOne_ctx_app$8(ctx,x) = +//│ case ctx of -- #67 +//│ _IdContext => +//│ x -- #66 +//│ _Context => +//│ let field = _Context.field(ctx) in -- #65 +//│ let ptr = _Context.ptr(ctx) in -- #64 +//│ let _ = assign ptr.t := x in -- #63 +//│ let acc = _Context.acc(ctx) in -- #62 +//│ acc -- #61 +//│ def _addOne_ctx_comp$9(ctx1,ctx2) = +//│ let ctx2acc = _Context.acc(ctx2) in -- #73 +//│ let ctx2ptr = _Context.ptr(ctx2) in -- #72 +//│ let ctx2field = _Context.field(ctx2) in -- #71 +//│ let* (newAcc) = _addOne_ctx_app$8(ctx1,ctx2acc) in -- #70 +//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #69 +//│ ret -- #68 +//│ def addOne_modcons$10_jp(ctx,xs$0) = +//│ case xs$0 of -- #99 +//│ Cons => +//│ let x$6 = Cons.t(xs$0) in -- #95 +//│ let x$7 = Cons.h(xs$0) in -- #94 +//│ let x$8 = +(x$7,1) in -- #93 +//│ let x$10 = Cons(x$8,0) in -- #92 +//│ let ctx2 = _Context(x$10,x$10,0) in -- #91 +//│ let* (composed) = _addOne_ctx_comp$9(ctx,ctx2) in -- #90 +//│ jump addOne_modcons$10_jp(composed,x$6) -- #89 +//│ Nil => +//│ let x$11 = Nil() in -- #98 +//│ let* (res) = _addOne_ctx_app$8(ctx,x$11) in -- #97 +//│ res -- #96 +//│ def addOne_modcons$10(ctx,xs$0) = +//│ let* (r0) = addOne_modcons$10_jp(ctx,xs$0) in -- #101 +//│ r0 -- #100 +//│ let x$0 = Nil() in -- #23 +//│ let x$1 = Cons(3,x$0) in -- #22 +//│ let x$2 = Cons(2,x$1) in -- #21 +//│ let x$3 = Cons(1,x$2) in -- #20 +//│ let* (x$4) = addOne(x$3) in -- #19 +//│ x$4 -- #18 //│ //│ Interpreted: -//│ Cons(2,Cons(3,Cons(4,Nil()))) +//│ Cons(2,0) :noTailRec :interpIR @@ -869,51 +569,44 @@ a(S(S(S(Zero)))) //│ |#class| |Zero|↵|#class| |S|(|x|)|↵|#fun| |a|(|n|)| |#=|→|#if| |n| |is|→|S|(|x|)| |#then| |S|(|@|tailcall| |b|(|x|)|)|↵|Zero| |#then| |S|(|Zero|)|←|←|↵|#fun| |b|(|n|)| |#=|→|#if| |n| |is|→|S|(|x|)| |#then| |S|(|S|(|@|tailcall| |a|(|x|)|)|)|↵|Zero| |#then| |S|(|S|(|Zero|)|)|←|←|↵|a|(|S|(|S|(|S|(|Zero|)|)|)|)| //│ Parsed: {class Zero {}; class S(x,) {}; fun a = (n,) => {if n is ‹(S(x,)) then S(@tailcall b(x,),); (Zero) then S(Zero,)›}; fun b = (n,) => {if n is ‹(S(x,)) then S(S(@tailcall a(x,),),); (Zero) then S(S(Zero,),)›}; a(S(S(S(Zero,),),),)} //│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Zero, []),ClassInfo(3, S, [x])}, { -//│ Def(0, a, [n$0], -//│ 1, -//│ case n$0 of -- #23 -//│ S => -//│ let x$1 = n$0.x in -- #15 -//│ let* (x$2) = @tailcall b(x$1) in -- #14 -//│ let x$3 = S(x$2) in -- #13 -//│ jump j$0(x$3) -- #12 -//│ Zero => -//│ let x$4 = Zero() in -- #22 -//│ let x$5 = S(x$4) in -- #21 -//│ jump j$0(x$5) -- #20 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, b, [n$1], -//│ 1, -//│ case n$1 of -- #55 -//│ S => -//│ let x$7 = n$1.x in -- #43 -//│ let* (x$8) = @tailcall a(x$7) in -- #42 -//│ let x$9 = S(x$8) in -- #41 -//│ let x$10 = S(x$9) in -- #40 -//│ jump j$1(x$10) -- #39 -//│ Zero => -//│ let x$11 = Zero() in -- #54 -//│ let x$12 = S(x$11) in -- #53 -//│ let x$13 = S(x$12) in -- #52 -//│ jump j$1(x$13) -- #51 -//│ ) -//│ Def(3, j$1, [x$6], -//│ 1, -//│ x$6 -- #25 -//│ ) -//│ }, -//│ let x$14 = Zero() in -- #74 -//│ let x$15 = S(x$14) in -- #73 -//│ let x$16 = S(x$15) in -- #72 -//│ let x$17 = S(x$16) in -- #71 -//│ let* (x$18) = a(x$17) in -- #70 -//│ x$18 -- #69) +//│ +//│ IR: +//│ Program: +//│ class Zero() +//│ def a(n$0) = +//│ case n$0 of -- #42 +//│ S => +//│ let x$6 = S.s(n$0) in -- #34 +//│ let* (x$7) = @tailcall b(x$6) in -- #33 +//│ let x$8 = S(x$7) in -- #32 +//│ jump j$0(x$8) -- #31 +//│ Zero => +//│ let x$9 = Zero() in -- #41 +//│ let x$10 = S(x$9) in -- #40 +//│ jump j$0(x$10) -- #39 +//│ def j$0(x$5) = +//│ x$5 -- #19 +//│ def b(n$1) = +//│ case n$1 of -- #75 +//│ S => +//│ let x$12 = S.s(n$1) in -- #63 +//│ let* (x$13) = @tailcall a(x$12) in -- #62 +//│ let x$14 = S(x$13) in -- #61 +//│ let x$15 = S(x$14) in -- #60 +//│ jump j$1(x$15) -- #59 +//│ Zero => +//│ let x$16 = Zero() in -- #74 +//│ let x$17 = S(x$16) in -- #73 +//│ let x$18 = S(x$17) in -- #72 +//│ jump j$1(x$18) -- #71 +//│ def j$1(x$11) = +//│ x$11 -- #44 +//│ let x$0 = Zero() in -- #17 +//│ let x$1 = S(x$0) in -- #16 +//│ let x$2 = S(x$1) in -- #15 +//│ let x$3 = S(x$2) in -- #14 +//│ let* (x$4) = a(x$3) in -- #13 +//│ x$4 -- #12 //│ //│ Interpreted: //│ S(S(S(S(S(S(Zero())))))) @@ -933,255 +626,131 @@ a(S(S(S(Zero)))) //│ |#class| |Zero|↵|#class| |S|(|x|)|↵|@|tailrec| |#fun| |a|(|n|)| |#=|→|#if| |n| |is|→|S|(|x|)| |#then| |S|(|@|tailcall| |b|(|x|)|)|↵|Zero| |#then| |S|(|Zero|)|←|←|↵|@|tailrec| |#fun| |b|(|n|)| |#=|→|#if| |n| |is|→|S|(|x|)| |#then| |S|(|S|(|@|tailcall| |a|(|x|)|)|)|↵|Zero| |#then| |S|(|S|(|Zero|)|)|←|←|↵|a|(|S|(|S|(|S|(|Zero|)|)|)|)| //│ Parsed: {class Zero {}; class S(x,) {}; fun a = (n,) => {if n is ‹(S(x,)) then S(@tailcall b(x,),); (Zero) then S(Zero,)›}; fun b = (n,) => {if n is ‹(S(x,)) then S(S(@tailcall a(x,),),); (Zero) then S(S(Zero,),)›}; a(S(S(S(Zero,),),),)} //│ -//│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Zero, []),ClassInfo(3, S, [x])}, { -//│ Def(0, a, [n$0], -//│ 1, -//│ case n$0 of -- #23 -//│ S => -//│ let x$1 = n$0.x in -- #15 -//│ let* (x$2) = @tailcall b(x$1) in -- #14 -//│ let x$3 = S(x$2) in -- #13 -//│ jump j$0(x$3) -- #12 -//│ Zero => -//│ let x$4 = Zero() in -- #22 -//│ let x$5 = S(x$4) in -- #21 -//│ jump j$0(x$5) -- #20 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, b, [n$1], -//│ 1, -//│ case n$1 of -- #55 -//│ S => -//│ let x$7 = n$1.x in -- #43 -//│ let* (x$8) = @tailcall a(x$7) in -- #42 -//│ let x$9 = S(x$8) in -- #41 -//│ let x$10 = S(x$9) in -- #40 -//│ jump j$1(x$10) -- #39 -//│ Zero => -//│ let x$11 = Zero() in -- #54 -//│ let x$12 = S(x$11) in -- #53 -//│ let x$13 = S(x$12) in -- #52 -//│ jump j$1(x$13) -- #51 -//│ ) -//│ Def(3, j$1, [x$6], -//│ 1, -//│ x$6 -- #25 -//│ ) -//│ }, -//│ let x$14 = Zero() in -- #74 -//│ let x$15 = S(x$14) in -- #73 -//│ let x$16 = S(x$15) in -- #72 -//│ let x$17 = S(x$16) in -- #71 -//│ let* (x$18) = a(x$17) in -- #70 -//│ x$18 -- #69) //│ -//│ Strongly Connected Tail Calls: -//│ List(Set(j$1), Set(j$0), Set(b, a)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Zero, []),ClassInfo(3, S, [x]),ClassInfo(4, _IdContext, []),ClassInfo(5, _Context, [acc,ptr,field])}, { -//│ Def(0, a, [n$0], -//│ 1, -//│ let idCtx = _IdContext() in -- #117 -//│ let* (res) = a_modcons$7(idCtx,n$0) in -- #116 -//│ res -- #115 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, b, [n$1], -//│ 1, -//│ let idCtx = _IdContext() in -- #103 -//│ let* (res) = b_modcons$6(idCtx,n$1) in -- #102 -//│ res -- #101 -//│ ) -//│ Def(3, j$1, [x$6], -//│ 1, -//│ x$6 -- #25 -//│ ) -//│ Def(4, _b_a_ctx_app$4, [ctx,x], -//│ 1, -//│ case ctx of -- #81 -//│ _IdContext => -//│ x -- #80 -//│ _Context => -//│ let field = ctx.field in -- #79 -//│ let ptr = ctx.ptr in -- #78 -//│ let _ = assign ptr.x := x in -- #77 -//│ let acc = ctx.acc in -- #76 -//│ acc -- #75 -//│ ) -//│ Def(5, _b_a_ctx_comp$5, [ctx1,ctx2], -//│ 1, -//│ let ctx2acc = ctx2.acc in -- #87 -//│ let ctx2ptr = ctx2.ptr in -- #86 -//│ let ctx2field = ctx2.field in -- #85 -//│ let* (newAcc) = _b_a_ctx_app$4(ctx1,ctx2acc) in -- #84 -//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #83 -//│ ret -- #82 -//│ ) -//│ Def(6, b_modcons$6, [ctx,n$1], -//│ 1, -//│ let* (r0) = _b_modcons$6_a_modcons$7_opt$8(6,ctx,n$1,undefined,undefined) in -- #156 -//│ r0 -- #155 -//│ ) -//│ Def(7, a_modcons$7, [ctx,n$0], -//│ 1, -//│ let* (r0) = _b_modcons$6_a_modcons$7_opt$8(7,undefined,undefined,ctx,n$0) in -- #158 -//│ r0 -- #157 -//│ ) -//│ Def(8, _b_modcons$6_a_modcons$7_opt$8, [tailrecBranch$,b_modcons$6_ctx,b_modcons$6_n$1,a_modcons$7_ctx,a_modcons$7_n$0], -//│ 1, -//│ jump _b_modcons$6_a_modcons$7_opt_jp$9(tailrecBranch$,b_modcons$6_ctx,b_modcons$6_n$1,a_modcons$7_ctx,a_modcons$7_n$0) -- #154 -//│ ) -//│ Def(9, _b_modcons$6_a_modcons$7_opt_jp$9, [tailrecBranch$,b_modcons$6_ctx,b_modcons$6_n$1,a_modcons$7_ctx,a_modcons$7_n$0], -//│ 1, -//│ let scrut = ==(7,tailrecBranch$) in -- #153 -//│ if scrut -- #152 -//│ true => -//│ case a_modcons$7_n$0 of -- #151 -//│ S => -//│ let x$1 = a_modcons$7_n$0.x in -- #146 -//│ let x$3 = S(0) in -- #145 -//│ let ctx2 = _Context(x$3,x$3,0) in -- #144 -//│ let* (composed) = _b_a_ctx_comp$5(a_modcons$7_ctx,ctx2) in -- #143 -//│ jump _b_modcons$6_a_modcons$7_opt_jp$9(6,composed,x$1,a_modcons$7_ctx,a_modcons$7_n$0) -- #142 -//│ Zero => -//│ let x$4 = Zero() in -- #150 -//│ let x$5 = S(x$4) in -- #149 -//│ let* (res) = _b_a_ctx_app$4(a_modcons$7_ctx,x$5) in -- #148 -//│ res -- #147 -//│ false => -//│ case b_modcons$6_n$1 of -- #141 -//│ S => -//│ let x$7 = b_modcons$6_n$1.x in -- #135 -//│ let x$9 = S(0) in -- #134 -//│ let x$10 = S(x$9) in -- #133 -//│ let ctx2 = _Context(x$10,x$9,0) in -- #132 -//│ let* (composed) = _b_a_ctx_comp$5(b_modcons$6_ctx,ctx2) in -- #131 -//│ jump _b_modcons$6_a_modcons$7_opt_jp$9(7,b_modcons$6_ctx,b_modcons$6_n$1,composed,x$7) -- #130 -//│ Zero => -//│ let x$11 = Zero() in -- #140 -//│ let x$12 = S(x$11) in -- #139 -//│ let x$13 = S(x$12) in -- #138 -//│ let* (res) = _b_a_ctx_app$4(b_modcons$6_ctx,x$13) in -- #137 -//│ res -- #136 -//│ ) -//│ }, -//│ let x$14 = Zero() in -- #74 -//│ let x$15 = S(x$14) in -- #73 -//│ let x$16 = S(x$15) in -- #72 -//│ let x$17 = S(x$16) in -- #71 -//│ let* (x$18) = a(x$17) in -- #70 -//│ x$18 -- #69) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Zero, []),ClassInfo(3, S, [x]),ClassInfo(4, _IdContext, []),ClassInfo(5, _Context, [acc,ptr,field])}, { -//│ Def(0, a, [n$0], -//│ 1, -//│ let idCtx = _IdContext() in -- #117 -//│ let* (res) = a_modcons$7(idCtx,n$0) in -- #116 -//│ res -- #115 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, b, [n$1], -//│ 1, -//│ let idCtx = _IdContext() in -- #103 -//│ let* (res) = b_modcons$6(idCtx,n$1) in -- #102 -//│ res -- #101 -//│ ) -//│ Def(3, j$1, [x$6], -//│ 1, -//│ x$6 -- #25 -//│ ) -//│ Def(4, _b_a_ctx_app$4, [ctx,x], -//│ 1, -//│ case ctx of -- #81 -//│ _IdContext => -//│ x -- #80 -//│ _Context => -//│ let field = ctx.field in -- #79 -//│ let ptr = ctx.ptr in -- #78 -//│ let _ = assign ptr.x := x in -- #77 -//│ let acc = ctx.acc in -- #76 -//│ acc -- #75 -//│ ) -//│ Def(5, _b_a_ctx_comp$5, [ctx1,ctx2], -//│ 1, -//│ let ctx2acc = ctx2.acc in -- #87 -//│ let ctx2ptr = ctx2.ptr in -- #86 -//│ let ctx2field = ctx2.field in -- #85 -//│ let* (newAcc) = _b_a_ctx_app$4(ctx1,ctx2acc) in -- #84 -//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #83 -//│ ret -- #82 -//│ ) -//│ Def(6, b_modcons$6, [ctx,n$1], -//│ 1, -//│ let* (r0) = _b_modcons$6_a_modcons$7_opt$8(6,ctx,n$1,undefined,undefined) in -- #156 -//│ r0 -- #155 -//│ ) -//│ Def(7, a_modcons$7, [ctx,n$0], -//│ 1, -//│ let* (r0) = _b_modcons$6_a_modcons$7_opt$8(7,undefined,undefined,ctx,n$0) in -- #158 -//│ r0 -- #157 -//│ ) -//│ Def(8, _b_modcons$6_a_modcons$7_opt$8, [tailrecBranch$,b_modcons$6_ctx,b_modcons$6_n$1,a_modcons$7_ctx,a_modcons$7_n$0], -//│ 1, -//│ jump _b_modcons$6_a_modcons$7_opt_jp$9(tailrecBranch$,b_modcons$6_ctx,b_modcons$6_n$1,a_modcons$7_ctx,a_modcons$7_n$0) -- #154 -//│ ) -//│ Def(9, _b_modcons$6_a_modcons$7_opt_jp$9, [tailrecBranch$,b_modcons$6_ctx,b_modcons$6_n$1,a_modcons$7_ctx,a_modcons$7_n$0], -//│ 1, -//│ let scrut = ==(7,tailrecBranch$) in -- #153 -//│ if scrut -- #152 -//│ true => -//│ case a_modcons$7_n$0 of -- #151 +//│ IR: +//│ Program: +//│ class Zero() +//│ def a(n$0) = +//│ case n$0 of -- #42 //│ S => -//│ let x$1 = a_modcons$7_n$0.x in -- #146 -//│ let x$3 = S(0) in -- #145 -//│ let ctx2 = _Context(x$3,x$3,0) in -- #144 -//│ let* (composed) = _b_a_ctx_comp$5(a_modcons$7_ctx,ctx2) in -- #143 -//│ jump _b_modcons$6_a_modcons$7_opt_jp$9(6,composed,x$1,a_modcons$7_ctx,a_modcons$7_n$0) -- #142 +//│ let x$6 = S.s(n$0) in -- #34 +//│ let* (x$7) = @tailcall b(x$6) in -- #33 +//│ let x$8 = S(x$7) in -- #32 +//│ jump j$0(x$8) -- #31 //│ Zero => -//│ let x$4 = Zero() in -- #150 -//│ let x$5 = S(x$4) in -- #149 -//│ let* (res) = _b_a_ctx_app$4(a_modcons$7_ctx,x$5) in -- #148 -//│ res -- #147 -//│ false => -//│ case b_modcons$6_n$1 of -- #141 +//│ let x$9 = Zero() in -- #41 +//│ let x$10 = S(x$9) in -- #40 +//│ jump j$0(x$10) -- #39 +//│ def j$0(x$5) = +//│ x$5 -- #19 +//│ def b(n$1) = +//│ case n$1 of -- #75 //│ S => -//│ let x$7 = b_modcons$6_n$1.x in -- #135 -//│ let x$9 = S(0) in -- #134 -//│ let x$10 = S(x$9) in -- #133 -//│ let ctx2 = _Context(x$10,x$9,0) in -- #132 -//│ let* (composed) = _b_a_ctx_comp$5(b_modcons$6_ctx,ctx2) in -- #131 -//│ jump _b_modcons$6_a_modcons$7_opt_jp$9(7,b_modcons$6_ctx,b_modcons$6_n$1,composed,x$7) -- #130 +//│ let x$12 = S.s(n$1) in -- #63 +//│ let* (x$13) = @tailcall a(x$12) in -- #62 +//│ let x$14 = S(x$13) in -- #61 +//│ let x$15 = S(x$14) in -- #60 +//│ jump j$1(x$15) -- #59 //│ Zero => -//│ let x$11 = Zero() in -- #140 -//│ let x$12 = S(x$11) in -- #139 -//│ let x$13 = S(x$12) in -- #138 -//│ let* (res) = _b_a_ctx_app$4(b_modcons$6_ctx,x$13) in -- #137 -//│ res -- #136 -//│ ) -//│ }, -//│ let x$14 = Zero() in -- #74 -//│ let x$15 = S(x$14) in -- #73 -//│ let x$16 = S(x$15) in -- #72 -//│ let x$17 = S(x$16) in -- #71 -//│ let* (x$18) = a(x$17) in -- #70 -//│ x$18 -- #69) +//│ let x$16 = Zero() in -- #74 +//│ let x$17 = S(x$16) in -- #73 +//│ let x$18 = S(x$17) in -- #72 +//│ jump j$1(x$18) -- #71 +//│ def j$1(x$11) = +//│ x$11 -- #44 +//│ let x$0 = Zero() in -- #17 +//│ let x$1 = S(x$0) in -- #16 +//│ let x$2 = S(x$1) in -- #15 +//│ let x$3 = S(x$2) in -- #14 +//│ let* (x$4) = a(x$3) in -- #13 +//│ x$4 -- #12 +//│ +//│ +//│ Strongly Connected Tail Calls: +//│ List(Set(j$1), Set(j$0), Set(b, a)) +//│ Program: +//│ class Zero() +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def a(n$0) = +//│ let idCtx = _IdContext() in -- #124 +//│ let* (res) = a_modcons$13(idCtx,n$0) in -- #123 +//│ res -- #122 +//│ def j$0(x$5) = +//│ x$5 -- #19 +//│ def b(n$1) = +//│ let idCtx = _IdContext() in -- #110 +//│ let* (res) = b_modcons$12(idCtx,n$1) in -- #109 +//│ res -- #108 +//│ def j$1(x$11) = +//│ x$11 -- #44 +//│ def _b_a_ctx_app$10(ctx,x) = +//│ case ctx of -- #88 +//│ _IdContext => +//│ x -- #87 +//│ _Context => +//│ let field = _Context.field(ctx) in -- #86 +//│ let ptr = _Context.ptr(ctx) in -- #85 +//│ let _ = assign ptr.s := x in -- #84 +//│ let acc = _Context.acc(ctx) in -- #83 +//│ acc -- #82 +//│ def _b_a_ctx_comp$11(ctx1,ctx2) = +//│ let ctx2acc = _Context.acc(ctx2) in -- #94 +//│ let ctx2ptr = _Context.ptr(ctx2) in -- #93 +//│ let ctx2field = _Context.field(ctx2) in -- #92 +//│ let* (newAcc) = _b_a_ctx_app$10(ctx1,ctx2acc) in -- #91 +//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #90 +//│ ret -- #89 +//│ def b_modcons$12(ctx,n$1) = +//│ let* (r0) = _b_modcons$12_a_modcons$13_opt$14(12,ctx,n$1,true,true) in -- #163 +//│ r0 -- #162 +//│ def a_modcons$13(ctx,n$0) = +//│ let* (r0) = _b_modcons$12_a_modcons$13_opt$14(13,true,true,ctx,n$0) in -- #165 +//│ r0 -- #164 +//│ def _b_modcons$12_a_modcons$13_opt$14(tailrecBranch$,b_modcons$12_ctx,b_modcons$12_n$1,a_modcons$13_ctx,a_modcons$13_n$0) = +//│ jump _b_modcons$12_a_modcons$13_opt_jp$15(tailrecBranch$,b_modcons$12_ctx,b_modcons$12_n$1,a_modcons$13_ctx,a_modcons$13_n$0) -- #161 +//│ def _b_modcons$12_a_modcons$13_opt_jp$15(tailrecBranch$,b_modcons$12_ctx,b_modcons$12_n$1,a_modcons$13_ctx,a_modcons$13_n$0) = +//│ let scrut = ==(13,tailrecBranch$) in -- #160 +//│ if scrut -- #159 +//│ true => +//│ case a_modcons$13_n$0 of -- #158 +//│ S => +//│ let x$6 = S.s(a_modcons$13_n$0) in -- #153 +//│ let x$8 = S(0) in -- #152 +//│ let ctx2 = _Context(x$8,x$8,0) in -- #151 +//│ let* (composed) = _b_a_ctx_comp$11(a_modcons$13_ctx,ctx2) in -- #150 +//│ jump _b_modcons$12_a_modcons$13_opt_jp$15(12,composed,x$6,a_modcons$13_ctx,a_modcons$13_n$0) -- #149 +//│ Zero => +//│ let x$9 = Zero() in -- #157 +//│ let x$10 = S(x$9) in -- #156 +//│ let* (res) = _b_a_ctx_app$10(a_modcons$13_ctx,x$10) in -- #155 +//│ res -- #154 +//│ false => +//│ case b_modcons$12_n$1 of -- #148 +//│ S => +//│ let x$12 = S.s(b_modcons$12_n$1) in -- #142 +//│ let x$14 = S(0) in -- #141 +//│ let x$15 = S(x$14) in -- #140 +//│ let ctx2 = _Context(x$15,x$14,0) in -- #139 +//│ let* (composed) = _b_a_ctx_comp$11(b_modcons$12_ctx,ctx2) in -- #138 +//│ jump _b_modcons$12_a_modcons$13_opt_jp$15(13,b_modcons$12_ctx,b_modcons$12_n$1,composed,x$12) -- #137 +//│ Zero => +//│ let x$16 = Zero() in -- #147 +//│ let x$17 = S(x$16) in -- #146 +//│ let x$18 = S(x$17) in -- #145 +//│ let* (res) = _b_a_ctx_app$10(b_modcons$12_ctx,x$18) in -- #144 +//│ res -- #143 +//│ let x$0 = Zero() in -- #17 +//│ let x$1 = S(x$0) in -- #16 +//│ let x$2 = S(x$1) in -- #15 +//│ let x$3 = S(x$2) in -- #14 +//│ let* (x$4) = a(x$3) in -- #13 +//│ x$4 -- #12 //│ //│ Interpreted: -//│ S(S(S(S(S(S(Zero())))))) +//│ S(0) :interpIR -class Cons(h, t) -class Nil @tailrec fun addOne(xs) = if xs is Cons(h, t) then @@ -1192,168 +761,91 @@ class Nil Nil then Nil addOne(Cons(1, Cons(2, Cons(3, Nil)))) -//│ |#class| |Cons|(|h|,| |t|)|↵|#class| |Nil|↵|@|tailrec| |#fun| |addOne|(|xs|)| |#=|→|#if| |xs| |is| |→|Cons|(|h|,| |t|)| |#then|→|#val| |next| |#=| |@|tailcall| |addOne|(|t|)|↵|#val| |ret| |#=| |Cons|(|h| |+| |1|,| |next|)|↵|#val| |rett| |#=| |ret|↵|rett|←|↵|Nil| |#then| |→|Nil|←|←|←|↵|addOne|(|Cons|(|1|,| |Cons|(|2|,| |Cons|(|3|,| |Nil|)|)|)|)| -//│ Parsed: {class Cons(h, t,) {}; class Nil {}; fun addOne = (xs,) => {if xs is ‹(Cons(h, t,)) then {let next = @tailcall addOne(t,); let ret = Cons(+(h,)(1,), next,); let rett = ret; rett}; (Nil) then {Nil}›}; addOne(Cons(1, Cons(2, Cons(3, Nil,),),),)} +//│ |@|tailrec| |#fun| |addOne|(|xs|)| |#=|→|#if| |xs| |is| |→|Cons|(|h|,| |t|)| |#then|→|#val| |next| |#=| |@|tailcall| |addOne|(|t|)|↵|#val| |ret| |#=| |Cons|(|h| |+| |1|,| |next|)|↵|#val| |rett| |#=| |ret|↵|rett|←|↵|Nil| |#then| |→|Nil|←|←|←|↵|addOne|(|Cons|(|1|,| |Cons|(|2|,| |Cons|(|3|,| |Nil|)|)|)|)| +//│ Parsed: {fun addOne = (xs,) => {if xs is ‹(Cons(h, t,)) then {let next = @tailcall addOne(t,); let ret = Cons(+(h,)(1,), next,); let rett = ret; rett}; (Nil) then {Nil}›}; addOne(Cons(1, Cons(2, Cons(3, Nil,),),),)} +//│ //│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Cons, [h,t]),ClassInfo(3, Nil, [])}, { -//│ Def(0, addOne, [xs$0], -//│ 1, -//│ case xs$0 of -- #30 -//│ Cons => -//│ let x$1 = xs$0.t in -- #26 -//│ let x$2 = xs$0.h in -- #25 -//│ let* (x$3) = @tailcall addOne(x$1) in -- #24 -//│ let x$4 = +(x$2,1) in -- #23 -//│ let x$5 = Cons(x$4,x$3) in -- #22 -//│ jump j$0(x$5) -- #21 -//│ Nil => -//│ let x$6 = Nil() in -- #29 -//│ jump j$0(x$6) -- #28 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ }, -//│ let x$7 = Nil() in -- #55 -//│ let x$8 = Cons(3,x$7) in -- #54 -//│ let x$9 = Cons(2,x$8) in -- #53 -//│ let x$10 = Cons(1,x$9) in -- #52 -//│ let* (x$11) = addOne(x$10) in -- #51 -//│ x$11 -- #50) +//│ Program: +//│ +//│ def addOne(xs$0) = +//│ case xs$0 of -- #57 +//│ Cons => +//│ let x$6 = Cons.t(xs$0) in -- #53 +//│ let x$7 = Cons.h(xs$0) in -- #52 +//│ let* (x$8) = @tailcall addOne(x$6) in -- #51 +//│ let x$9 = +(x$7,1) in -- #50 +//│ let x$10 = Cons(x$9,x$8) in -- #49 +//│ jump j$0(x$10) -- #48 +//│ Nil => +//│ let x$11 = Nil() in -- #56 +//│ jump j$0(x$11) -- #55 +//│ def j$0(x$5) = +//│ x$5 -- #25 +//│ let x$0 = Nil() in -- #23 +//│ let x$1 = Cons(3,x$0) in -- #22 +//│ let x$2 = Cons(2,x$1) in -- #21 +//│ let x$3 = Cons(1,x$2) in -- #20 +//│ let* (x$4) = addOne(x$3) in -- #19 +//│ x$4 -- #18 +//│ //│ //│ Strongly Connected Tail Calls: //│ List(Set(j$0), Set(addOne)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Cons, [h,t]),ClassInfo(3, Nil, []),ClassInfo(4, _IdContext, []),ClassInfo(5, _Context, [acc,ptr,field])}, { -//│ Def(0, addOne, [xs$0], -//│ 1, -//│ let idCtx = _IdContext() in -- #83 -//│ let* (res) = addOne_modcons$4(idCtx,xs$0) in -- #82 -//│ res -- #81 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, _addOne_ctx_app$2, [ctx,x], -//│ 1, -//│ case ctx of -- #62 -//│ _IdContext => -//│ x -- #61 -//│ _Context => -//│ let field = ctx.field in -- #60 -//│ let ptr = ctx.ptr in -- #59 -//│ let _ = assign ptr.t := x in -- #58 -//│ let acc = ctx.acc in -- #57 -//│ acc -- #56 -//│ ) -//│ Def(3, _addOne_ctx_comp$3, [ctx1,ctx2], -//│ 1, -//│ let ctx2acc = ctx2.acc in -- #68 -//│ let ctx2ptr = ctx2.ptr in -- #67 -//│ let ctx2field = ctx2.field in -- #66 -//│ let* (newAcc) = _addOne_ctx_app$2(ctx1,ctx2acc) in -- #65 -//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #64 -//│ ret -- #63 -//│ ) -//│ Def(5, addOne_modcons$4_jp, [ctx,xs$0], -//│ 1, -//│ case xs$0 of -- #94 -//│ Cons => -//│ let x$1 = xs$0.t in -- #90 -//│ let x$2 = xs$0.h in -- #89 -//│ let x$4 = +(x$2,1) in -- #88 -//│ let x$5 = Cons(x$4,0) in -- #87 -//│ let ctx2 = _Context(x$5,x$5,0) in -- #86 -//│ let* (composed) = _addOne_ctx_comp$3(ctx,ctx2) in -- #85 -//│ jump addOne_modcons$4_jp(composed,x$1) -- #84 -//│ Nil => -//│ let x$6 = Nil() in -- #93 -//│ let* (res) = _addOne_ctx_app$2(ctx,x$6) in -- #92 -//│ res -- #91 -//│ ) -//│ Def(6, addOne_modcons$4, [ctx,xs$0], -//│ 1, -//│ let* (r0) = addOne_modcons$4_jp(ctx,xs$0) in -- #96 -//│ r0 -- #95 -//│ ) -//│ }, -//│ let x$7 = Nil() in -- #55 -//│ let x$8 = Cons(3,x$7) in -- #54 -//│ let x$9 = Cons(2,x$8) in -- #53 -//│ let x$10 = Cons(1,x$9) in -- #52 -//│ let* (x$11) = addOne(x$10) in -- #51 -//│ x$11 -- #50) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Cons, [h,t]),ClassInfo(3, Nil, []),ClassInfo(4, _IdContext, []),ClassInfo(5, _Context, [acc,ptr,field])}, { -//│ Def(0, addOne, [xs$0], -//│ 1, -//│ let idCtx = _IdContext() in -- #83 -//│ let* (res) = addOne_modcons$4(idCtx,xs$0) in -- #82 -//│ res -- #81 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, _addOne_ctx_app$2, [ctx,x], -//│ 1, -//│ case ctx of -- #62 -//│ _IdContext => -//│ x -- #61 -//│ _Context => -//│ let field = ctx.field in -- #60 -//│ let ptr = ctx.ptr in -- #59 -//│ let _ = assign ptr.t := x in -- #58 -//│ let acc = ctx.acc in -- #57 -//│ acc -- #56 -//│ ) -//│ Def(3, _addOne_ctx_comp$3, [ctx1,ctx2], -//│ 1, -//│ let ctx2acc = ctx2.acc in -- #68 -//│ let ctx2ptr = ctx2.ptr in -- #67 -//│ let ctx2field = ctx2.field in -- #66 -//│ let* (newAcc) = _addOne_ctx_app$2(ctx1,ctx2acc) in -- #65 -//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #64 -//│ ret -- #63 -//│ ) -//│ Def(5, addOne_modcons$4_jp, [ctx,xs$0], -//│ 1, -//│ case xs$0 of -- #94 -//│ Cons => -//│ let x$1 = xs$0.t in -- #90 -//│ let x$2 = xs$0.h in -- #89 -//│ let x$4 = +(x$2,1) in -- #88 -//│ let x$5 = Cons(x$4,0) in -- #87 -//│ let ctx2 = _Context(x$5,x$5,0) in -- #86 -//│ let* (composed) = _addOne_ctx_comp$3(ctx,ctx2) in -- #85 -//│ jump addOne_modcons$4_jp(composed,x$1) -- #84 -//│ Nil => -//│ let x$6 = Nil() in -- #93 -//│ let* (res) = _addOne_ctx_app$2(ctx,x$6) in -- #92 -//│ res -- #91 -//│ ) -//│ Def(6, addOne_modcons$4, [ctx,xs$0], -//│ 1, -//│ let* (r0) = addOne_modcons$4_jp(ctx,xs$0) in -- #96 -//│ r0 -- #95 -//│ ) -//│ }, -//│ let x$7 = Nil() in -- #55 -//│ let x$8 = Cons(3,x$7) in -- #54 -//│ let x$9 = Cons(2,x$8) in -- #53 -//│ let x$10 = Cons(1,x$9) in -- #52 -//│ let* (x$11) = addOne(x$10) in -- #51 -//│ x$11 -- #50) +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def addOne(xs$0) = +//│ let idCtx = _IdContext() in -- #91 +//│ let* (res) = addOne_modcons$10(idCtx,xs$0) in -- #90 +//│ res -- #89 +//│ def j$0(x$5) = +//│ x$5 -- #25 +//│ def _addOne_ctx_app$8(ctx,x) = +//│ case ctx of -- #70 +//│ _IdContext => +//│ x -- #69 +//│ _Context => +//│ let field = _Context.field(ctx) in -- #68 +//│ let ptr = _Context.ptr(ctx) in -- #67 +//│ let _ = assign ptr.t := x in -- #66 +//│ let acc = _Context.acc(ctx) in -- #65 +//│ acc -- #64 +//│ def _addOne_ctx_comp$9(ctx1,ctx2) = +//│ let ctx2acc = _Context.acc(ctx2) in -- #76 +//│ let ctx2ptr = _Context.ptr(ctx2) in -- #75 +//│ let ctx2field = _Context.field(ctx2) in -- #74 +//│ let* (newAcc) = _addOne_ctx_app$8(ctx1,ctx2acc) in -- #73 +//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #72 +//│ ret -- #71 +//│ def addOne_modcons$10_jp(ctx,xs$0) = +//│ case xs$0 of -- #102 +//│ Cons => +//│ let x$6 = Cons.t(xs$0) in -- #98 +//│ let x$7 = Cons.h(xs$0) in -- #97 +//│ let x$9 = +(x$7,1) in -- #96 +//│ let x$10 = Cons(x$9,0) in -- #95 +//│ let ctx2 = _Context(x$10,x$10,0) in -- #94 +//│ let* (composed) = _addOne_ctx_comp$9(ctx,ctx2) in -- #93 +//│ jump addOne_modcons$10_jp(composed,x$6) -- #92 +//│ Nil => +//│ let x$11 = Nil() in -- #101 +//│ let* (res) = _addOne_ctx_app$8(ctx,x$11) in -- #100 +//│ res -- #99 +//│ def addOne_modcons$10(ctx,xs$0) = +//│ let* (r0) = addOne_modcons$10_jp(ctx,xs$0) in -- #104 +//│ r0 -- #103 +//│ let x$0 = Nil() in -- #23 +//│ let x$1 = Cons(3,x$0) in -- #22 +//│ let x$2 = Cons(2,x$1) in -- #21 +//│ let x$3 = Cons(1,x$2) in -- #20 +//│ let* (x$4) = addOne(x$3) in -- #19 +//│ x$4 -- #18 //│ //│ Interpreted: -//│ Cons(2,Cons(3,Cons(4,Nil()))) +//│ Cons(2,0) :interpIR -class Nil -class Cons(m, n) @tailrec fun a(x) = if x is Cons(m, n) then @@ -1368,281 +860,145 @@ class Cons(m, n) else a(Cons(n, Nil)) b(16) -//│ |#class| |Nil|↵|#class| |Cons|(|m|,| |n|)|↵|@|tailrec| |#fun| |a|(|x|)| |#=|→|#if| |x| |is|→|Cons|(|m|,| |n|)| |#then|→|#if| |m| |<| |0| |#then|→|Cons|(|-|1|,| |Nil|)|←|↵|#else| |→|Cons|(|m| |*| |4|,| |b|(|m| |-| |2|)|)|←|←|↵|Nil| |#then| |Nil|←|←|↵|@|tailrec| |#fun| |b|(|n|)| |#=|→|#if| |n| |<=| |0| |#then| |→|Cons|(|0|,| |Nil|)|←|↵|#else| |→|a|(|Cons|(|n|,| |Nil|)|)|←|←|↵|b|(|16|)| -//│ Parsed: {class Nil {}; class Cons(m, n,) {}; fun a = (x,) => {if x is ‹(Cons(m, n,)) then {if (<(m,)(0,)) then {Cons(-1, Nil,)} else {Cons(*(m,)(4,), b(-(m,)(2,),),)}}; (Nil) then Nil›}; fun b = (n,) => {if (<=(n,)(0,)) then {Cons(0, Nil,)} else {a(Cons(n, Nil,),)}}; b(16,)} +//│ |@|tailrec| |#fun| |a|(|x|)| |#=|→|#if| |x| |is|→|Cons|(|m|,| |n|)| |#then|→|#if| |m| |<| |0| |#then|→|Cons|(|-|1|,| |Nil|)|←|↵|#else| |→|Cons|(|m| |*| |4|,| |b|(|m| |-| |2|)|)|←|←|↵|Nil| |#then| |Nil|←|←|↵|@|tailrec| |#fun| |b|(|n|)| |#=|→|#if| |n| |<=| |0| |#then| |→|Cons|(|0|,| |Nil|)|←|↵|#else| |→|a|(|Cons|(|n|,| |Nil|)|)|←|←|↵|b|(|16|)| +//│ Parsed: {fun a = (x,) => {if x is ‹(Cons(m, n,)) then {if (<(m,)(0,)) then {Cons(-1, Nil,)} else {Cons(*(m,)(4,), b(-(m,)(2,),),)}}; (Nil) then Nil›}; fun b = (n,) => {if (<=(n,)(0,)) then {Cons(0, Nil,)} else {a(Cons(n, Nil,),)}}; b(16,)} +//│ //│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Nil, []),ClassInfo(3, Cons, [m,n])}, { -//│ Def(0, a, [x$0], -//│ 1, -//│ case x$0 of -- #46 -//│ Cons => -//│ let x$2 = x$0.n in -- #42 -//│ let x$3 = x$0.m in -- #41 -//│ let x$4 = <(x$3,0) in -- #40 -//│ if x$4 -- #39 -//│ true => -//│ let x$6 = Nil() in -- #19 -//│ let x$7 = Cons(-1,x$6) in -- #18 -//│ jump j$1(x$7) -- #17 -//│ false => -//│ let x$8 = *(x$3,4) in -- #38 -//│ let x$9 = -(x$3,2) in -- #37 -//│ let* (x$10) = b(x$9) in -- #36 -//│ let x$11 = Cons(x$8,x$10) in -- #35 -//│ jump j$1(x$11) -- #34 -//│ Nil => -//│ let x$12 = Nil() in -- #45 -//│ jump j$0(x$12) -- #44 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #1 -//│ ) -//│ Def(2, j$1, [x$5], -//│ 1, -//│ jump j$0(x$5) -- #10 -//│ ) -//│ Def(3, b, [n$0], -//│ 1, -//│ let x$13 = <=(n$0,0) in -- #75 -//│ if x$13 -- #74 -//│ true => -//│ let x$15 = Nil() in -- #59 -//│ let x$16 = Cons(0,x$15) in -- #58 -//│ jump j$2(x$16) -- #57 -//│ false => -//│ let x$17 = Nil() in -- #73 -//│ let x$18 = Cons(n$0,x$17) in -- #72 -//│ let* (x$19) = a(x$18) in -- #71 -//│ jump j$2(x$19) -- #70 -//│ ) -//│ Def(4, j$2, [x$14], -//│ 1, -//│ x$14 -- #50 -//│ ) -//│ }, -//│ let* (x$20) = b(16) in -- #81 -//│ x$20 -- #80) +//│ Program: //│ -//│ Strongly Connected Tail Calls: -//│ List(Set(j$2), Set(j$1), Set(j$0), Set(b, a)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Nil, []),ClassInfo(3, Cons, [m,n]),ClassInfo(4, _IdContext, []),ClassInfo(5, _Context, [acc,ptr,field])}, { -//│ Def(0, a, [x$0], -//│ 1, -//│ let idCtx = _IdContext() in -- #129 -//│ let* (res) = a_modcons$8(idCtx,x$0) in -- #128 -//│ res -- #127 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #1 -//│ ) -//│ Def(2, j$1, [x$5], -//│ 1, -//│ jump j$0(x$5) -- #10 -//│ ) -//│ Def(3, b, [n$0], -//│ 1, -//│ let idCtx = _IdContext() in -- #107 -//│ let* (res) = b_modcons$7(idCtx,n$0) in -- #106 -//│ res -- #105 -//│ ) -//│ Def(4, j$2, [x$14], -//│ 1, -//│ x$14 -- #50 -//│ ) -//│ Def(5, _b_a_ctx_app$5, [ctx,x], -//│ 1, -//│ case ctx of -- #88 -//│ _IdContext => -//│ x -- #87 -//│ _Context => -//│ let field = ctx.field in -- #86 -//│ let ptr = ctx.ptr in -- #85 -//│ let _ = assign ptr.n := x in -- #84 -//│ let acc = ctx.acc in -- #83 -//│ acc -- #82 -//│ ) -//│ Def(6, _b_a_ctx_comp$6, [ctx1,ctx2], -//│ 1, -//│ let ctx2acc = ctx2.acc in -- #94 -//│ let ctx2ptr = ctx2.ptr in -- #93 -//│ let ctx2field = ctx2.field in -- #92 -//│ let* (newAcc) = _b_a_ctx_app$5(ctx1,ctx2acc) in -- #91 -//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #90 -//│ ret -- #89 -//│ ) -//│ Def(7, b_modcons$7, [ctx,n$0], -//│ 1, -//│ let* (r0) = _b_modcons$7_a_modcons$8_opt$9(7,ctx,n$0,undefined,undefined) in -- #170 -//│ r0 -- #169 -//│ ) -//│ Def(8, a_modcons$8, [ctx,x$0], -//│ 1, -//│ let* (r0) = _b_modcons$7_a_modcons$8_opt$9(8,undefined,undefined,ctx,x$0) in -- #172 -//│ r0 -- #171 -//│ ) -//│ Def(9, _b_modcons$7_a_modcons$8_opt$9, [tailrecBranch$,b_modcons$7_ctx,b_modcons$7_n$0,a_modcons$8_ctx,a_modcons$8_x$0], -//│ 1, -//│ jump _b_modcons$7_a_modcons$8_opt_jp$10(tailrecBranch$,b_modcons$7_ctx,b_modcons$7_n$0,a_modcons$8_ctx,a_modcons$8_x$0) -- #168 -//│ ) -//│ Def(10, _b_modcons$7_a_modcons$8_opt_jp$10, [tailrecBranch$,b_modcons$7_ctx,b_modcons$7_n$0,a_modcons$8_ctx,a_modcons$8_x$0], -//│ 1, -//│ let scrut = ==(8,tailrecBranch$) in -- #167 -//│ if scrut -- #166 -//│ true => -//│ case a_modcons$8_x$0 of -- #165 +//│ def a(x$1) = +//│ case x$1 of -- #54 //│ Cons => -//│ let x$2 = a_modcons$8_x$0.n in -- #161 -//│ let x$3 = a_modcons$8_x$0.m in -- #160 -//│ let x$4 = <(x$3,0) in -- #159 -//│ if x$4 -- #158 +//│ let x$3 = Cons.t(x$1) in -- #50 +//│ let x$4 = Cons.h(x$1) in -- #49 +//│ let x$5 = <(x$4,0) in -- #48 +//│ if x$5 -- #47 //│ true => -//│ let x$6 = Nil() in -- #151 -//│ let x$7 = Cons(-1,x$6) in -- #150 -//│ let* (res) = _b_a_ctx_app$5(a_modcons$8_ctx,x$7) in -- #149 -//│ res -- #148 +//│ let x$7 = Nil() in -- #28 +//│ let x$8 = Cons(-1,x$7) in -- #27 +//│ jump j$1(x$8) -- #26 //│ false => -//│ let x$8 = *(x$3,4) in -- #157 -//│ let x$9 = -(x$3,2) in -- #156 -//│ let x$11 = Cons(x$8,0) in -- #155 -//│ let ctx2 = _Context(x$11,x$11,0) in -- #154 -//│ let* (composed) = _b_a_ctx_comp$6(a_modcons$8_ctx,ctx2) in -- #153 -//│ jump _b_modcons$7_a_modcons$8_opt_jp$10(7,composed,x$9,a_modcons$8_ctx,a_modcons$8_x$0) -- #152 +//│ let x$9 = *(x$4,4) in -- #46 +//│ let x$10 = -(x$4,2) in -- #45 +//│ let* (x$11) = b(x$10) in -- #44 +//│ let x$12 = Cons(x$9,x$11) in -- #43 +//│ jump j$1(x$12) -- #42 //│ Nil => -//│ let x$12 = Nil() in -- #164 -//│ let* (res) = _b_a_ctx_app$5(a_modcons$8_ctx,x$12) in -- #163 -//│ res -- #162 -//│ false => -//│ let x$13 = <=(b_modcons$7_n$0,0) in -- #147 -//│ if x$13 -- #146 +//│ let x$13 = Nil() in -- #53 +//│ jump j$0(x$13) -- #52 +//│ def j$0(x$2) = +//│ x$2 -- #6 +//│ def j$1(x$6) = +//│ jump j$0(x$6) -- #19 +//│ def b(n$0) = +//│ let x$14 = <=(n$0,0) in -- #82 +//│ if x$14 -- #81 //│ true => -//│ let x$15 = Nil() in -- #142 -//│ let x$16 = Cons(0,x$15) in -- #141 -//│ let* (res) = _b_a_ctx_app$5(b_modcons$7_ctx,x$16) in -- #140 -//│ res -- #139 +//│ let x$16 = Nil() in -- #67 +//│ let x$17 = Cons(0,x$16) in -- #66 +//│ jump j$2(x$17) -- #65 //│ false => -//│ let x$17 = Nil() in -- #145 -//│ let x$18 = Cons(b_modcons$7_n$0,x$17) in -- #144 -//│ jump _b_modcons$7_a_modcons$8_opt_jp$10(8,b_modcons$7_ctx,b_modcons$7_n$0,b_modcons$7_ctx,x$18) -- #143 -//│ ) -//│ }, -//│ let* (x$20) = b(16) in -- #81 -//│ x$20 -- #80) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Nil, []),ClassInfo(3, Cons, [m,n]),ClassInfo(4, _IdContext, []),ClassInfo(5, _Context, [acc,ptr,field])}, { -//│ Def(0, a, [x$0], -//│ 1, -//│ let idCtx = _IdContext() in -- #129 -//│ let* (res) = a_modcons$8(idCtx,x$0) in -- #128 -//│ res -- #127 -//│ ) -//│ Def(1, j$0, [x$1], -//│ 1, -//│ x$1 -- #1 -//│ ) -//│ Def(2, j$1, [x$5], -//│ 1, -//│ jump j$0(x$5) -- #10 -//│ ) -//│ Def(3, b, [n$0], -//│ 1, -//│ let idCtx = _IdContext() in -- #107 -//│ let* (res) = b_modcons$7(idCtx,n$0) in -- #106 -//│ res -- #105 -//│ ) -//│ Def(4, j$2, [x$14], -//│ 1, -//│ x$14 -- #50 -//│ ) -//│ Def(5, _b_a_ctx_app$5, [ctx,x], -//│ 1, -//│ case ctx of -- #88 -//│ _IdContext => -//│ x -- #87 -//│ _Context => -//│ let field = ctx.field in -- #86 -//│ let ptr = ctx.ptr in -- #85 -//│ let _ = assign ptr.n := x in -- #84 -//│ let acc = ctx.acc in -- #83 -//│ acc -- #82 -//│ ) -//│ Def(6, _b_a_ctx_comp$6, [ctx1,ctx2], -//│ 1, -//│ let ctx2acc = ctx2.acc in -- #94 -//│ let ctx2ptr = ctx2.ptr in -- #93 -//│ let ctx2field = ctx2.field in -- #92 -//│ let* (newAcc) = _b_a_ctx_app$5(ctx1,ctx2acc) in -- #91 -//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #90 -//│ ret -- #89 -//│ ) -//│ Def(7, b_modcons$7, [ctx,n$0], -//│ 1, -//│ let* (r0) = _b_modcons$7_a_modcons$8_opt$9(7,ctx,n$0,undefined,undefined) in -- #170 -//│ r0 -- #169 -//│ ) -//│ Def(8, a_modcons$8, [ctx,x$0], -//│ 1, -//│ let* (r0) = _b_modcons$7_a_modcons$8_opt$9(8,undefined,undefined,ctx,x$0) in -- #172 -//│ r0 -- #171 -//│ ) -//│ Def(9, _b_modcons$7_a_modcons$8_opt$9, [tailrecBranch$,b_modcons$7_ctx,b_modcons$7_n$0,a_modcons$8_ctx,a_modcons$8_x$0], -//│ 1, -//│ jump _b_modcons$7_a_modcons$8_opt_jp$10(tailrecBranch$,b_modcons$7_ctx,b_modcons$7_n$0,a_modcons$8_ctx,a_modcons$8_x$0) -- #168 -//│ ) -//│ Def(10, _b_modcons$7_a_modcons$8_opt_jp$10, [tailrecBranch$,b_modcons$7_ctx,b_modcons$7_n$0,a_modcons$8_ctx,a_modcons$8_x$0], -//│ 1, -//│ let scrut = ==(8,tailrecBranch$) in -- #167 -//│ if scrut -- #166 -//│ true => -//│ case a_modcons$8_x$0 of -- #165 -//│ Cons => -//│ let x$2 = a_modcons$8_x$0.n in -- #161 -//│ let x$3 = a_modcons$8_x$0.m in -- #160 -//│ let x$4 = <(x$3,0) in -- #159 -//│ if x$4 -- #158 -//│ true => -//│ let x$6 = Nil() in -- #151 -//│ let x$7 = Cons(-1,x$6) in -- #150 -//│ let* (res) = _b_a_ctx_app$5(a_modcons$8_ctx,x$7) in -- #149 -//│ res -- #148 -//│ false => -//│ let x$8 = *(x$3,4) in -- #157 -//│ let x$9 = -(x$3,2) in -- #156 -//│ let x$11 = Cons(x$8,0) in -- #155 -//│ let ctx2 = _Context(x$11,x$11,0) in -- #154 -//│ let* (composed) = _b_a_ctx_comp$6(a_modcons$8_ctx,ctx2) in -- #153 -//│ jump _b_modcons$7_a_modcons$8_opt_jp$10(7,composed,x$9,a_modcons$8_ctx,a_modcons$8_x$0) -- #152 -//│ Nil => -//│ let x$12 = Nil() in -- #164 -//│ let* (res) = _b_a_ctx_app$5(a_modcons$8_ctx,x$12) in -- #163 -//│ res -- #162 -//│ false => -//│ let x$13 = <=(b_modcons$7_n$0,0) in -- #147 -//│ if x$13 -- #146 +//│ let x$18 = Nil() in -- #80 +//│ let x$19 = Cons(n$0,x$18) in -- #79 +//│ let* (x$20) = a(x$19) in -- #78 +//│ jump j$2(x$20) -- #77 +//│ def j$2(x$15) = +//│ x$15 -- #58 +//│ let* (x$0) = b(16) in -- #4 +//│ x$0 -- #3 +//│ +//│ +//│ Strongly Connected Tail Calls: +//│ List(Set(j$2), Set(j$1), Set(j$0), Set(b, a)) +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def a(x$1) = +//│ let idCtx = _IdContext() in -- #136 +//│ let* (res) = a_modcons$14(idCtx,x$1) in -- #135 +//│ res -- #134 +//│ def j$0(x$2) = +//│ x$2 -- #6 +//│ def j$1(x$6) = +//│ jump j$0(x$6) -- #19 +//│ def b(n$0) = +//│ let idCtx = _IdContext() in -- #114 +//│ let* (res) = b_modcons$13(idCtx,n$0) in -- #113 +//│ res -- #112 +//│ def j$2(x$15) = +//│ x$15 -- #58 +//│ def _b_a_ctx_app$11(ctx,x) = +//│ case ctx of -- #95 +//│ _IdContext => +//│ x -- #94 +//│ _Context => +//│ let field = _Context.field(ctx) in -- #93 +//│ let ptr = _Context.ptr(ctx) in -- #92 +//│ let _ = assign ptr.t := x in -- #91 +//│ let acc = _Context.acc(ctx) in -- #90 +//│ acc -- #89 +//│ def _b_a_ctx_comp$12(ctx1,ctx2) = +//│ let ctx2acc = _Context.acc(ctx2) in -- #101 +//│ let ctx2ptr = _Context.ptr(ctx2) in -- #100 +//│ let ctx2field = _Context.field(ctx2) in -- #99 +//│ let* (newAcc) = _b_a_ctx_app$11(ctx1,ctx2acc) in -- #98 +//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #97 +//│ ret -- #96 +//│ def b_modcons$13(ctx,n$0) = +//│ let* (r0) = _b_modcons$13_a_modcons$14_opt$15(13,ctx,n$0,true,true) in -- #177 +//│ r0 -- #176 +//│ def a_modcons$14(ctx,x$1) = +//│ let* (r0) = _b_modcons$13_a_modcons$14_opt$15(14,true,true,ctx,x$1) in -- #179 +//│ r0 -- #178 +//│ def _b_modcons$13_a_modcons$14_opt$15(tailrecBranch$,b_modcons$13_ctx,b_modcons$13_n$0,a_modcons$14_ctx,a_modcons$14_x$1) = +//│ jump _b_modcons$13_a_modcons$14_opt_jp$16(tailrecBranch$,b_modcons$13_ctx,b_modcons$13_n$0,a_modcons$14_ctx,a_modcons$14_x$1) -- #175 +//│ def _b_modcons$13_a_modcons$14_opt_jp$16(tailrecBranch$,b_modcons$13_ctx,b_modcons$13_n$0,a_modcons$14_ctx,a_modcons$14_x$1) = +//│ let scrut = ==(14,tailrecBranch$) in -- #174 +//│ if scrut -- #173 //│ true => -//│ let x$15 = Nil() in -- #142 -//│ let x$16 = Cons(0,x$15) in -- #141 -//│ let* (res) = _b_a_ctx_app$5(b_modcons$7_ctx,x$16) in -- #140 -//│ res -- #139 +//│ case a_modcons$14_x$1 of -- #172 +//│ Cons => +//│ let x$3 = Cons.t(a_modcons$14_x$1) in -- #168 +//│ let x$4 = Cons.h(a_modcons$14_x$1) in -- #167 +//│ let x$5 = <(x$4,0) in -- #166 +//│ if x$5 -- #165 +//│ true => +//│ let x$7 = Nil() in -- #158 +//│ let x$8 = Cons(-1,x$7) in -- #157 +//│ let* (res) = _b_a_ctx_app$11(a_modcons$14_ctx,x$8) in -- #156 +//│ res -- #155 +//│ false => +//│ let x$9 = *(x$4,4) in -- #164 +//│ let x$10 = -(x$4,2) in -- #163 +//│ let x$12 = Cons(x$9,0) in -- #162 +//│ let ctx2 = _Context(x$12,x$12,0) in -- #161 +//│ let* (composed) = _b_a_ctx_comp$12(a_modcons$14_ctx,ctx2) in -- #160 +//│ jump _b_modcons$13_a_modcons$14_opt_jp$16(13,composed,x$10,a_modcons$14_ctx,a_modcons$14_x$1) -- #159 +//│ Nil => +//│ let x$13 = Nil() in -- #171 +//│ let* (res) = _b_a_ctx_app$11(a_modcons$14_ctx,x$13) in -- #170 +//│ res -- #169 //│ false => -//│ let x$17 = Nil() in -- #145 -//│ let x$18 = Cons(b_modcons$7_n$0,x$17) in -- #144 -//│ jump _b_modcons$7_a_modcons$8_opt_jp$10(8,b_modcons$7_ctx,b_modcons$7_n$0,b_modcons$7_ctx,x$18) -- #143 -//│ ) -//│ }, -//│ let* (x$20) = b(16) in -- #81 -//│ x$20 -- #80) +//│ let x$14 = <=(b_modcons$13_n$0,0) in -- #154 +//│ if x$14 -- #153 +//│ true => +//│ let x$16 = Nil() in -- #149 +//│ let x$17 = Cons(0,x$16) in -- #148 +//│ let* (res) = _b_a_ctx_app$11(b_modcons$13_ctx,x$17) in -- #147 +//│ res -- #146 +//│ false => +//│ let x$18 = Nil() in -- #152 +//│ let x$19 = Cons(b_modcons$13_n$0,x$18) in -- #151 +//│ jump _b_modcons$13_a_modcons$14_opt_jp$16(14,b_modcons$13_ctx,b_modcons$13_n$0,b_modcons$13_ctx,x$19) -- #150 +//│ let* (x$0) = b(16) in -- #4 +//│ x$0 -- #3 //│ //│ Interpreted: -//│ Cons(64,Cons(56,Cons(48,Cons(40,Cons(32,Cons(24,Cons(16,Cons(8,Cons(0,Nil()))))))))) +//│ Cons(64,0) :noTailRec :interpIR -class Cons(h, t) -class Nil fun foo(xs) = if xs is Cons(h, t) then @@ -1653,66 +1009,57 @@ fun foo(xs) = Nil then Nil foo(Cons(1, Cons(6, Cons(7, Cons(4, Cons(2, Cons(3, Cons(9, Nil)))))))) -//│ |#class| |Cons|(|h|,| |t|)|↵|#class| |Nil|↵|#fun| |foo|(|xs|)| |#=|→|#if| |xs| |is| |→|Cons|(|h|,| |t|)| |#then|→|#if| |h| |>| |5| |#then| |foo|(|t|)|↵|#else| |→|#val| |item| |#=| |#if| |h| |<| |3| |#then| |-|1| |#else| |100| |↵|Cons|(|item|,| |Cons|(|h|,| |foo|(|t|)|)|)|←|←|↵|Nil| |#then| |→|Nil|←|←|←|↵|foo|(|Cons|(|1|,| |Cons|(|6|,| |Cons|(|7|,| |Cons|(|4|,| |Cons|(|2|,| |Cons|(|3|,| |Cons|(|9|,| |Nil|)|)|)|)|)|)|)|)| -//│ Parsed: {class Cons(h, t,) {}; class Nil {}; fun foo = (xs,) => {if xs is ‹(Cons(h, t,)) then {if (>(h,)(5,)) then foo(t,) else {let item = if (<(h,)(3,)) then -1 else 100; Cons(item, Cons(h, foo(t,),),)}}; (Nil) then {Nil}›}; foo(Cons(1, Cons(6, Cons(7, Cons(4, Cons(2, Cons(3, Cons(9, Nil,),),),),),),),)} -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Cons, [h,t]),ClassInfo(3, Nil, [])}, { -//│ Def(0, foo, [xs$0], -//│ 1, -//│ case xs$0 of -- #54 -//│ Cons => -//│ let x$1 = xs$0.t in -- #50 -//│ let x$2 = xs$0.h in -- #49 -//│ let x$3 = >(x$2,5) in -- #48 -//│ if x$3 -- #47 -//│ true => -//│ let* (x$5) = foo(x$1) in -- #17 -//│ jump j$1(x$5) -- #16 -//│ false => -//│ let x$6 = <(x$2,3) in -- #46 -//│ if x$6 -- #45 +//│ |#fun| |foo|(|xs|)| |#=|→|#if| |xs| |is| |→|Cons|(|h|,| |t|)| |#then|→|#if| |h| |>| |5| |#then| |foo|(|t|)|↵|#else| |→|#val| |item| |#=| |#if| |h| |<| |3| |#then| |-|1| |#else| |100| |↵|Cons|(|item|,| |Cons|(|h|,| |foo|(|t|)|)|)|←|←|↵|Nil| |#then| |→|Nil|←|←|←|↵|foo|(|Cons|(|1|,| |Cons|(|6|,| |Cons|(|7|,| |Cons|(|4|,| |Cons|(|2|,| |Cons|(|3|,| |Cons|(|9|,| |Nil|)|)|)|)|)|)|)|)| +//│ Parsed: {fun foo = (xs,) => {if xs is ‹(Cons(h, t,)) then {if (>(h,)(5,)) then foo(t,) else {let item = if (<(h,)(3,)) then -1 else 100; Cons(item, Cons(h, foo(t,),),)}}; (Nil) then {Nil}›}; foo(Cons(1, Cons(6, Cons(7, Cons(4, Cons(2, Cons(3, Cons(9, Nil,),),),),),),),)} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def foo(xs$0) = +//│ case xs$0 of -- #104 +//│ Cons => +//│ let x$10 = Cons.t(xs$0) in -- #100 +//│ let x$11 = Cons.h(xs$0) in -- #99 +//│ let x$12 = >(x$11,5) in -- #98 +//│ if x$12 -- #97 //│ true => -//│ jump j$2(-1,x$1,x$2) -- #42 +//│ let* (x$14) = foo(x$10) in -- #68 +//│ jump j$1(x$14) -- #67 //│ false => -//│ jump j$2(100,x$1,x$2) -- #44 -//│ Nil => -//│ let x$11 = Nil() in -- #53 -//│ jump j$0(x$11) -- #52 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, j$1, [x$4], -//│ 1, -//│ jump j$0(x$4) -- #10 -//│ ) -//│ Def(3, j$2, [x$7,x$1,x$2], -//│ 1, -//│ let* (x$8) = foo(x$1) in -- #40 -//│ let x$9 = Cons(x$2,x$8) in -- #39 -//│ let x$10 = Cons(x$7,x$9) in -- #38 -//│ jump j$1(x$10) -- #37 -//│ ) -//│ }, -//│ let x$12 = Nil() in -- #103 -//│ let x$13 = Cons(9,x$12) in -- #102 -//│ let x$14 = Cons(3,x$13) in -- #101 -//│ let x$15 = Cons(2,x$14) in -- #100 -//│ let x$16 = Cons(4,x$15) in -- #99 -//│ let x$17 = Cons(7,x$16) in -- #98 -//│ let x$18 = Cons(6,x$17) in -- #97 -//│ let x$19 = Cons(1,x$18) in -- #96 -//│ let* (x$20) = foo(x$19) in -- #95 -//│ x$20 -- #94) +//│ let x$15 = <(x$11,3) in -- #96 +//│ if x$15 -- #95 +//│ true => +//│ jump j$2(-1,x$10,x$11) -- #92 +//│ false => +//│ jump j$2(100,x$10,x$11) -- #94 +//│ Nil => +//│ let x$20 = Nil() in -- #103 +//│ jump j$0(x$20) -- #102 +//│ def j$0(x$9) = +//│ x$9 -- #49 +//│ def j$1(x$13) = +//│ jump j$0(x$13) -- #62 +//│ def j$2(x$16,x$10,x$11) = +//│ let* (x$17) = foo(x$10) in -- #90 +//│ let x$18 = Cons(x$11,x$17) in -- #89 +//│ let x$19 = Cons(x$16,x$18) in -- #88 +//│ jump j$1(x$19) -- #87 +//│ let x$0 = Nil() in -- #47 +//│ let x$1 = Cons(9,x$0) in -- #46 +//│ let x$2 = Cons(3,x$1) in -- #45 +//│ let x$3 = Cons(2,x$2) in -- #44 +//│ let x$4 = Cons(4,x$3) in -- #43 +//│ let x$5 = Cons(7,x$4) in -- #42 +//│ let x$6 = Cons(6,x$5) in -- #41 +//│ let x$7 = Cons(1,x$6) in -- #40 +//│ let* (x$8) = foo(x$7) in -- #39 +//│ x$8 -- #38 //│ //│ Interpreted: //│ Cons(-1,Cons(1,Cons(100,Cons(4,Cons(-1,Cons(2,Cons(100,Cons(3,Nil())))))))) :interpIR -class Cons(h, t) -class Nil @tailrec fun foo(xs) = if xs is Cons(h, t) then @@ -1723,241 +1070,131 @@ class Nil Nil then Nil foo(Cons(1, Cons(6, Cons(7, Cons(4, Cons(2, Cons(3, Cons(9, Nil)))))))) -//│ |#class| |Cons|(|h|,| |t|)|↵|#class| |Nil|↵|@|tailrec| |#fun| |foo|(|xs|)| |#=|→|#if| |xs| |is| |→|Cons|(|h|,| |t|)| |#then|→|#if| |h| |>| |5| |#then| |@|tailcall| |foo|(|t|)|↵|#else| |→|#val| |item| |#=| |#if| |h| |<| |3| |#then| |-|1| |#else| |100| |↵|Cons|(|item|,| |Cons|(|h|,| |@|tailcall| |foo|(|t|)|)|)|←|←|↵|Nil| |#then| |→|Nil|←|←|←|↵|foo|(|Cons|(|1|,| |Cons|(|6|,| |Cons|(|7|,| |Cons|(|4|,| |Cons|(|2|,| |Cons|(|3|,| |Cons|(|9|,| |Nil|)|)|)|)|)|)|)|)| -//│ Parsed: {class Cons(h, t,) {}; class Nil {}; fun foo = (xs,) => {if xs is ‹(Cons(h, t,)) then {if (>(h,)(5,)) then @tailcall foo(t,) else {let item = if (<(h,)(3,)) then -1 else 100; Cons(item, Cons(h, @tailcall foo(t,),),)}}; (Nil) then {Nil}›}; foo(Cons(1, Cons(6, Cons(7, Cons(4, Cons(2, Cons(3, Cons(9, Nil,),),),),),),),)} +//│ |@|tailrec| |#fun| |foo|(|xs|)| |#=|→|#if| |xs| |is| |→|Cons|(|h|,| |t|)| |#then|→|#if| |h| |>| |5| |#then| |@|tailcall| |foo|(|t|)|↵|#else| |→|#val| |item| |#=| |#if| |h| |<| |3| |#then| |-|1| |#else| |100| |↵|Cons|(|item|,| |Cons|(|h|,| |@|tailcall| |foo|(|t|)|)|)|←|←|↵|Nil| |#then| |→|Nil|←|←|←|↵|foo|(|Cons|(|1|,| |Cons|(|6|,| |Cons|(|7|,| |Cons|(|4|,| |Cons|(|2|,| |Cons|(|3|,| |Cons|(|9|,| |Nil|)|)|)|)|)|)|)|)| +//│ Parsed: {fun foo = (xs,) => {if xs is ‹(Cons(h, t,)) then {if (>(h,)(5,)) then @tailcall foo(t,) else {let item = if (<(h,)(3,)) then -1 else 100; Cons(item, Cons(h, @tailcall foo(t,),),)}}; (Nil) then {Nil}›}; foo(Cons(1, Cons(6, Cons(7, Cons(4, Cons(2, Cons(3, Cons(9, Nil,),),),),),),),)} +//│ //│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Cons, [h,t]),ClassInfo(3, Nil, [])}, { -//│ Def(0, foo, [xs$0], -//│ 1, -//│ case xs$0 of -- #54 -//│ Cons => -//│ let x$1 = xs$0.t in -- #50 -//│ let x$2 = xs$0.h in -- #49 -//│ let x$3 = >(x$2,5) in -- #48 -//│ if x$3 -- #47 -//│ true => -//│ let* (x$5) = @tailcall foo(x$1) in -- #17 -//│ jump j$1(x$5) -- #16 -//│ false => -//│ let x$6 = <(x$2,3) in -- #46 -//│ if x$6 -- #45 -//│ true => -//│ jump j$2(-1,x$1,x$2) -- #42 -//│ false => -//│ jump j$2(100,x$1,x$2) -- #44 -//│ Nil => -//│ let x$11 = Nil() in -- #53 -//│ jump j$0(x$11) -- #52 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, j$1, [x$4], -//│ 1, -//│ jump j$0(x$4) -- #10 -//│ ) -//│ Def(3, j$2, [x$7,x$1,x$2], -//│ 1, -//│ let* (x$8) = @tailcall foo(x$1) in -- #40 -//│ let x$9 = Cons(x$2,x$8) in -- #39 -//│ let x$10 = Cons(x$7,x$9) in -- #38 -//│ jump j$1(x$10) -- #37 -//│ ) -//│ }, -//│ let x$12 = Nil() in -- #103 -//│ let x$13 = Cons(9,x$12) in -- #102 -//│ let x$14 = Cons(3,x$13) in -- #101 -//│ let x$15 = Cons(2,x$14) in -- #100 -//│ let x$16 = Cons(4,x$15) in -- #99 -//│ let x$17 = Cons(7,x$16) in -- #98 -//│ let x$18 = Cons(6,x$17) in -- #97 -//│ let x$19 = Cons(1,x$18) in -- #96 -//│ let* (x$20) = foo(x$19) in -- #95 -//│ x$20 -- #94) +//│ Program: //│ -//│ Strongly Connected Tail Calls: -//│ List(Set(j$1), Set(j$0), Set(foo)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Cons, [h,t]),ClassInfo(3, Nil, []),ClassInfo(4, _IdContext, []),ClassInfo(5, _Context, [acc,ptr,field])}, { -//│ Def(0, foo, [xs$0], -//│ 1, -//│ let idCtx = _IdContext() in -- #137 -//│ let* (res) = foo_modcons$7(idCtx,xs$0) in -- #136 -//│ res -- #135 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, j$1, [x$4], -//│ 1, -//│ jump j$0(x$4) -- #10 -//│ ) -//│ Def(4, _foo_ctx_app$4, [ctx,x], -//│ 1, -//│ case ctx of -- #110 -//│ _IdContext => -//│ x -- #109 -//│ _Context => -//│ let field = ctx.field in -- #108 -//│ let ptr = ctx.ptr in -- #107 -//│ let _ = assign ptr.t := x in -- #106 -//│ let acc = ctx.acc in -- #105 -//│ acc -- #104 -//│ ) -//│ Def(5, _foo_ctx_comp$5, [ctx1,ctx2], -//│ 1, -//│ let ctx2acc = ctx2.acc in -- #116 -//│ let ctx2ptr = ctx2.ptr in -- #115 -//│ let ctx2field = ctx2.field in -- #114 -//│ let* (newAcc) = _foo_ctx_app$4(ctx1,ctx2acc) in -- #113 -//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #112 -//│ ret -- #111 -//│ ) -//│ Def(7, foo_modcons$7, [ctx,xs$0], -//│ 1, -//│ let* (r0) = _foo_modcons$7_j$2_modcons$6_opt$8(7,ctx,xs$0,undefined,undefined,undefined,undefined) in -- #173 -//│ r0 -- #172 -//│ ) -//│ Def(8, _foo_modcons$7_j$2_modcons$6_opt$8, [tailrecBranch$,foo_modcons$7_ctx,foo_modcons$7_xs$0,j$2_modcons$6_ctx,j$2_modcons$6_x$7,j$2_modcons$6_x$1,j$2_modcons$6_x$2], -//│ 1, -//│ jump _foo_modcons$7_j$2_modcons$6_opt_jp$9(tailrecBranch$,foo_modcons$7_ctx,foo_modcons$7_xs$0,j$2_modcons$6_ctx,j$2_modcons$6_x$7,j$2_modcons$6_x$1,j$2_modcons$6_x$2) -- #171 -//│ ) -//│ Def(9, _foo_modcons$7_j$2_modcons$6_opt_jp$9, [tailrecBranch$,foo_modcons$7_ctx,foo_modcons$7_xs$0,j$2_modcons$6_ctx,j$2_modcons$6_x$7,j$2_modcons$6_x$1,j$2_modcons$6_x$2], -//│ 1, -//│ let scrut = ==(6,tailrecBranch$) in -- #170 -//│ if scrut -- #169 -//│ true => -//│ let x$9 = Cons(j$2_modcons$6_x$2,0) in -- #168 -//│ let x$10 = Cons(j$2_modcons$6_x$7,x$9) in -- #167 -//│ let ctx2 = _Context(x$10,x$9,0) in -- #166 -//│ let* (composed) = _foo_ctx_comp$5(j$2_modcons$6_ctx,ctx2) in -- #165 -//│ jump _foo_modcons$7_j$2_modcons$6_opt_jp$9(7,composed,j$2_modcons$6_x$1,j$2_modcons$6_ctx,j$2_modcons$6_x$7,j$2_modcons$6_x$1,j$2_modcons$6_x$2) -- #164 -//│ false => -//│ case foo_modcons$7_xs$0 of -- #163 +//│ def foo(xs$0) = +//│ case xs$0 of -- #104 //│ Cons => -//│ let x$1 = foo_modcons$7_xs$0.t in -- #159 -//│ let x$2 = foo_modcons$7_xs$0.h in -- #158 -//│ let x$3 = >(x$2,5) in -- #157 -//│ if x$3 -- #156 +//│ let x$10 = Cons.t(xs$0) in -- #100 +//│ let x$11 = Cons.h(xs$0) in -- #99 +//│ let x$12 = >(x$11,5) in -- #98 +//│ if x$12 -- #97 //│ true => -//│ jump _foo_modcons$7_j$2_modcons$6_opt_jp$9(7,foo_modcons$7_ctx,x$1,j$2_modcons$6_ctx,j$2_modcons$6_x$7,j$2_modcons$6_x$1,j$2_modcons$6_x$2) -- #151 +//│ let* (x$14) = @tailcall foo(x$10) in -- #68 +//│ jump j$1(x$14) -- #67 //│ false => -//│ let x$6 = <(x$2,3) in -- #155 -//│ if x$6 -- #154 +//│ let x$15 = <(x$11,3) in -- #96 +//│ if x$15 -- #95 //│ true => -//│ jump _foo_modcons$7_j$2_modcons$6_opt_jp$9(6,foo_modcons$7_ctx,foo_modcons$7_xs$0,foo_modcons$7_ctx,-1,x$1,x$2) -- #152 +//│ jump j$2(-1,x$10,x$11) -- #92 //│ false => -//│ jump _foo_modcons$7_j$2_modcons$6_opt_jp$9(6,foo_modcons$7_ctx,foo_modcons$7_xs$0,foo_modcons$7_ctx,100,x$1,x$2) -- #153 +//│ jump j$2(100,x$10,x$11) -- #94 //│ Nil => -//│ let x$11 = Nil() in -- #162 -//│ let* (res) = _foo_ctx_app$4(foo_modcons$7_ctx,x$11) in -- #161 -//│ res -- #160 -//│ ) -//│ }, -//│ let x$12 = Nil() in -- #103 -//│ let x$13 = Cons(9,x$12) in -- #102 -//│ let x$14 = Cons(3,x$13) in -- #101 -//│ let x$15 = Cons(2,x$14) in -- #100 -//│ let x$16 = Cons(4,x$15) in -- #99 -//│ let x$17 = Cons(7,x$16) in -- #98 -//│ let x$18 = Cons(6,x$17) in -- #97 -//│ let x$19 = Cons(1,x$18) in -- #96 -//│ let* (x$20) = foo(x$19) in -- #95 -//│ x$20 -- #94) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, Cons, [h,t]),ClassInfo(3, Nil, []),ClassInfo(4, _IdContext, []),ClassInfo(5, _Context, [acc,ptr,field])}, { -//│ Def(0, foo, [xs$0], -//│ 1, -//│ let idCtx = _IdContext() in -- #137 -//│ let* (res) = foo_modcons$7(idCtx,xs$0) in -- #136 -//│ res -- #135 -//│ ) -//│ Def(1, j$0, [x$0], -//│ 1, -//│ x$0 -- #1 -//│ ) -//│ Def(2, j$1, [x$4], -//│ 1, -//│ jump j$0(x$4) -- #10 -//│ ) -//│ Def(4, _foo_ctx_app$4, [ctx,x], -//│ 1, -//│ case ctx of -- #110 -//│ _IdContext => -//│ x -- #109 -//│ _Context => -//│ let field = ctx.field in -- #108 -//│ let ptr = ctx.ptr in -- #107 -//│ let _ = assign ptr.t := x in -- #106 -//│ let acc = ctx.acc in -- #105 -//│ acc -- #104 -//│ ) -//│ Def(5, _foo_ctx_comp$5, [ctx1,ctx2], -//│ 1, -//│ let ctx2acc = ctx2.acc in -- #116 -//│ let ctx2ptr = ctx2.ptr in -- #115 -//│ let ctx2field = ctx2.field in -- #114 -//│ let* (newAcc) = _foo_ctx_app$4(ctx1,ctx2acc) in -- #113 -//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #112 -//│ ret -- #111 -//│ ) -//│ Def(7, foo_modcons$7, [ctx,xs$0], -//│ 1, -//│ let* (r0) = _foo_modcons$7_j$2_modcons$6_opt$8(7,ctx,xs$0,undefined,undefined,undefined,undefined) in -- #173 -//│ r0 -- #172 -//│ ) -//│ Def(8, _foo_modcons$7_j$2_modcons$6_opt$8, [tailrecBranch$,foo_modcons$7_ctx,foo_modcons$7_xs$0,j$2_modcons$6_ctx,j$2_modcons$6_x$7,j$2_modcons$6_x$1,j$2_modcons$6_x$2], -//│ 1, -//│ jump _foo_modcons$7_j$2_modcons$6_opt_jp$9(tailrecBranch$,foo_modcons$7_ctx,foo_modcons$7_xs$0,j$2_modcons$6_ctx,j$2_modcons$6_x$7,j$2_modcons$6_x$1,j$2_modcons$6_x$2) -- #171 -//│ ) -//│ Def(9, _foo_modcons$7_j$2_modcons$6_opt_jp$9, [tailrecBranch$,foo_modcons$7_ctx,foo_modcons$7_xs$0,j$2_modcons$6_ctx,j$2_modcons$6_x$7,j$2_modcons$6_x$1,j$2_modcons$6_x$2], -//│ 1, -//│ let scrut = ==(6,tailrecBranch$) in -- #170 -//│ if scrut -- #169 -//│ true => -//│ let x$9 = Cons(j$2_modcons$6_x$2,0) in -- #168 -//│ let x$10 = Cons(j$2_modcons$6_x$7,x$9) in -- #167 -//│ let ctx2 = _Context(x$10,x$9,0) in -- #166 -//│ let* (composed) = _foo_ctx_comp$5(j$2_modcons$6_ctx,ctx2) in -- #165 -//│ jump _foo_modcons$7_j$2_modcons$6_opt_jp$9(7,composed,j$2_modcons$6_x$1,j$2_modcons$6_ctx,j$2_modcons$6_x$7,j$2_modcons$6_x$1,j$2_modcons$6_x$2) -- #164 -//│ false => -//│ case foo_modcons$7_xs$0 of -- #163 -//│ Cons => -//│ let x$1 = foo_modcons$7_xs$0.t in -- #159 -//│ let x$2 = foo_modcons$7_xs$0.h in -- #158 -//│ let x$3 = >(x$2,5) in -- #157 -//│ if x$3 -- #156 -//│ true => -//│ jump _foo_modcons$7_j$2_modcons$6_opt_jp$9(7,foo_modcons$7_ctx,x$1,j$2_modcons$6_ctx,j$2_modcons$6_x$7,j$2_modcons$6_x$1,j$2_modcons$6_x$2) -- #151 -//│ false => -//│ let x$6 = <(x$2,3) in -- #155 -//│ if x$6 -- #154 +//│ let x$20 = Nil() in -- #103 +//│ jump j$0(x$20) -- #102 +//│ def j$0(x$9) = +//│ x$9 -- #49 +//│ def j$1(x$13) = +//│ jump j$0(x$13) -- #62 +//│ def j$2(x$16,x$10,x$11) = +//│ let* (x$17) = @tailcall foo(x$10) in -- #90 +//│ let x$18 = Cons(x$11,x$17) in -- #89 +//│ let x$19 = Cons(x$16,x$18) in -- #88 +//│ jump j$1(x$19) -- #87 +//│ let x$0 = Nil() in -- #47 +//│ let x$1 = Cons(9,x$0) in -- #46 +//│ let x$2 = Cons(3,x$1) in -- #45 +//│ let x$3 = Cons(2,x$2) in -- #44 +//│ let x$4 = Cons(4,x$3) in -- #43 +//│ let x$5 = Cons(7,x$4) in -- #42 +//│ let x$6 = Cons(6,x$5) in -- #41 +//│ let x$7 = Cons(1,x$6) in -- #40 +//│ let* (x$8) = foo(x$7) in -- #39 +//│ x$8 -- #38 +//│ +//│ +//│ Strongly Connected Tail Calls: +//│ List(Set(j$1), Set(j$0), Set(foo)) +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def foo(xs$0) = +//│ let idCtx = _IdContext() in -- #144 +//│ let* (res) = foo_modcons$13(idCtx,xs$0) in -- #143 +//│ res -- #142 +//│ def j$0(x$9) = +//│ x$9 -- #49 +//│ def j$1(x$13) = +//│ jump j$0(x$13) -- #62 +//│ def _foo_ctx_app$10(ctx,x) = +//│ case ctx of -- #117 +//│ _IdContext => +//│ x -- #116 +//│ _Context => +//│ let field = _Context.field(ctx) in -- #115 +//│ let ptr = _Context.ptr(ctx) in -- #114 +//│ let _ = assign ptr.t := x in -- #113 +//│ let acc = _Context.acc(ctx) in -- #112 +//│ acc -- #111 +//│ def _foo_ctx_comp$11(ctx1,ctx2) = +//│ let ctx2acc = _Context.acc(ctx2) in -- #123 +//│ let ctx2ptr = _Context.ptr(ctx2) in -- #122 +//│ let ctx2field = _Context.field(ctx2) in -- #121 +//│ let* (newAcc) = _foo_ctx_app$10(ctx1,ctx2acc) in -- #120 +//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #119 +//│ ret -- #118 +//│ def foo_modcons$13(ctx,xs$0) = +//│ let* (r0) = _foo_modcons$13_j$2_modcons$12_opt$14(13,ctx,xs$0,true,true,true,true) in -- #180 +//│ r0 -- #179 +//│ def _foo_modcons$13_j$2_modcons$12_opt$14(tailrecBranch$,foo_modcons$13_ctx,foo_modcons$13_xs$0,j$2_modcons$12_ctx,j$2_modcons$12_x$16,j$2_modcons$12_x$10,j$2_modcons$12_x$11) = +//│ jump _foo_modcons$13_j$2_modcons$12_opt_jp$15(tailrecBranch$,foo_modcons$13_ctx,foo_modcons$13_xs$0,j$2_modcons$12_ctx,j$2_modcons$12_x$16,j$2_modcons$12_x$10,j$2_modcons$12_x$11) -- #178 +//│ def _foo_modcons$13_j$2_modcons$12_opt_jp$15(tailrecBranch$,foo_modcons$13_ctx,foo_modcons$13_xs$0,j$2_modcons$12_ctx,j$2_modcons$12_x$16,j$2_modcons$12_x$10,j$2_modcons$12_x$11) = +//│ let scrut = ==(12,tailrecBranch$) in -- #177 +//│ if scrut -- #176 +//│ true => +//│ let x$18 = Cons(j$2_modcons$12_x$11,0) in -- #175 +//│ let x$19 = Cons(j$2_modcons$12_x$16,x$18) in -- #174 +//│ let ctx2 = _Context(x$19,x$18,0) in -- #173 +//│ let* (composed) = _foo_ctx_comp$11(j$2_modcons$12_ctx,ctx2) in -- #172 +//│ jump _foo_modcons$13_j$2_modcons$12_opt_jp$15(13,composed,j$2_modcons$12_x$10,j$2_modcons$12_ctx,j$2_modcons$12_x$16,j$2_modcons$12_x$10,j$2_modcons$12_x$11) -- #171 +//│ false => +//│ case foo_modcons$13_xs$0 of -- #170 +//│ Cons => +//│ let x$10 = Cons.t(foo_modcons$13_xs$0) in -- #166 +//│ let x$11 = Cons.h(foo_modcons$13_xs$0) in -- #165 +//│ let x$12 = >(x$11,5) in -- #164 +//│ if x$12 -- #163 //│ true => -//│ jump _foo_modcons$7_j$2_modcons$6_opt_jp$9(6,foo_modcons$7_ctx,foo_modcons$7_xs$0,foo_modcons$7_ctx,-1,x$1,x$2) -- #152 +//│ jump _foo_modcons$13_j$2_modcons$12_opt_jp$15(13,foo_modcons$13_ctx,x$10,j$2_modcons$12_ctx,j$2_modcons$12_x$16,j$2_modcons$12_x$10,j$2_modcons$12_x$11) -- #158 //│ false => -//│ jump _foo_modcons$7_j$2_modcons$6_opt_jp$9(6,foo_modcons$7_ctx,foo_modcons$7_xs$0,foo_modcons$7_ctx,100,x$1,x$2) -- #153 -//│ Nil => -//│ let x$11 = Nil() in -- #162 -//│ let* (res) = _foo_ctx_app$4(foo_modcons$7_ctx,x$11) in -- #161 -//│ res -- #160 -//│ ) -//│ }, -//│ let x$12 = Nil() in -- #103 -//│ let x$13 = Cons(9,x$12) in -- #102 -//│ let x$14 = Cons(3,x$13) in -- #101 -//│ let x$15 = Cons(2,x$14) in -- #100 -//│ let x$16 = Cons(4,x$15) in -- #99 -//│ let x$17 = Cons(7,x$16) in -- #98 -//│ let x$18 = Cons(6,x$17) in -- #97 -//│ let x$19 = Cons(1,x$18) in -- #96 -//│ let* (x$20) = foo(x$19) in -- #95 -//│ x$20 -- #94) +//│ let x$15 = <(x$11,3) in -- #162 +//│ if x$15 -- #161 +//│ true => +//│ jump _foo_modcons$13_j$2_modcons$12_opt_jp$15(12,foo_modcons$13_ctx,foo_modcons$13_xs$0,foo_modcons$13_ctx,-1,x$10,x$11) -- #159 +//│ false => +//│ jump _foo_modcons$13_j$2_modcons$12_opt_jp$15(12,foo_modcons$13_ctx,foo_modcons$13_xs$0,foo_modcons$13_ctx,100,x$10,x$11) -- #160 +//│ Nil => +//│ let x$20 = Nil() in -- #169 +//│ let* (res) = _foo_ctx_app$10(foo_modcons$13_ctx,x$20) in -- #168 +//│ res -- #167 +//│ let x$0 = Nil() in -- #47 +//│ let x$1 = Cons(9,x$0) in -- #46 +//│ let x$2 = Cons(3,x$1) in -- #45 +//│ let x$3 = Cons(2,x$2) in -- #44 +//│ let x$4 = Cons(4,x$3) in -- #43 +//│ let x$5 = Cons(7,x$4) in -- #42 +//│ let x$6 = Cons(6,x$5) in -- #41 +//│ let x$7 = Cons(1,x$6) in -- #40 +//│ let* (x$8) = foo(x$7) in -- #39 +//│ x$8 -- #38 //│ //│ Interpreted: -//│ Cons(-1,Cons(1,Cons(100,Cons(4,Cons(-1,Cons(2,Cons(100,Cons(3,Nil())))))))) +//│ Cons(-1,Cons(1,0)) :ce fun b() = @@ -1971,117 +1208,65 @@ a() //│ |#fun| |b|(||)| |#=|→|a|(||)|↵|a|(||)|←|↵|@|tailrec| |↵|#fun| |a|(||)| |#=| |→|#if| |0| |<| |1| |#then| |a|(||)|↵|#else| |b|(||)|←|↵|a|(||)| //│ Parsed: {fun b = () => {a(); a()}; fun a = () => {if (<(0,)(1,)) then a() else b()}; a()} //│ +//│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, [])}, { -//│ Def(0, b, [], -//│ 1, -//│ let* (x$0) = a() in -- #7 -//│ let* (x$1) = a() in -- #6 -//│ x$1 -- #5 -//│ ) -//│ Def(1, a, [], -//│ 1, -//│ let x$2 = <(0,1) in -- #23 -//│ if x$2 -- #22 -//│ true => -//│ let* (x$4) = a() in -- #16 -//│ jump j$0(x$4) -- #15 -//│ false => -//│ let* (x$5) = b() in -- #21 -//│ jump j$0(x$5) -- #20 -//│ ) -//│ Def(2, j$0, [x$3], -//│ 1, -//│ x$3 -- #11 -//│ ) -//│ }, -//│ let* (x$6) = a() in -- #27 -//│ x$6 -- #26) +//│ Program: +//│ +//│ def b() = +//│ let* (x$1) = a() in -- #8 +//│ let* (x$2) = a() in -- #7 +//│ x$2 -- #6 +//│ def a() = +//│ let x$3 = <(0,1) in -- #22 +//│ if x$3 -- #21 +//│ true => +//│ let* (x$5) = a() in -- #16 +//│ jump j$0(x$5) -- #15 +//│ false => +//│ let* (x$6) = b() in -- #20 +//│ jump j$0(x$6) -- #19 +//│ def j$0(x$4) = +//│ x$4 -- #12 +//│ let* (x$0) = a() in -- #2 +//│ x$0 -- #1 //│ ╔══[COMPILATION ERROR] function `a` is not tail-recursive, but is marked as @tailrec -//│ ║ l.1966: @tailrec +//│ ║ l.1203: @tailrec //│ ║ ^^^^^^^ //│ ╟── it could self-recurse through this call, which may not be a tail-call -//│ ║ l.1964: a() +//│ ║ l.1201: a() //│ ╙── ^ //│ +//│ //│ Strongly Connected Tail Calls: //│ List(Set(j$0), Set(a, b)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(0, b, [], -//│ 1, -//│ let* (r0) = _a_b_opt$3(0) in -- #44 -//│ r0 -- #43 -//│ ) -//│ Def(1, a, [], -//│ 1, -//│ let* (r0) = _a_b_opt$3(1) in -- #42 -//│ r0 -- #41 -//│ ) -//│ Def(2, j$0, [x$3], -//│ 1, -//│ x$3 -- #11 -//│ ) -//│ Def(3, _a_b_opt$3, [tailrecBranch$], -//│ 1, -//│ jump _a_b_opt_jp$4(tailrecBranch$) -- #40 -//│ ) -//│ Def(4, _a_b_opt_jp$4, [tailrecBranch$], -//│ 1, -//│ let scrut = ==(0,tailrecBranch$) in -- #39 -//│ if scrut -- #38 -//│ true => -//│ let* (x$0) = a() in -- #37 -//│ jump _a_b_opt_jp$4(1) -- #36 -//│ false => -//│ let x$2 = <(0,1) in -- #35 -//│ if x$2 -- #34 +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def b() = +//│ let* (r0) = _a_b_opt$9(0) in -- #45 +//│ r0 -- #44 +//│ def a() = +//│ let* (r0) = _a_b_opt$9(1) in -- #43 +//│ r0 -- #42 +//│ def j$0(x$4) = +//│ x$4 -- #12 +//│ def _a_b_opt$9(tailrecBranch$) = +//│ jump _a_b_opt_jp$10(tailrecBranch$) -- #41 +//│ def _a_b_opt_jp$10(tailrecBranch$) = +//│ let scrut = ==(0,tailrecBranch$) in -- #40 +//│ if scrut -- #39 //│ true => -//│ jump _a_b_opt_jp$4(1) -- #32 +//│ let* (x$1) = a() in -- #38 +//│ jump _a_b_opt_jp$10(1) -- #37 //│ false => -//│ jump _a_b_opt_jp$4(0) -- #33 -//│ ) -//│ }, -//│ let* (x$6) = a() in -- #27 -//│ x$6 -- #26) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(0, b, [], -//│ 1, -//│ let* (r0) = _a_b_opt$3(0) in -- #44 -//│ r0 -- #43 -//│ ) -//│ Def(1, a, [], -//│ 1, -//│ let* (r0) = _a_b_opt$3(1) in -- #42 -//│ r0 -- #41 -//│ ) -//│ Def(2, j$0, [x$3], -//│ 1, -//│ x$3 -- #11 -//│ ) -//│ Def(3, _a_b_opt$3, [tailrecBranch$], -//│ 1, -//│ jump _a_b_opt_jp$4(tailrecBranch$) -- #40 -//│ ) -//│ Def(4, _a_b_opt_jp$4, [tailrecBranch$], -//│ 1, -//│ let scrut = ==(0,tailrecBranch$) in -- #39 -//│ if scrut -- #38 -//│ true => -//│ let* (x$0) = a() in -- #37 -//│ jump _a_b_opt_jp$4(1) -- #36 -//│ false => -//│ let x$2 = <(0,1) in -- #35 -//│ if x$2 -- #34 -//│ true => -//│ jump _a_b_opt_jp$4(1) -- #32 -//│ false => -//│ jump _a_b_opt_jp$4(0) -- #33 -//│ ) -//│ }, -//│ let* (x$6) = a() in -- #27 -//│ x$6 -- #26) +//│ let x$3 = <(0,1) in -- #36 +//│ if x$3 -- #35 +//│ true => +//│ jump _a_b_opt_jp$10(1) -- #33 +//│ false => +//│ jump _a_b_opt_jp$10(0) -- #34 +//│ let* (x$0) = a() in -- #2 +//│ x$0 -- #1 :ce class A(a, b) @@ -2093,229 +1278,111 @@ a() //│ |#class| |A|(|a|,| |b|)|↵|@|tailrec|↵|#fun| |a|(||)| |#=| |A|(|b|(||)|,| |1|)|↵|#fun| |b|(||)| |#=| |A|(|c|(||)|,| |@|tailcall| |a|(||)|)|↵|#fun| |c|(||)| |#=| |A|(|b|(||)|,| |1|)|↵|a|(||)| //│ Parsed: {class A(a, b,) {}; fun a = () => A(b(), 1,); fun b = () => A(c(), @tailcall a(),); fun c = () => A(b(), 1,); a()} //│ +//│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, A, [a,b])}, { -//│ Def(0, a, [], -//│ 1, -//│ let* (x$0) = b() in -- #9 -//│ let x$1 = A(x$0,1) in -- #8 -//│ x$1 -- #7 -//│ ) -//│ Def(1, b, [], -//│ 1, -//│ let* (x$2) = c() in -- #22 -//│ let* (x$3) = @tailcall a() in -- #21 -//│ let x$4 = A(x$2,x$3) in -- #20 -//│ x$4 -- #19 -//│ ) -//│ Def(2, c, [], -//│ 1, -//│ let* (x$5) = b() in -- #32 -//│ let x$6 = A(x$5,1) in -- #31 -//│ x$6 -- #30 -//│ ) -//│ }, -//│ let* (x$7) = a() in -- #36 -//│ x$7 -- #35) +//│ Program: +//│ class A(a,b) +//│ def a() = +//│ let* (x$1) = b() in -- #11 +//│ let x$2 = A(x$1,1) in -- #10 +//│ x$2 -- #9 +//│ def b() = +//│ let* (x$3) = c() in -- #22 +//│ let* (x$4) = @tailcall a() in -- #21 +//│ let x$5 = A(x$3,x$4) in -- #20 +//│ x$5 -- #19 +//│ def c() = +//│ let* (x$6) = b() in -- #31 +//│ let x$7 = A(x$6,1) in -- #30 +//│ x$7 -- #29 +//│ let* (x$0) = a() in -- #2 +//│ x$0 -- #1 //│ ╔══[COMPILATION ERROR] function `a` is not tail-recursive, but is marked as @tailrec -//│ ║ l.2088: @tailrec +//│ ║ l.1273: @tailrec //│ ║ ^^^^^^^ //│ ╟── it could self-recurse through this call, which may not be a tail-call -//│ ║ l.2090: fun b() = A(c(), @tailcall a()) +//│ ║ l.1275: fun b() = A(c(), @tailcall a()) //│ ╙── ^ //│ +//│ //│ Strongly Connected Tail Calls: //│ List(Set(c, b, a)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, A, [a,b]),ClassInfo(3, _IdContext, []),ClassInfo(4, _Context, [acc,ptr,field])}, { -//│ Def(0, a, [], -//│ 1, -//│ let idCtx = _IdContext() in -- #80 -//│ let* (res) = a_modcons$7(idCtx) in -- #79 -//│ res -- #78 -//│ ) -//│ Def(1, b, [], -//│ 1, -//│ let idCtx = _IdContext() in -- #72 -//│ let* (res) = b_modcons$6(idCtx) in -- #71 -//│ res -- #70 -//│ ) -//│ Def(2, c, [], -//│ 1, -//│ let idCtx = _IdContext() in -- #63 -//│ let* (res) = c_modcons$5(idCtx) in -- #62 -//│ res -- #61 -//│ ) -//│ Def(3, _c_b_a_ctx_app$3, [ctx,x], -//│ 1, -//│ case ctx of -- #49 -//│ _IdContext => -//│ x -- #48 -//│ _Context => -//│ let field = ctx.field in -- #47 -//│ let scrut = ==(1,field) in -- #46 -//│ if scrut -- #45 -//│ true => -//│ let ptr = ctx.ptr in -- #44 -//│ let _ = assign ptr.b := x in -- #43 -//│ let acc = ctx.acc in -- #42 -//│ acc -- #41 -//│ false => -//│ let ptr = ctx.ptr in -- #40 -//│ let _ = assign ptr.a := x in -- #39 -//│ let acc = ctx.acc in -- #38 -//│ acc -- #37 -//│ ) -//│ Def(4, _c_b_a_ctx_comp$4, [ctx1,ctx2], -//│ 1, -//│ let ctx2acc = ctx2.acc in -- #55 -//│ let ctx2ptr = ctx2.ptr in -- #54 -//│ let ctx2field = ctx2.field in -- #53 -//│ let* (newAcc) = _c_b_a_ctx_app$3(ctx1,ctx2acc) in -- #52 -//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #51 -//│ ret -- #50 -//│ ) -//│ Def(5, c_modcons$5, [ctx], -//│ 1, -//│ let* (r0) = _c_modcons$5_b_modcons$6_a_modcons$7_opt$8(5,ctx,undefined,undefined) in -- #104 -//│ r0 -- #103 -//│ ) -//│ Def(6, b_modcons$6, [ctx], -//│ 1, -//│ let* (r0) = _c_modcons$5_b_modcons$6_a_modcons$7_opt$8(6,undefined,ctx,undefined) in -- #106 -//│ r0 -- #105 -//│ ) -//│ Def(7, a_modcons$7, [ctx], -//│ 1, -//│ let* (r0) = _c_modcons$5_b_modcons$6_a_modcons$7_opt$8(7,undefined,undefined,ctx) in -- #108 -//│ r0 -- #107 -//│ ) -//│ Def(8, _c_modcons$5_b_modcons$6_a_modcons$7_opt$8, [tailrecBranch$,c_modcons$5_ctx,b_modcons$6_ctx,a_modcons$7_ctx], -//│ 1, -//│ jump _c_modcons$5_b_modcons$6_a_modcons$7_opt_jp$9(tailrecBranch$,c_modcons$5_ctx,b_modcons$6_ctx,a_modcons$7_ctx) -- #102 -//│ ) -//│ Def(9, _c_modcons$5_b_modcons$6_a_modcons$7_opt_jp$9, [tailrecBranch$,c_modcons$5_ctx,b_modcons$6_ctx,a_modcons$7_ctx], -//│ 1, -//│ let scrut = ==(7,tailrecBranch$) in -- #101 -//│ if scrut -- #100 -//│ true => -//│ let x$1 = A(0,1) in -- #97 -//│ let ctx2 = _Context(x$1,x$1,0) in -- #96 -//│ let* (composed) = _c_b_a_ctx_comp$4(a_modcons$7_ctx,ctx2) in -- #95 -//│ jump _c_modcons$5_b_modcons$6_a_modcons$7_opt_jp$9(6,c_modcons$5_ctx,composed,a_modcons$7_ctx) -- #94 -//│ false => -//│ let scrut = ==(6,tailrecBranch$) in -- #99 -//│ if scrut -- #98 -//│ true => -//│ let* (x$2) = c() in -- #93 -//│ let x$4 = A(x$2,0) in -- #92 -//│ let ctx2 = _Context(x$4,x$4,1) in -- #91 -//│ let* (composed) = _c_b_a_ctx_comp$4(b_modcons$6_ctx,ctx2) in -- #90 -//│ jump _c_modcons$5_b_modcons$6_a_modcons$7_opt_jp$9(7,c_modcons$5_ctx,b_modcons$6_ctx,composed) -- #89 -//│ false => -//│ let x$6 = A(0,1) in -- #88 -//│ let ctx2 = _Context(x$6,x$6,0) in -- #87 -//│ let* (composed) = _c_b_a_ctx_comp$4(c_modcons$5_ctx,ctx2) in -- #86 -//│ jump _c_modcons$5_b_modcons$6_a_modcons$7_opt_jp$9(6,c_modcons$5_ctx,composed,a_modcons$7_ctx) -- #85 -//│ ) -//│ }, -//│ let* (x$7) = a() in -- #36 -//│ x$7 -- #35) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, A, [a,b]),ClassInfo(3, _IdContext, []),ClassInfo(4, _Context, [acc,ptr,field])}, { -//│ Def(0, a, [], -//│ 1, -//│ let idCtx = _IdContext() in -- #80 -//│ let* (res) = a_modcons$7(idCtx) in -- #79 -//│ res -- #78 -//│ ) -//│ Def(1, b, [], -//│ 1, -//│ let idCtx = _IdContext() in -- #72 -//│ let* (res) = b_modcons$6(idCtx) in -- #71 -//│ res -- #70 -//│ ) -//│ Def(2, c, [], -//│ 1, -//│ let idCtx = _IdContext() in -- #63 -//│ let* (res) = c_modcons$5(idCtx) in -- #62 -//│ res -- #61 -//│ ) -//│ Def(3, _c_b_a_ctx_app$3, [ctx,x], -//│ 1, -//│ case ctx of -- #49 -//│ _IdContext => -//│ x -- #48 -//│ _Context => -//│ let field = ctx.field in -- #47 -//│ let scrut = ==(1,field) in -- #46 -//│ if scrut -- #45 -//│ true => -//│ let ptr = ctx.ptr in -- #44 -//│ let _ = assign ptr.b := x in -- #43 -//│ let acc = ctx.acc in -- #42 -//│ acc -- #41 -//│ false => -//│ let ptr = ctx.ptr in -- #40 -//│ let _ = assign ptr.a := x in -- #39 -//│ let acc = ctx.acc in -- #38 -//│ acc -- #37 -//│ ) -//│ Def(4, _c_b_a_ctx_comp$4, [ctx1,ctx2], -//│ 1, -//│ let ctx2acc = ctx2.acc in -- #55 -//│ let ctx2ptr = ctx2.ptr in -- #54 -//│ let ctx2field = ctx2.field in -- #53 -//│ let* (newAcc) = _c_b_a_ctx_app$3(ctx1,ctx2acc) in -- #52 -//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #51 -//│ ret -- #50 -//│ ) -//│ Def(5, c_modcons$5, [ctx], -//│ 1, -//│ let* (r0) = _c_modcons$5_b_modcons$6_a_modcons$7_opt$8(5,ctx,undefined,undefined) in -- #104 -//│ r0 -- #103 -//│ ) -//│ Def(6, b_modcons$6, [ctx], -//│ 1, -//│ let* (r0) = _c_modcons$5_b_modcons$6_a_modcons$7_opt$8(6,undefined,ctx,undefined) in -- #106 -//│ r0 -- #105 -//│ ) -//│ Def(7, a_modcons$7, [ctx], -//│ 1, -//│ let* (r0) = _c_modcons$5_b_modcons$6_a_modcons$7_opt$8(7,undefined,undefined,ctx) in -- #108 -//│ r0 -- #107 -//│ ) -//│ Def(8, _c_modcons$5_b_modcons$6_a_modcons$7_opt$8, [tailrecBranch$,c_modcons$5_ctx,b_modcons$6_ctx,a_modcons$7_ctx], -//│ 1, -//│ jump _c_modcons$5_b_modcons$6_a_modcons$7_opt_jp$9(tailrecBranch$,c_modcons$5_ctx,b_modcons$6_ctx,a_modcons$7_ctx) -- #102 -//│ ) -//│ Def(9, _c_modcons$5_b_modcons$6_a_modcons$7_opt_jp$9, [tailrecBranch$,c_modcons$5_ctx,b_modcons$6_ctx,a_modcons$7_ctx], -//│ 1, -//│ let scrut = ==(7,tailrecBranch$) in -- #101 -//│ if scrut -- #100 -//│ true => -//│ let x$1 = A(0,1) in -- #97 -//│ let ctx2 = _Context(x$1,x$1,0) in -- #96 -//│ let* (composed) = _c_b_a_ctx_comp$4(a_modcons$7_ctx,ctx2) in -- #95 -//│ jump _c_modcons$5_b_modcons$6_a_modcons$7_opt_jp$9(6,c_modcons$5_ctx,composed,a_modcons$7_ctx) -- #94 -//│ false => -//│ let scrut = ==(6,tailrecBranch$) in -- #99 -//│ if scrut -- #98 +//│ Program: +//│ class A(a,b) +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def a() = +//│ let idCtx = _IdContext() in -- #81 +//│ let* (res) = a_modcons$13(idCtx) in -- #80 +//│ res -- #79 +//│ def b() = +//│ let idCtx = _IdContext() in -- #73 +//│ let* (res) = b_modcons$12(idCtx) in -- #72 +//│ res -- #71 +//│ def c() = +//│ let idCtx = _IdContext() in -- #64 +//│ let* (res) = c_modcons$11(idCtx) in -- #63 +//│ res -- #62 +//│ def _c_b_a_ctx_app$9(ctx,x) = +//│ case ctx of -- #50 +//│ _IdContext => +//│ x -- #49 +//│ _Context => +//│ let field = _Context.field(ctx) in -- #48 +//│ let scrut = ==(1,field) in -- #47 +//│ if scrut -- #46 +//│ true => +//│ let ptr = _Context.ptr(ctx) in -- #45 +//│ let _ = assign ptr.b := x in -- #44 +//│ let acc = _Context.acc(ctx) in -- #43 +//│ acc -- #42 +//│ false => +//│ let ptr = _Context.ptr(ctx) in -- #41 +//│ let _ = assign ptr.a := x in -- #40 +//│ let acc = _Context.acc(ctx) in -- #39 +//│ acc -- #38 +//│ def _c_b_a_ctx_comp$10(ctx1,ctx2) = +//│ let ctx2acc = _Context.acc(ctx2) in -- #56 +//│ let ctx2ptr = _Context.ptr(ctx2) in -- #55 +//│ let ctx2field = _Context.field(ctx2) in -- #54 +//│ let* (newAcc) = _c_b_a_ctx_app$9(ctx1,ctx2acc) in -- #53 +//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #52 +//│ ret -- #51 +//│ def c_modcons$11(ctx) = +//│ let* (r0) = _c_modcons$11_b_modcons$12_a_modcons$13_opt$14(11,ctx,true,true) in -- #105 +//│ r0 -- #104 +//│ def b_modcons$12(ctx) = +//│ let* (r0) = _c_modcons$11_b_modcons$12_a_modcons$13_opt$14(12,true,ctx,true) in -- #107 +//│ r0 -- #106 +//│ def a_modcons$13(ctx) = +//│ let* (r0) = _c_modcons$11_b_modcons$12_a_modcons$13_opt$14(13,true,true,ctx) in -- #109 +//│ r0 -- #108 +//│ def _c_modcons$11_b_modcons$12_a_modcons$13_opt$14(tailrecBranch$,c_modcons$11_ctx,b_modcons$12_ctx,a_modcons$13_ctx) = +//│ jump _c_modcons$11_b_modcons$12_a_modcons$13_opt_jp$15(tailrecBranch$,c_modcons$11_ctx,b_modcons$12_ctx,a_modcons$13_ctx) -- #103 +//│ def _c_modcons$11_b_modcons$12_a_modcons$13_opt_jp$15(tailrecBranch$,c_modcons$11_ctx,b_modcons$12_ctx,a_modcons$13_ctx) = +//│ let scrut = ==(13,tailrecBranch$) in -- #102 +//│ if scrut -- #101 //│ true => -//│ let* (x$2) = c() in -- #93 -//│ let x$4 = A(x$2,0) in -- #92 -//│ let ctx2 = _Context(x$4,x$4,1) in -- #91 -//│ let* (composed) = _c_b_a_ctx_comp$4(b_modcons$6_ctx,ctx2) in -- #90 -//│ jump _c_modcons$5_b_modcons$6_a_modcons$7_opt_jp$9(7,c_modcons$5_ctx,b_modcons$6_ctx,composed) -- #89 +//│ let x$2 = A(0,1) in -- #98 +//│ let ctx2 = _Context(x$2,x$2,0) in -- #97 +//│ let* (composed) = _c_b_a_ctx_comp$10(a_modcons$13_ctx,ctx2) in -- #96 +//│ jump _c_modcons$11_b_modcons$12_a_modcons$13_opt_jp$15(12,c_modcons$11_ctx,composed,a_modcons$13_ctx) -- #95 //│ false => -//│ let x$6 = A(0,1) in -- #88 -//│ let ctx2 = _Context(x$6,x$6,0) in -- #87 -//│ let* (composed) = _c_b_a_ctx_comp$4(c_modcons$5_ctx,ctx2) in -- #86 -//│ jump _c_modcons$5_b_modcons$6_a_modcons$7_opt_jp$9(6,c_modcons$5_ctx,composed,a_modcons$7_ctx) -- #85 -//│ ) -//│ }, -//│ let* (x$7) = a() in -- #36 -//│ x$7 -- #35) +//│ let scrut = ==(12,tailrecBranch$) in -- #100 +//│ if scrut -- #99 +//│ true => +//│ let* (x$3) = c() in -- #94 +//│ let x$5 = A(x$3,0) in -- #93 +//│ let ctx2 = _Context(x$5,x$5,1) in -- #92 +//│ let* (composed) = _c_b_a_ctx_comp$10(b_modcons$12_ctx,ctx2) in -- #91 +//│ jump _c_modcons$11_b_modcons$12_a_modcons$13_opt_jp$15(13,c_modcons$11_ctx,b_modcons$12_ctx,composed) -- #90 +//│ false => +//│ let x$7 = A(0,1) in -- #89 +//│ let ctx2 = _Context(x$7,x$7,0) in -- #88 +//│ let* (composed) = _c_b_a_ctx_comp$10(c_modcons$11_ctx,ctx2) in -- #87 +//│ jump _c_modcons$11_b_modcons$12_a_modcons$13_opt_jp$15(12,c_modcons$11_ctx,composed,a_modcons$13_ctx) -- #86 +//│ let* (x$0) = a() in -- #2 +//│ x$0 -- #1 // TODO: Purity check class A(a, b) @@ -2327,241 +1394,141 @@ a() //│ |#class| |A|(|a|,| |b|)|↵|@|tailrec|↵|#fun| |a|(||)| |#=| |A|(|b|(||)|,| |1|)|↵|#fun| |b|(||)| |#=| |A|(|@|tailcall| |a|(||)|,| |c|(||)|)|↵|#fun| |c|(||)| |#=| |A|(|0|,| |1|)|↵|a|(||)| //│ Parsed: {class A(a, b,) {}; fun a = () => A(b(), 1,); fun b = () => A(@tailcall a(), c(),); fun c = () => A(0, 1,); a()} //│ +//│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, A, [a,b])}, { -//│ Def(0, a, [], -//│ 1, -//│ let* (x$0) = b() in -- #9 -//│ let x$1 = A(x$0,1) in -- #8 -//│ x$1 -- #7 -//│ ) -//│ Def(1, b, [], -//│ 1, -//│ let* (x$2) = @tailcall a() in -- #22 -//│ let* (x$3) = c() in -- #21 -//│ let x$4 = A(x$2,x$3) in -- #20 -//│ x$4 -- #19 -//│ ) -//│ Def(2, c, [], -//│ 1, -//│ let x$5 = A(0,1) in -- #29 -//│ x$5 -- #28 -//│ ) -//│ }, -//│ let* (x$6) = a() in -- #33 -//│ x$6 -- #32) +//│ Program: +//│ class A(a,b) +//│ def a() = +//│ let* (x$1) = b() in -- #11 +//│ let x$2 = A(x$1,1) in -- #10 +//│ x$2 -- #9 +//│ def b() = +//│ let* (x$3) = @tailcall a() in -- #22 +//│ let* (x$4) = c() in -- #21 +//│ let x$5 = A(x$3,x$4) in -- #20 +//│ x$5 -- #19 +//│ def c() = +//│ let x$6 = A(0,1) in -- #29 +//│ x$6 -- #28 +//│ let* (x$0) = a() in -- #2 +//│ x$0 -- #1 //│ ╔══[COMPILATION ERROR] not a tail call, as the remaining functions may be impure -//│ ║ l.2324: fun b() = A(@tailcall a(), c()) +//│ ║ l.1391: fun b() = A(@tailcall a(), c()) //│ ╙── ^ //│ ╔══[COMPILATION ERROR] function `a` is not tail-recursive, but is marked as @tailrec -//│ ║ l.2322: @tailrec +//│ ║ l.1389: @tailrec //│ ║ ^^^^^^^ //│ ╟── it could self-recurse through this call, which may not be a tail-call -//│ ║ l.2324: fun b() = A(@tailcall a(), c()) +//│ ║ l.1391: fun b() = A(@tailcall a(), c()) //│ ╙── ^ //│ +//│ //│ Strongly Connected Tail Calls: //│ List(Set(b, a), Set(c)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, A, [a,b]),ClassInfo(3, _IdContext, []),ClassInfo(4, _Context, [acc,ptr,field])}, { -//│ Def(0, a, [], -//│ 1, -//│ let idCtx = _IdContext() in -- #62 -//│ let* (res) = a_modcons$6(idCtx) in -- #61 -//│ res -- #60 -//│ ) -//│ Def(1, b, [], -//│ 1, -//│ let idCtx = _IdContext() in -- #54 -//│ let* (res) = b_modcons$5(idCtx) in -- #53 -//│ res -- #52 -//│ ) -//│ Def(2, c, [], -//│ 1, -//│ let x$5 = A(0,1) in -- #29 -//│ x$5 -- #28 -//│ ) -//│ Def(3, _b_a_ctx_app$3, [ctx,x], -//│ 1, -//│ case ctx of -- #40 -//│ _IdContext => -//│ x -- #39 -//│ _Context => -//│ let field = ctx.field in -- #38 -//│ let ptr = ctx.ptr in -- #37 -//│ let _ = assign ptr.a := x in -- #36 -//│ let acc = ctx.acc in -- #35 -//│ acc -- #34 -//│ ) -//│ Def(4, _b_a_ctx_comp$4, [ctx1,ctx2], -//│ 1, -//│ let ctx2acc = ctx2.acc in -- #46 -//│ let ctx2ptr = ctx2.ptr in -- #45 -//│ let ctx2field = ctx2.field in -- #44 -//│ let* (newAcc) = _b_a_ctx_app$3(ctx1,ctx2acc) in -- #43 -//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #42 -//│ ret -- #41 -//│ ) -//│ Def(5, b_modcons$5, [ctx], -//│ 1, -//│ let* (r0) = _b_modcons$5_a_modcons$6_opt$7(5,ctx,undefined) in -- #81 -//│ r0 -- #80 -//│ ) -//│ Def(6, a_modcons$6, [ctx], -//│ 1, -//│ let* (r0) = _b_modcons$5_a_modcons$6_opt$7(6,undefined,ctx) in -- #83 -//│ r0 -- #82 -//│ ) -//│ Def(7, _b_modcons$5_a_modcons$6_opt$7, [tailrecBranch$,b_modcons$5_ctx,a_modcons$6_ctx], -//│ 1, -//│ jump _b_modcons$5_a_modcons$6_opt_jp$8(tailrecBranch$,b_modcons$5_ctx,a_modcons$6_ctx) -- #79 -//│ ) -//│ Def(8, _b_modcons$5_a_modcons$6_opt_jp$8, [tailrecBranch$,b_modcons$5_ctx,a_modcons$6_ctx], -//│ 1, -//│ let scrut = ==(6,tailrecBranch$) in -- #78 -//│ if scrut -- #77 -//│ true => -//│ let x$1 = A(0,1) in -- #76 -//│ let ctx2 = _Context(x$1,x$1,0) in -- #75 -//│ let* (composed) = _b_a_ctx_comp$4(a_modcons$6_ctx,ctx2) in -- #74 -//│ jump _b_modcons$5_a_modcons$6_opt_jp$8(5,composed,a_modcons$6_ctx) -- #73 -//│ false => -//│ let* (x$2) = @tailcall a() in -- #72 -//│ let* (x$3) = c() in -- #71 -//│ let x$4 = A(x$2,x$3) in -- #70 -//│ let* (res) = _b_a_ctx_app$3(b_modcons$5_ctx,x$4) in -- #69 -//│ res -- #68 -//│ ) -//│ }, -//│ let* (x$6) = a() in -- #33 -//│ x$6 -- #32) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, A, [a,b]),ClassInfo(3, _IdContext, []),ClassInfo(4, _Context, [acc,ptr,field])}, { -//│ Def(0, a, [], -//│ 1, -//│ let idCtx = _IdContext() in -- #62 -//│ let* (res) = a_modcons$6(idCtx) in -- #61 -//│ res -- #60 -//│ ) -//│ Def(1, b, [], -//│ 1, -//│ let idCtx = _IdContext() in -- #54 -//│ let* (res) = b_modcons$5(idCtx) in -- #53 -//│ res -- #52 -//│ ) -//│ Def(2, c, [], -//│ 1, -//│ let x$5 = A(0,1) in -- #29 -//│ x$5 -- #28 -//│ ) -//│ Def(3, _b_a_ctx_app$3, [ctx,x], -//│ 1, -//│ case ctx of -- #40 -//│ _IdContext => -//│ x -- #39 -//│ _Context => -//│ let field = ctx.field in -- #38 -//│ let ptr = ctx.ptr in -- #37 -//│ let _ = assign ptr.a := x in -- #36 -//│ let acc = ctx.acc in -- #35 -//│ acc -- #34 -//│ ) -//│ Def(4, _b_a_ctx_comp$4, [ctx1,ctx2], -//│ 1, -//│ let ctx2acc = ctx2.acc in -- #46 -//│ let ctx2ptr = ctx2.ptr in -- #45 -//│ let ctx2field = ctx2.field in -- #44 -//│ let* (newAcc) = _b_a_ctx_app$3(ctx1,ctx2acc) in -- #43 -//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #42 -//│ ret -- #41 -//│ ) -//│ Def(5, b_modcons$5, [ctx], -//│ 1, -//│ let* (r0) = _b_modcons$5_a_modcons$6_opt$7(5,ctx,undefined) in -- #81 -//│ r0 -- #80 -//│ ) -//│ Def(6, a_modcons$6, [ctx], -//│ 1, -//│ let* (r0) = _b_modcons$5_a_modcons$6_opt$7(6,undefined,ctx) in -- #83 -//│ r0 -- #82 -//│ ) -//│ Def(7, _b_modcons$5_a_modcons$6_opt$7, [tailrecBranch$,b_modcons$5_ctx,a_modcons$6_ctx], -//│ 1, -//│ jump _b_modcons$5_a_modcons$6_opt_jp$8(tailrecBranch$,b_modcons$5_ctx,a_modcons$6_ctx) -- #79 -//│ ) -//│ Def(8, _b_modcons$5_a_modcons$6_opt_jp$8, [tailrecBranch$,b_modcons$5_ctx,a_modcons$6_ctx], -//│ 1, -//│ let scrut = ==(6,tailrecBranch$) in -- #78 -//│ if scrut -- #77 -//│ true => -//│ let x$1 = A(0,1) in -- #76 -//│ let ctx2 = _Context(x$1,x$1,0) in -- #75 -//│ let* (composed) = _b_a_ctx_comp$4(a_modcons$6_ctx,ctx2) in -- #74 -//│ jump _b_modcons$5_a_modcons$6_opt_jp$8(5,composed,a_modcons$6_ctx) -- #73 -//│ false => -//│ let* (x$2) = @tailcall a() in -- #72 -//│ let* (x$3) = c() in -- #71 -//│ let x$4 = A(x$2,x$3) in -- #70 -//│ let* (res) = _b_a_ctx_app$3(b_modcons$5_ctx,x$4) in -- #69 -//│ res -- #68 -//│ ) -//│ }, -//│ let* (x$6) = a() in -- #33 -//│ x$6 -- #32) +//│ Program: +//│ class A(a,b) +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def a() = +//│ let idCtx = _IdContext() in -- #64 +//│ let* (res) = a_modcons$12(idCtx) in -- #63 +//│ res -- #62 +//│ def b() = +//│ let idCtx = _IdContext() in -- #56 +//│ let* (res) = b_modcons$11(idCtx) in -- #55 +//│ res -- #54 +//│ def c() = +//│ let x$6 = A(0,1) in -- #29 +//│ x$6 -- #28 +//│ def _b_a_ctx_app$9(ctx,x) = +//│ case ctx of -- #42 +//│ _IdContext => +//│ x -- #41 +//│ _Context => +//│ let field = _Context.field(ctx) in -- #40 +//│ let ptr = _Context.ptr(ctx) in -- #39 +//│ let _ = assign ptr.a := x in -- #38 +//│ let acc = _Context.acc(ctx) in -- #37 +//│ acc -- #36 +//│ def _b_a_ctx_comp$10(ctx1,ctx2) = +//│ let ctx2acc = _Context.acc(ctx2) in -- #48 +//│ let ctx2ptr = _Context.ptr(ctx2) in -- #47 +//│ let ctx2field = _Context.field(ctx2) in -- #46 +//│ let* (newAcc) = _b_a_ctx_app$9(ctx1,ctx2acc) in -- #45 +//│ let ret = _Context(newAcc,ctx2ptr,ctx2field) in -- #44 +//│ ret -- #43 +//│ def b_modcons$11(ctx) = +//│ let* (r0) = _b_modcons$11_a_modcons$12_opt$13(11,ctx,true) in -- #83 +//│ r0 -- #82 +//│ def a_modcons$12(ctx) = +//│ let* (r0) = _b_modcons$11_a_modcons$12_opt$13(12,true,ctx) in -- #85 +//│ r0 -- #84 +//│ def _b_modcons$11_a_modcons$12_opt$13(tailrecBranch$,b_modcons$11_ctx,a_modcons$12_ctx) = +//│ jump _b_modcons$11_a_modcons$12_opt_jp$14(tailrecBranch$,b_modcons$11_ctx,a_modcons$12_ctx) -- #81 +//│ def _b_modcons$11_a_modcons$12_opt_jp$14(tailrecBranch$,b_modcons$11_ctx,a_modcons$12_ctx) = +//│ let scrut = ==(12,tailrecBranch$) in -- #80 +//│ if scrut -- #79 +//│ true => +//│ let x$2 = A(0,1) in -- #78 +//│ let ctx2 = _Context(x$2,x$2,0) in -- #77 +//│ let* (composed) = _b_a_ctx_comp$10(a_modcons$12_ctx,ctx2) in -- #76 +//│ jump _b_modcons$11_a_modcons$12_opt_jp$14(11,composed,a_modcons$12_ctx) -- #75 +//│ false => +//│ let* (x$3) = @tailcall a() in -- #74 +//│ let* (x$4) = c() in -- #73 +//│ let x$5 = A(x$3,x$4) in -- #72 +//│ let* (res) = _b_a_ctx_app$9(b_modcons$11_ctx,x$5) in -- #71 +//│ res -- #70 +//│ let* (x$0) = a() in -- #2 +//│ x$0 -- #1 :ce @tailcall 1 //│ |@|tailcall| |1| //│ Parsed: {@tailcall 1} //│ ╔══[COMPILATION ERROR] @tailcall may only be used to annotate function calls -//│ ║ l.2513: @tailcall 1 +//│ ║ l.1486: @tailcall 1 //│ ╙── ^^^^^^^^ //│ +//│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, [])}, { +//│ Program: //│ -//│ }, -//│ 1 -- #0) //│ -//│ Strongly Connected Tail Calls: -//│ List() -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { +//│ 1 -- #0 //│ -//│ }, -//│ 1 -- #0) //│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { +//│ Strongly Connected Tail Calls: +//│ List() +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) //│ -//│ }, -//│ 1 -- #0) +//│ 1 -- #0 :ce @tailrec 1 //│ |@|tailrec| |1| //│ Parsed: {@tailrec 1} //│ ╔══[COMPILATION ERROR] @tailrec may only be used to annotate functions -//│ ║ l.2540: @tailrec 1 +//│ ║ l.1510: @tailrec 1 //│ ╙── ^^^^^^^ //│ +//│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, [])}, { +//│ Program: //│ -//│ }, -//│ 1 -- #0) //│ -//│ Strongly Connected Tail Calls: -//│ List() -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { +//│ 1 -- #0 //│ -//│ }, -//│ 1 -- #0) //│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { +//│ Strongly Connected Tail Calls: +//│ List() +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) //│ -//│ }, -//│ 1 -- #0) +//│ 1 -- #0 :ce fun foo() = @@ -2570,50 +1537,32 @@ foo() //│ |#fun| |foo|(||)| |#=|→|@|tailrec| |foo|(||)|←|↵|foo|(||)| //│ Parsed: {fun foo = () => {@tailrec foo()}; foo()} //│ ╔══[COMPILATION ERROR] @tailrec is for annotating functions; try @tailcall instead -//│ ║ l.2568: @tailrec foo() +//│ ║ l.1535: @tailrec foo() //│ ╙── ^^^^^^^ //│ +//│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, [])}, { -//│ Def(0, foo, [], -//│ 1, -//│ let* (x$0) = foo() in -- #3 -//│ x$0 -- #2 -//│ ) -//│ }, -//│ let* (x$1) = foo() in -- #7 -//│ x$1 -- #6) +//│ Program: +//│ +//│ def foo() = +//│ let* (x$1) = foo() in -- #5 +//│ x$1 -- #4 +//│ let* (x$0) = foo() in -- #2 +//│ x$0 -- #1 +//│ //│ //│ Strongly Connected Tail Calls: //│ List(Set(foo)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(1, foo_jp, [], -//│ 1, -//│ jump foo_jp() -- #8 -//│ ) -//│ Def(2, foo, [], -//│ 1, -//│ let* (r0) = foo_jp() in -- #10 -//│ r0 -- #9 -//│ ) -//│ }, -//│ let* (x$1) = foo() in -- #7 -//│ x$1 -- #6) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(1, foo_jp, [], -//│ 1, -//│ jump foo_jp() -- #8 -//│ ) -//│ Def(2, foo, [], -//│ 1, -//│ let* (r0) = foo_jp() in -- #10 -//│ r0 -- #9 -//│ ) -//│ }, -//│ let* (x$1) = foo() in -- #7 -//│ x$1 -- #6) +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def foo_jp() = +//│ jump foo_jp() -- #12 +//│ def foo() = +//│ let* (r0) = foo_jp() in -- #14 +//│ r0 -- #13 +//│ let* (x$0) = foo() in -- #2 +//│ x$0 -- #1 :ce @tailcall @@ -2623,47 +1572,29 @@ foo() //│ |@|tailcall|↵|#fun| |foo|(||)| |#=|→|foo|(||)|←|↵|foo|(||)| //│ Parsed: {fun foo = () => {foo()}; foo()} //│ ╔══[COMPILATION ERROR] @tailcall is for annotating function calls; try @tailrec instead -//│ ║ l.2619: @tailcall +//│ ║ l.1568: @tailcall //│ ╙── ^^^^^^^^ //│ +//│ //│ IR: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, [])}, { -//│ Def(0, foo, [], -//│ 1, -//│ let* (x$0) = foo() in -- #3 -//│ x$0 -- #2 -//│ ) -//│ }, -//│ let* (x$1) = foo() in -- #7 -//│ x$1 -- #6) +//│ Program: +//│ +//│ def foo() = +//│ let* (x$1) = foo() in -- #5 +//│ x$1 -- #4 +//│ let* (x$0) = foo() in -- #2 +//│ x$0 -- #1 +//│ //│ //│ Strongly Connected Tail Calls: //│ List(Set(foo)) -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(1, foo_jp, [], -//│ 1, -//│ jump foo_jp() -- #8 -//│ ) -//│ Def(2, foo, [], -//│ 1, -//│ let* (r0) = foo_jp() in -- #10 -//│ r0 -- #9 -//│ ) -//│ }, -//│ let* (x$1) = foo() in -- #7 -//│ x$1 -- #6) -//│ -//│ Promoted: -//│ Program({ClassInfo(0, True, []),ClassInfo(1, False, []),ClassInfo(2, _IdContext, []),ClassInfo(3, _Context, [acc,ptr,field])}, { -//│ Def(1, foo_jp, [], -//│ 1, -//│ jump foo_jp() -- #8 -//│ ) -//│ Def(2, foo, [], -//│ 1, -//│ let* (r0) = foo_jp() in -- #10 -//│ r0 -- #9 -//│ ) -//│ }, -//│ let* (x$1) = foo() in -- #7 -//│ x$1 -- #6) +//│ Program: +//│ class _IdContext() +//│ class _Context(acc,ptr,field) +//│ def foo_jp() = +//│ jump foo_jp() -- #12 +//│ def foo() = +//│ let* (r0) = foo_jp() in -- #14 +//│ r0 -- #13 +//│ let* (x$0) = foo() in -- #2 +//│ x$0 -- #1 diff --git a/compiler/shared/test/diff-ir/LiftClass.mls b/compiler/shared/test/diff-ir/LiftClass.mls new file mode 100644 index 0000000000..05b2267a9b --- /dev/null +++ b/compiler/shared/test/diff-ir/LiftClass.mls @@ -0,0 +1,158 @@ +:NewDefs +:ParseOnly +:UseIR +:NoTailRec + +:prelude +module True +module False +module Callable { + fun apply0() = 0 + fun apply1(x0) = 0 + fun apply2(x0,x1) = 0 + fun apply3(x0,x1,x2) = 0 + fun apply4(x0,x1,x2,x3) = 0 + fun apply5(x0,x1,x2,x3,x4) = 0 +} +module List[A, B] +class Cons[A, B](h: A, t: Cons[A, B]) extends List[A, B] +module Nil[A, B] extends List[A, B] +module Option[A] +class Some[A](x: A) extends Option[A] +module None[A] extends Option[A] +class Pair[A, B](x: A, y: B) +class Tuple2[A, B](x: A, y: B) +class Tuple3[A, B, C](x: A, y: B, z: C) +module Nat +class S(s: Nat) extends Nat +module O extends Nat +class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O) +//│ |#module| |True|↵|#module| |False|↵|#module| |Callable| |{|→|#fun| |apply0|(||)| |#=| |0|↵|#fun| |apply1|(|x0|)| |#=| |0|↵|#fun| |apply2|(|x0|,|x1|)| |#=| |0|↵|#fun| |apply3|(|x0|,|x1|,|x2|)| |#=| |0|↵|#fun| |apply4|(|x0|,|x1|,|x2|,|x3|)| |#=| |0|↵|#fun| |apply5|(|x0|,|x1|,|x2|,|x3|,|x4|)| |#=| |0|←|↵|}|↵|#module| |List|[|A|,| |B|]|↵|#class| |Cons|[|A|,| |B|]|(|h|#:| |A|,| |t|#:| |Cons|[|A|,| |B|]|)| |#extends| |List|[|A|,| |B|]|↵|#module| |Nil|[|A|,| |B|]| |#extends| |List|[|A|,| |B|]|↵|#module| |Option|[|A|]|↵|#class| |Some|[|A|]|(|x|#:| |A|)| |#extends| |Option|[|A|]|↵|#module| |None|[|A|]| |#extends| |Option|[|A|]|↵|#class| |Pair|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple2|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple3|[|A|,| |B|,| |C|]|(|x|#:| |A|,| |y|#:| |B|,| |z|#:| |C|)|↵|#module| |Nat|↵|#class| |S|(|s|#:| |Nat|)| |#extends| |Nat|↵|#module| |O| |#extends| |Nat|↵|#class| |HiddenTheseEntities|(|_0|#:| |HiddenTheseEntities|,| |_1|#:| |True|,| |_2|#:| |False|,| |_3|#:| |Callable|,| |_4|#:| |List|,| |_5|#:| |Cons|,| |_6|#:| |Nil|,| |_7|#:| |Option|,| |_8|#:| |Some|,| |_9|#:| |None|,| |_10|#:| |Pair|,| |_11|#:| |Tuple2|,| |_12|#:| |Tuple3|,| |_13|#:| |Nat|,| |_14|#:| |S|,| |_15|#:| |O|)| +//│ Parsed: {module True {}; module False {}; module Callable {fun apply0 = () => 0; fun apply1 = (x0,) => 0; fun apply2 = (x0, x1,) => 0; fun apply3 = (x0, x1, x2,) => 0; fun apply4 = (x0, x1, x2, x3,) => 0; fun apply5 = (x0, x1, x2, x3, x4,) => 0}; module List‹A, B› {}; class Cons‹A, B›(h: A, t: Cons‹A, B›,): List‹A, B› {}; module Nil‹A, B›: List‹A, B› {}; module Option‹A› {}; class Some‹A›(x: A,): Option‹A› {}; module None‹A›: Option‹A› {}; class Pair‹A, B›(x: A, y: B,) {}; class Tuple2‹A, B›(x: A, y: B,) {}; class Tuple3‹A, B, C›(x: A, y: B, z: C,) {}; module Nat {}; class S(s: Nat,): Nat {}; module O: Nat {}; class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O,) {}} +//│ +//│ Preluded. +//│ + +:genCpp +:runCpp +:interpIR +fun main(x) = + class InnerClass(y) extends Callable { + fun apply1(z) = x + y + z + } + let ic = InnerClass(1) + ic(2) + ic(3) +main(4) +//│ |#fun| |main|(|x|)| |#=|→|#class| |InnerClass|(|y|)| |#extends| |Callable| |{|→|#fun| |apply1|(|z|)| |#=| |x| |+| |y| |+| |z|←|↵|}|↵|#let| |ic| |#=| |InnerClass|(|1|)|↵|ic|(|2|)| |+| |ic|(|3|)|←|↵|main|(|4|)| +//│ Parsed: {fun main = (x,) => {class InnerClass(y,): Callable {fun apply1 = (z,) => +(+(x, y,), z,)}; let ic = InnerClass(1,); +(ic(2,), ic(3,),)}; main(4,)} +//│ +//│ +//│ IR: +//│ Program: +//│ class InnerClass(y,x) extends Callable { +//│ def apply1(z$0) = +//│ let x$6 = +(x,y) in -- #45 +//│ let x$7 = +(x$6,z$0) in -- #44 +//│ x$7 -- #43 +//│ } +//│ def main(x$1) = +//│ let x$2 = InnerClass(1,x$1) in -- #26 +//│ let x$3 = Callable.apply1(x$2,2) in -- #25 +//│ let x$4 = Callable.apply1(x$2,3) in -- #24 +//│ let x$5 = +(x$3,x$4) in -- #23 +//│ x$5 -- #22 +//│ let* (x$0) = main(4) in -- #4 +//│ x$0 -- #3 +//│ +//│ Interpreted: +//│ 15 +//│ +//│ +//│ Execution succeeded: +//│ 15 +//│ + +:genCpp +:runCpp +:interpIR +fun main(x) = + class InnerClass(y) extends Callable { + fun apply1(z) = + module InnerClass2 extends Callable { + fun apply1(w) = w + z + } + InnerClass2 + } + let ic = InnerClass(1) + ic(2)(2) + ic(3)(1) +main(4) +//│ |#fun| |main|(|x|)| |#=|→|#class| |InnerClass|(|y|)| |#extends| |Callable| |{|→|#fun| |apply1|(|z|)| |#=|→|#module| |InnerClass2| |#extends| |Callable| |{|→|#fun| |apply1|(|w|)| |#=| |w| |+| |z|←|↵|}|↵|InnerClass2|←|←|↵|}|↵|#let| |ic| |#=| |InnerClass|(|1|)|↵|ic|(|2|)|(|2|)| |+| |ic|(|3|)|(|1|)|←|↵|main|(|4|)| +//│ Parsed: {fun main = (x,) => {class InnerClass(y,): Callable {fun apply1 = (z,) => {module InnerClass2: Callable {fun apply1 = (w,) => +(w, z,)}; InnerClass2}}; let ic = InnerClass(1,); +(ic(2,)(2,), ic(3,)(1,),)}; main(4,)} +//│ +//│ +//│ IR: +//│ Program: +//│ class InnerClass(y) extends Callable { +//│ def apply1(z$0) = +//│ let x$8 = InnerClass2(z$0) in -- #44 +//│ x$8 -- #43 +//│ } +//│ class InnerClass2(z) extends Callable { +//│ def apply1(w$0) = +//│ let x$9 = +(w$0,z) in -- #51 +//│ x$9 -- #50 +//│ } +//│ def main(x$1) = +//│ let x$2 = InnerClass(1) in -- #36 +//│ let x$3 = Callable.apply1(x$2,2) in -- #35 +//│ let x$4 = Callable.apply1(x$3,2) in -- #34 +//│ let x$5 = Callable.apply1(x$2,3) in -- #33 +//│ let x$6 = Callable.apply1(x$5,1) in -- #32 +//│ let x$7 = +(x$4,x$6) in -- #31 +//│ x$7 -- #30 +//│ let* (x$0) = main(4) in -- #4 +//│ x$0 -- #3 +//│ +//│ Interpreted: +//│ 8 +//│ +//│ +//│ Execution succeeded: +//│ 8 +//│ + +:genCpp +:runCpp +:interpIR +fun main(x) = + class InnerClass(y) extends Callable { + fun f(x) = y + } + let ic = InnerClass(1) + InnerClass.f(ic, Nil) +main(2) +//│ |#fun| |main|(|x|)| |#=|→|#class| |InnerClass|(|y|)| |#extends| |Callable| |{|→|#fun| |f|(|x|)| |#=| |y|←|↵|}|↵|#let| |ic| |#=| |InnerClass|(|1|)|↵|InnerClass|.f|(|ic|,| |Nil|)|←|↵|main|(|2|)| +//│ Parsed: {fun main = (x,) => {class InnerClass(y,): Callable {fun f = (x,) => y}; let ic = InnerClass(1,); (InnerClass).f(ic, Nil,)}; main(2,)} +//│ +//│ +//│ IR: +//│ Program: +//│ class InnerClass(y) extends Callable { +//│ def f(x$5) = +//│ y -- #24 +//│ } +//│ def main(x$1) = +//│ let x$2 = InnerClass(1) in -- #17 +//│ let x$3 = Nil() in -- #16 +//│ let x$4 = InnerClass.f(x$2,x$3) in -- #15 +//│ x$4 -- #14 +//│ let* (x$0) = main(2) in -- #4 +//│ x$0 -- #3 +//│ +//│ Interpreted: +//│ 1 +//│ +//│ +//│ Execution succeeded: +//│ 1 +//│ diff --git a/compiler/shared/test/diff-ir/LiftFun.mls b/compiler/shared/test/diff-ir/LiftFun.mls new file mode 100644 index 0000000000..1d148b4551 --- /dev/null +++ b/compiler/shared/test/diff-ir/LiftFun.mls @@ -0,0 +1,186 @@ +:NewDefs +:ParseOnly +:UseIR +:NoTailRec + +:prelude +module True +module False +module Callable { + fun apply0() = 0 + fun apply1(x0) = 0 + fun apply2(x0,x1) = 0 + fun apply3(x0,x1,x2) = 0 + fun apply4(x0,x1,x2,x3) = 0 + fun apply5(x0,x1,x2,x3,x4) = 0 +} +module List[A, B] +class Cons[A, B](h: A, t: Cons[A, B]) extends List[A, B] +module Nil[A, B] extends List[A, B] +module Option[A] +class Some[A](x: A) extends Option[A] +module None[A] extends Option[A] +class Pair[A, B](x: A, y: B) +class Tuple2[A, B](x: A, y: B) +class Tuple3[A, B, C](x: A, y: B, z: C) +module Nat +class S(s: Nat) extends Nat +module O extends Nat +class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O) +//│ |#module| |True|↵|#module| |False|↵|#module| |Callable| |{|→|#fun| |apply0|(||)| |#=| |0|↵|#fun| |apply1|(|x0|)| |#=| |0|↵|#fun| |apply2|(|x0|,|x1|)| |#=| |0|↵|#fun| |apply3|(|x0|,|x1|,|x2|)| |#=| |0|↵|#fun| |apply4|(|x0|,|x1|,|x2|,|x3|)| |#=| |0|↵|#fun| |apply5|(|x0|,|x1|,|x2|,|x3|,|x4|)| |#=| |0|←|↵|}|↵|#module| |List|[|A|,| |B|]|↵|#class| |Cons|[|A|,| |B|]|(|h|#:| |A|,| |t|#:| |Cons|[|A|,| |B|]|)| |#extends| |List|[|A|,| |B|]|↵|#module| |Nil|[|A|,| |B|]| |#extends| |List|[|A|,| |B|]|↵|#module| |Option|[|A|]|↵|#class| |Some|[|A|]|(|x|#:| |A|)| |#extends| |Option|[|A|]|↵|#module| |None|[|A|]| |#extends| |Option|[|A|]|↵|#class| |Pair|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple2|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple3|[|A|,| |B|,| |C|]|(|x|#:| |A|,| |y|#:| |B|,| |z|#:| |C|)|↵|#module| |Nat|↵|#class| |S|(|s|#:| |Nat|)| |#extends| |Nat|↵|#module| |O| |#extends| |Nat|↵|#class| |HiddenTheseEntities|(|_0|#:| |HiddenTheseEntities|,| |_1|#:| |True|,| |_2|#:| |False|,| |_3|#:| |Callable|,| |_4|#:| |List|,| |_5|#:| |Cons|,| |_6|#:| |Nil|,| |_7|#:| |Option|,| |_8|#:| |Some|,| |_9|#:| |None|,| |_10|#:| |Pair|,| |_11|#:| |Tuple2|,| |_12|#:| |Tuple3|,| |_13|#:| |Nat|,| |_14|#:| |S|,| |_15|#:| |O|)| +//│ Parsed: {module True {}; module False {}; module Callable {fun apply0 = () => 0; fun apply1 = (x0,) => 0; fun apply2 = (x0, x1,) => 0; fun apply3 = (x0, x1, x2,) => 0; fun apply4 = (x0, x1, x2, x3,) => 0; fun apply5 = (x0, x1, x2, x3, x4,) => 0}; module List‹A, B› {}; class Cons‹A, B›(h: A, t: Cons‹A, B›,): List‹A, B› {}; module Nil‹A, B›: List‹A, B› {}; module Option‹A› {}; class Some‹A›(x: A,): Option‹A› {}; module None‹A›: Option‹A› {}; class Pair‹A, B›(x: A, y: B,) {}; class Tuple2‹A, B›(x: A, y: B,) {}; class Tuple3‹A, B, C›(x: A, y: B, z: C,) {}; module Nat {}; class S(s: Nat,): Nat {}; module O: Nat {}; class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O,) {}} +//│ +//│ Preluded. +//│ + +:genCpp +:runCpp +:interpIR +fun main(init, key) = + fun r(x) = if x <= 0 then key else r(x - 1) + r(init) +main(1, 42) +//│ |#fun| |main|(|init|,| |key|)| |#=|→|#fun| |r|(|x|)| |#=| |#if| |x| |<=| |0| |#then| |key| |#else| |r|(|x| |-| |1|)|↵|r|(|init|)|←|↵|main|(|1|,| |42|)| +//│ Parsed: {fun main = (init, key,) => {fun r = (x,) => if (<=(x, 0,)) then key else r(-(x, 1,),); r(init,)}; main(1, 42,)} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def main(init$0,key$0) = +//│ let* (x$1) = r(init$0,key$0) in -- #11 +//│ x$1 -- #10 +//│ def r(x$2,key$1) = +//│ let x$3 = <=(x$2,0) in -- #40 +//│ if x$3 -- #39 +//│ true => +//│ jump j$0(key$1) -- #26 +//│ false => +//│ let x$5 = -(x$2,1) in -- #38 +//│ let* (x$6) = r(x$5,key$1) in -- #37 +//│ jump j$0(x$6) -- #36 +//│ def j$0(x$4) = +//│ x$4 -- #24 +//│ let* (x$0) = main(1,42) in -- #6 +//│ x$0 -- #5 +//│ +//│ Interpreted: +//│ 42 +//│ +//│ +//│ Execution succeeded: +//│ 42 +//│ + +:genCpp +:runCpp +:interpIR +fun main(init, key) = + fun ping(x) = if x <= 0 then key + 1 else pong(x - 1) + fun pong(x) = if x <= 0 then key + 2 else ping(x - 1) + ping(init) +main(1, 42) +//│ |#fun| |main|(|init|,| |key|)| |#=|→|#fun| |ping|(|x|)| |#=| |#if| |x| |<=| |0| |#then| |key| |+| |1| |#else| |pong|(|x| |-| |1|)|↵|#fun| |pong|(|x|)| |#=| |#if| |x| |<=| |0| |#then| |key| |+| |2| |#else| |ping|(|x| |-| |1|)|↵|ping|(|init|)|←|↵|main|(|1|,| |42|)| +//│ Parsed: {fun main = (init, key,) => {fun ping = (x,) => if (<=(x, 0,)) then +(key, 1,) else pong(-(x, 1,),); fun pong = (x,) => if (<=(x, 0,)) then +(key, 2,) else ping(-(x, 1,),); ping(init,)}; main(1, 42,)} +//│ +//│ +//│ IR: +//│ Program: +//│ +//│ def main(init$0,key$0) = +//│ let* (x$1) = ping(init$0,key$0) in -- #11 +//│ x$1 -- #10 +//│ def ping(x$2,key$1) = +//│ let x$3 = <=(x$2,0) in -- #46 +//│ if x$3 -- #45 +//│ true => +//│ let x$5 = +(key$1,1) in -- #32 +//│ jump j$0(x$5) -- #31 +//│ false => +//│ let x$6 = -(x$2,1) in -- #44 +//│ let* (x$7) = pong(x$6,key$1) in -- #43 +//│ jump j$0(x$7) -- #42 +//│ def j$0(x$4) = +//│ x$4 -- #24 +//│ def pong(x$8,key$2) = +//│ let x$9 = <=(x$8,0) in -- #75 +//│ if x$9 -- #74 +//│ true => +//│ let x$11 = +(key$2,2) in -- #61 +//│ jump j$1(x$11) -- #60 +//│ false => +//│ let x$12 = -(x$8,1) in -- #73 +//│ let* (x$13) = ping(x$12,key$2) in -- #72 +//│ jump j$1(x$13) -- #71 +//│ def j$1(x$10) = +//│ x$10 -- #53 +//│ let* (x$0) = main(1,42) in -- #6 +//│ x$0 -- #5 +//│ +//│ Interpreted: +//│ 44 +//│ +//│ +//│ Execution succeeded: +//│ 44 +//│ + +:genCpp +:runCpp +:interpIR +fun main(init, key) = + let ping = + fun ping(x) = if x <= 0 then key + 1 else pong(x - 1) + fun pong(x) = if x <= 0 then key + 2 else ping(x - 1) + ping + ping(init) +main(1, 42) +//│ |#fun| |main|(|init|,| |key|)| |#=|→|#let| |ping| |#=|→|#fun| |ping|(|x|)| |#=| |#if| |x| |<=| |0| |#then| |key| |+| |1| |#else| |pong|(|x| |-| |1|)|↵|#fun| |pong|(|x|)| |#=| |#if| |x| |<=| |0| |#then| |key| |+| |2| |#else| |ping|(|x| |-| |1|)|↵|ping|←|↵|ping|(|init|)|←|↵|main|(|1|,| |42|)| +//│ Parsed: {fun main = (init, key,) => {let ping = {fun ping = (x,) => if (<=(x, 0,)) then +(key, 1,) else pong(-(x, 1,),); fun pong = (x,) => if (<=(x, 0,)) then +(key, 2,) else ping(-(x, 1,),); ping}; ping(init,)}; main(1, 42,)} +//│ +//│ +//│ IR: +//│ Program: +//│ class Lambda$0(key) extends Callable { +//│ def apply1(x$17) = +//│ let* (x$18) = ping(x$17,key) in -- #85 +//│ x$18 -- #84 +//│ } +//│ def main(init$0,key$0) = +//│ let x$3 = Lambda$0(key$0) in -- #14 +//│ let x$4 = Callable.apply1(x$3,init$0) in -- #13 +//│ x$4 -- #12 +//│ def ping(x$5,key$1) = +//│ let x$6 = <=(x$5,0) in -- #49 +//│ if x$6 -- #48 +//│ true => +//│ let x$8 = +(key$1,1) in -- #35 +//│ jump j$0(x$8) -- #34 +//│ false => +//│ let x$9 = -(x$5,1) in -- #47 +//│ let* (x$10) = pong(x$9,key$1) in -- #46 +//│ jump j$0(x$10) -- #45 +//│ def j$0(x$7) = +//│ x$7 -- #27 +//│ def pong(x$11,key$2) = +//│ let x$12 = <=(x$11,0) in -- #78 +//│ if x$12 -- #77 +//│ true => +//│ let x$14 = +(key$2,2) in -- #64 +//│ jump j$1(x$14) -- #63 +//│ false => +//│ let x$15 = -(x$11,1) in -- #76 +//│ let* (x$16) = ping(x$15,key$2) in -- #75 +//│ jump j$1(x$16) -- #74 +//│ def j$1(x$13) = +//│ x$13 -- #56 +//│ let* (x$0) = main(1,42) in -- #6 +//│ x$0 -- #5 +//│ +//│ Interpreted: +//│ 44 +//│ +//│ +//│ Execution succeeded: +//│ 44 +//│ diff --git a/compiler/shared/test/diff-ir/LiftLambda.mls b/compiler/shared/test/diff-ir/LiftLambda.mls new file mode 100644 index 0000000000..9f397b3118 --- /dev/null +++ b/compiler/shared/test/diff-ir/LiftLambda.mls @@ -0,0 +1,87 @@ +:NewDefs +:ParseOnly +:UseIR +:NoTailRec + +:prelude +module True +module False +module Callable { + fun apply0() = 0 + fun apply1(x0) = 0 + fun apply2(x0,x1) = 0 + fun apply3(x0,x1,x2) = 0 + fun apply4(x0,x1,x2,x3) = 0 + fun apply5(x0,x1,x2,x3,x4) = 0 +} +module List[A, B] +class Cons[A, B](h: A, t: Cons[A, B]) extends List[A, B] +module Nil[A, B] extends List[A, B] +module Option[A] +class Some[A](x: A) extends Option[A] +module None[A] extends Option[A] +class Pair[A, B](x: A, y: B) +class Tuple2[A, B](x: A, y: B) +class Tuple3[A, B, C](x: A, y: B, z: C) +module Nat +class S(s: Nat) extends Nat +module O extends Nat +class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O) +//│ |#module| |True|↵|#module| |False|↵|#module| |Callable| |{|→|#fun| |apply0|(||)| |#=| |0|↵|#fun| |apply1|(|x0|)| |#=| |0|↵|#fun| |apply2|(|x0|,|x1|)| |#=| |0|↵|#fun| |apply3|(|x0|,|x1|,|x2|)| |#=| |0|↵|#fun| |apply4|(|x0|,|x1|,|x2|,|x3|)| |#=| |0|↵|#fun| |apply5|(|x0|,|x1|,|x2|,|x3|,|x4|)| |#=| |0|←|↵|}|↵|#module| |List|[|A|,| |B|]|↵|#class| |Cons|[|A|,| |B|]|(|h|#:| |A|,| |t|#:| |Cons|[|A|,| |B|]|)| |#extends| |List|[|A|,| |B|]|↵|#module| |Nil|[|A|,| |B|]| |#extends| |List|[|A|,| |B|]|↵|#module| |Option|[|A|]|↵|#class| |Some|[|A|]|(|x|#:| |A|)| |#extends| |Option|[|A|]|↵|#module| |None|[|A|]| |#extends| |Option|[|A|]|↵|#class| |Pair|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple2|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple3|[|A|,| |B|,| |C|]|(|x|#:| |A|,| |y|#:| |B|,| |z|#:| |C|)|↵|#module| |Nat|↵|#class| |S|(|s|#:| |Nat|)| |#extends| |Nat|↵|#module| |O| |#extends| |Nat|↵|#class| |HiddenTheseEntities|(|_0|#:| |HiddenTheseEntities|,| |_1|#:| |True|,| |_2|#:| |False|,| |_3|#:| |Callable|,| |_4|#:| |List|,| |_5|#:| |Cons|,| |_6|#:| |Nil|,| |_7|#:| |Option|,| |_8|#:| |Some|,| |_9|#:| |None|,| |_10|#:| |Pair|,| |_11|#:| |Tuple2|,| |_12|#:| |Tuple3|,| |_13|#:| |Nat|,| |_14|#:| |S|,| |_15|#:| |O|)| +//│ Parsed: {module True {}; module False {}; module Callable {fun apply0 = () => 0; fun apply1 = (x0,) => 0; fun apply2 = (x0, x1,) => 0; fun apply3 = (x0, x1, x2,) => 0; fun apply4 = (x0, x1, x2, x3,) => 0; fun apply5 = (x0, x1, x2, x3, x4,) => 0}; module List‹A, B› {}; class Cons‹A, B›(h: A, t: Cons‹A, B›,): List‹A, B› {}; module Nil‹A, B›: List‹A, B› {}; module Option‹A› {}; class Some‹A›(x: A,): Option‹A› {}; module None‹A›: Option‹A› {}; class Pair‹A, B›(x: A, y: B,) {}; class Tuple2‹A, B›(x: A, y: B,) {}; class Tuple3‹A, B, C›(x: A, y: B, z: C,) {}; module Nat {}; class S(s: Nat,): Nat {}; module O: Nat {}; class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O,) {}} +//│ +//│ Preluded. +//│ + +:genCpp +:runCpp +:interpIR +fun compose(f)(g)(x) = f(g(x)) +fun main(x) = + let y = 1 + let lam = z => x + y + z + compose(lam)(lam)(2) +main(3) +//│ |#fun| |compose|(|f|)|(|g|)|(|x|)| |#=| |f|(|g|(|x|)|)|↵|#fun| |main|(|x|)| |#=|→|#let| |y| |#=| |1|↵|#let| |lam| |#=| |z| |#=>| |x| |+| |y| |+| |z|↵|compose|(|lam|)|(|lam|)|(|2|)|←|↵|main|(|3|)| +//│ Parsed: {fun compose = (f,) => (g,) => (x,) => f(g(x,),); fun main = (x,) => {let y = 1; let lam = (z,) => +(+(x, y,), z,); compose(lam,)(lam,)(2,)}; main(3,)} +//│ +//│ +//│ IR: +//│ Program: +//│ class Lambda$0(f) extends Callable { +//│ def apply1(g$0) = +//│ let x$11 = Lambda$2(f,g$0) in -- #33 +//│ x$11 -- #32 +//│ } +//│ class Lambda$1(x,y) extends Callable { +//│ def apply1(z$0) = +//│ let x$12 = +(x,y) in -- #46 +//│ let x$13 = +(x$12,z$0) in -- #45 +//│ x$13 -- #44 +//│ } +//│ class Lambda$2(f,g) extends Callable { +//│ def apply1(x$14) = +//│ let x$15 = Callable.apply1(g,x$14) in -- #57 +//│ let x$16 = Callable.apply1(f,x$15) in -- #56 +//│ x$16 -- #55 +//│ } +//│ def compose(f$0) = +//│ let x$2 = Lambda$0(f$0) in -- #6 +//│ x$2 -- #5 +//│ def main(x$3) = +//│ let x$4 = 1 in -- #25 +//│ let x$6 = Lambda$1(x$3,x$4) in -- #24 +//│ let* (x$7) = compose(x$6) in -- #23 +//│ let x$8 = Callable.apply1(x$7,x$6) in -- #22 +//│ let x$9 = Callable.apply1(x$8,2) in -- #21 +//│ x$9 -- #20 +//│ let* (x$0) = main(3) in -- #4 +//│ x$0 -- #3 +//│ +//│ Interpreted: +//│ 10 +//│ +//│ +//│ Execution succeeded: +//│ 10 +//│ diff --git a/compiler/shared/test/diff-ir/Override.mls b/compiler/shared/test/diff-ir/Override.mls new file mode 100644 index 0000000000..7658c8a51f --- /dev/null +++ b/compiler/shared/test/diff-ir/Override.mls @@ -0,0 +1,48 @@ +:NewDefs +:ParseOnly +:UseIR +:NoTailRec + +:genCpp +:runCpp +:interpIR +module Base { + fun f() = 1 +} +module Child extends Base { + fun f() = 2 +} +fun main() = + let c = Child() + Base.f(c) + Child.f(c) +main() +//│ |#module| |Base| |{|→|#fun| |f|(||)| |#=| |1|←|↵|}|↵|#module| |Child| |#extends| |Base| |{|→|#fun| |f|(||)| |#=| |2|←|↵|}|↵|#fun| |main|(||)| |#=|→|#let| |c| |#=| |Child|(||)|↵|Base|.f|(|c|)|↵|Child|.f|(|c|)|←|↵|main|(||)| +//│ Parsed: {module Base {fun f = () => 1}; module Child: Base {fun f = () => 2}; fun main = () => {let c = Child(); (Base).f(c,); (Child).f(c,)}; main()} +//│ +//│ +//│ IR: +//│ Program: +//│ class Base() { +//│ def f() = +//│ 1 -- #16 +//│ } +//│ class Child() extends Base { +//│ def f() = +//│ 2 -- #17 +//│ } +//│ def main() = +//│ let x$1 = Child() in -- #15 +//│ let x$2 = Base.f(x$1) in -- #14 +//│ let x$3 = Child.f(x$1) in -- #13 +//│ x$3 -- #12 +//│ let* (x$0) = main() in -- #2 +//│ x$0 -- #1 +//│ +//│ Interpreted: +//│ 2 +//│ +//│ +//│ Execution succeeded: +//│ 2 +//│ diff --git a/compiler/shared/test/diff-ir/cpp/Makefile b/compiler/shared/test/diff-ir/cpp/Makefile new file mode 100644 index 0000000000..082a04fbea --- /dev/null +++ b/compiler/shared/test/diff-ir/cpp/Makefile @@ -0,0 +1,26 @@ +CXX := g++ +CFLAGS := $(CFLAGS) -O3 -Wall -Wextra -std=c++20 -I. -Wno-inconsistent-missing-override +LDFLAGS := $(LDFLAGS) -lmimalloc -lgmp +SRC := +INCLUDES = mlsprelude.h +DST := +DEFAULT_TARGET := mls +TARGET := $(or $(DST),$(DEFAULT_TARGET)) + +.PHONY: pre all run clean auto + +all: $(TARGET) + +run: $(TARGET) + ./$(TARGET) + +pre: $(SRC) + sed -i '' 's#^//│ ##g' $(SRC) + +clean: + rm -r $(TARGET) $(TARGET).dSYM + +auto: $(TARGET) + +$(TARGET): $(SRC) $(INCLUDES) + $(CXX) $(CFLAGS) $(LDFLAGS) $(SRC) -o $(TARGET) diff --git a/compiler/shared/test/diff-ir/cpp/mlsprelude.h b/compiler/shared/test/diff-ir/cpp/mlsprelude.h new file mode 100644 index 0000000000..8415951c93 --- /dev/null +++ b/compiler/shared/test/diff-ir/cpp/mlsprelude.h @@ -0,0 +1,568 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +constexpr std::size_t _mlsAlignment = 8; + +template class tuple_type { + template > struct impl; + template struct impl> { + template using wrap = T; + using type = std::tuple...>; + }; + +public: + using type = typename impl<>::type; +}; +template struct counter { + using tag = counter; + + struct generator { + friend consteval auto is_defined(tag) { return true; } + }; + friend consteval auto is_defined(tag); + + template + static consteval auto exists(auto) { + return true; + } + + static consteval auto exists(...) { return generator(), false; } +}; + +template +consteval auto nextTypeTag() { + if constexpr (not counter::exists(Id)) + return Id; + else + return nextTypeTag(); +} + +struct _mlsObject { + uint32_t refCount; + uint32_t tag; + constexpr static inline uint32_t stickyRefCount = + std::numeric_limits::max(); + + void incRef() { + if (refCount != stickyRefCount) + ++refCount; + } + bool decRef() { + if (refCount != stickyRefCount && --refCount == 0) + return true; + return false; + } + + virtual void print() const = 0; + virtual void destroy() = 0; +}; + +struct _mls_True; +struct _mls_False; + +class _mlsValue { + using uintptr_t = std::uintptr_t; + using uint64_t = std::uint64_t; + + void *value alignas(_mlsAlignment); + + bool isInt63() const { return (reinterpret_cast(value) & 1) == 1; } + + bool isPtr() const { return (reinterpret_cast(value) & 1) == 0; } + + uint64_t asInt63() const { return reinterpret_cast(value) >> 1; } + + uintptr_t asRawInt() const { return reinterpret_cast(value); } + + static _mlsValue fromRawInt(uintptr_t i) { + return _mlsValue(reinterpret_cast(i)); + } + + static _mlsValue fromInt63(uint64_t i) { + return _mlsValue(reinterpret_cast((i << 1) | 1)); + } + + void *asPtr() const { + assert(!isInt63()); + return value; + } + + _mlsObject *asObject() const { + assert(isPtr()); + return static_cast<_mlsObject *>(value); + } + + bool eqInt63(const _mlsValue &other) const { + return asRawInt() == other.asRawInt(); + } + + _mlsValue addInt63(const _mlsValue &other) const { + return fromRawInt(asRawInt() + other.asRawInt() - 1); + } + + _mlsValue subInt63(const _mlsValue &other) const { + return fromRawInt(asRawInt() - other.asRawInt() + 1); + } + + _mlsValue mulInt63(const _mlsValue &other) const { + return fromInt63(asInt63() * other.asInt63()); + } + + _mlsValue divInt63(const _mlsValue &other) const { + return fromInt63(asInt63() / other.asInt63()); + } + + _mlsValue gtInt63(const _mlsValue &other) const { + return asInt63() > other.asInt63() ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue ltInt63(const _mlsValue &other) const { + return asInt63() < other.asInt63() ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue geInt63(const _mlsValue &other) const { + return asInt63() >= other.asInt63() ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue leInt63(const _mlsValue &other) const { + return asInt63() <= other.asInt63() ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + +public: + explicit _mlsValue() : value(nullptr) {} + explicit _mlsValue(void *value) : value(value) {} + _mlsValue(const _mlsValue &other) : value(other.value) { + if (isPtr()) + asObject()->incRef(); + } + + _mlsValue &operator=(const _mlsValue &other) { + if (value != nullptr && isPtr()) + asObject()->decRef(); + value = other.value; + if (isPtr()) + asObject()->incRef(); + return *this; + } + + ~_mlsValue() { + if (isPtr()) + if (asObject()->decRef()) { + asObject()->destroy(); + value = nullptr; + } + } + + uint64_t asInt() const { + assert(isInt63()); + return asInt63(); + } + + static _mlsValue fromIntLit(uint64_t i) { return fromInt63(i); } + + template static tuple_type<_mlsValue, N> never() { + __builtin_unreachable(); + } + static _mlsValue never() { __builtin_unreachable(); } + + template static _mlsValue create(U... args) { + return _mlsValue(T::create(args...)); + } + + static void destroy(_mlsValue &v) { v.~_mlsValue(); } + + template static bool isValueOf(const _mlsValue &v) { + return v.asObject()->tag == T::typeTag; + } + + static bool isIntLit(const _mlsValue &v, uint64_t n) { + return v.asInt63() == n; + } + + static bool isIntLit(const _mlsValue &v) { return v.isInt63(); } + + template static T *as(const _mlsValue &v) { + return dynamic_cast(v.asObject()); + } + + template static T *cast(_mlsValue &v) { + return static_cast(v.asObject()); + } + + // Operators + + _mlsValue operator==(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return eqInt63(other) ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + assert(false); + } + + _mlsValue operator+(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return addInt63(other); + assert(false); + } + + _mlsValue operator-(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return subInt63(other); + assert(false); + } + + _mlsValue operator*(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return mulInt63(other); + assert(false); + } + + _mlsValue operator/(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return divInt63(other); + assert(false); + } + + _mlsValue operator>(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return gtInt63(other); + assert(false); + } + + _mlsValue operator<(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return ltInt63(other); + assert(false); + } + + _mlsValue operator>=(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return geInt63(other); + assert(false); + } + + _mlsValue operator<=(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return leInt63(other); + assert(false); + } + + // Auxiliary functions + + void print() const { + if (isInt63()) + std::printf("%" PRIu64, asInt63()); + else if (isPtr() && asObject()) + asObject()->print(); + } +}; + +struct _mls_Callable : public _mlsObject { + virtual _mlsValue _mls_apply0() { throw std::runtime_error("Not implemented"); } + virtual _mlsValue _mls_apply1(_mlsValue) { + throw std::runtime_error("Not implemented"); + } + virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue) { + throw std::runtime_error("Not implemented"); + } + virtual _mlsValue _mls_apply3(_mlsValue, _mlsValue, _mlsValue) { + throw std::runtime_error("Not implemented"); + } + virtual _mlsValue _mls_apply4(_mlsValue, _mlsValue, _mlsValue, _mlsValue) { + throw std::runtime_error("Not implemented"); + } + virtual void destroy() override {} +}; + +inline static _mls_Callable *_mlsToCallable(_mlsValue fn) { + auto *ptr = _mlsValue::as<_mls_Callable>(fn); + if (!ptr) + throw std::runtime_error("Not a callable object"); + return ptr; +} + +template +inline static _mlsValue _mlsCall(_mlsValue f, U... args) { + static_assert(sizeof...(U) <= 4, "Too many arguments"); + if constexpr (sizeof...(U) == 0) + return _mlsToCallable(f)->_mls_apply0(); + else if constexpr (sizeof...(U) == 1) + return _mlsToCallable(f)->_mls_apply1(args...); + else if constexpr (sizeof...(U) == 2) + return _mlsToCallable(f)->_mls_apply2(args...); + else if constexpr (sizeof...(U) == 3) + return _mlsToCallable(f)->_mls_apply3(args...); + else if constexpr (sizeof...(U) == 4) + return _mlsToCallable(f)->_mls_apply4(args...); +} + +template +inline static T *_mlsMethodCall(_mlsValue self) { + auto *ptr = _mlsValue::as(self); + if (!ptr) + throw std::runtime_error("unable to convert object for method calls"); + return ptr; +} + +inline int _mlsLargeStack(void *(*fn)(void *)) { + pthread_t thread; + pthread_attr_t attr; + + size_t stacksize = 512 * 1024 * 1024; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, stacksize); + + int rc = pthread_create(&thread, &attr, fn, nullptr); + if (rc) { + printf("ERROR: return code from pthread_create() is %d\n", rc); + return 1; + } + pthread_join(thread, NULL); + return 0; +} + +_mlsValue _mlsMain(); + +inline void *_mlsMainWrapper(void *) { + _mlsValue res = _mlsMain(); + res.print(); + return nullptr; +} + +struct _mls_Unit final : public _mlsObject { + constexpr static inline const char *typeName = "Unit"; + constexpr static inline uint32_t typeTag = nextTypeTag(); + virtual void print() const override { std::printf(typeName); } + static _mlsValue create() { + static _mls_Unit mlsUnit alignas(_mlsAlignment); + mlsUnit.refCount = stickyRefCount; + mlsUnit.tag = typeTag; + return _mlsValue(&mlsUnit); + } + virtual void destroy() override {} +}; + +struct _mls_Boolean : public _mlsObject {}; + +struct _mls_True final : public _mls_Boolean { + constexpr static inline const char *typeName = "True"; + constexpr static inline uint32_t typeTag = nextTypeTag(); + virtual void print() const override { std::printf(typeName); } + static _mlsValue create() { + static _mls_True mlsTrue alignas(_mlsAlignment); + mlsTrue.refCount = stickyRefCount; + mlsTrue.tag = typeTag; + return _mlsValue(&mlsTrue); + } + virtual void destroy() override {} +}; + +struct _mls_False final : public _mls_Boolean { + constexpr static inline const char *typeName = "False"; + constexpr static inline uint32_t typeTag = nextTypeTag(); + virtual void print() const override { std::printf(typeName); } + static _mlsValue create() { + static _mls_False mlsFalse alignas(_mlsAlignment); + mlsFalse.refCount = stickyRefCount; + mlsFalse.tag = typeTag; + return _mlsValue(&mlsFalse); + } + virtual void destroy() override {} +}; + +#include + +struct _mls_ZInt final : public _mlsObject { + boost::multiprecision::mpz_int z; + constexpr static inline const char *typeName = "Z"; + constexpr static inline uint32_t typeTag = nextTypeTag(); + virtual void print() const override { + std::printf(typeName); + std::printf("("); + std::printf("%s", z.str().c_str()); + std::printf(")"); + } + virtual void destroy() override { + z.~number(); + operator delete(this, std::align_val_t(_mlsAlignment)); + } + static _mlsValue create() { + auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_ZInt; + _mlsVal->refCount = 1; + _mlsVal->tag = typeTag; + return _mlsValue(_mlsVal); + } + static _mlsValue create(_mlsValue z) { + auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_ZInt; + _mlsVal->z = z.asInt(); + _mlsVal->refCount = 1; + _mlsVal->tag = typeTag; + return _mlsValue(_mlsVal); + } + _mlsValue operator+(const _mls_ZInt &other) const { + auto _mlsVal = _mlsValue::create<_mls_ZInt>(); + _mlsValue::cast<_mls_ZInt>(_mlsVal)->z = z + other.z; + return _mlsVal; + } + + _mlsValue operator-(const _mls_ZInt &other) const { + auto _mlsVal = _mlsValue::create<_mls_ZInt>(); + _mlsValue::cast<_mls_ZInt>(_mlsVal)->z = z - other.z; + return _mlsVal; + } + + _mlsValue operator*(const _mls_ZInt &other) const { + auto _mlsVal = _mlsValue::create<_mls_ZInt>(); + _mlsValue::cast<_mls_ZInt>(_mlsVal)->z = z * other.z; + return _mlsVal; + } + + _mlsValue operator/(const _mls_ZInt &other) const { + auto _mlsVal = _mlsValue::create<_mls_ZInt>(); + _mlsValue::cast<_mls_ZInt>(_mlsVal)->z = z / other.z; + return _mlsVal; + } + + _mlsValue operator%(const _mls_ZInt &other) const { + auto _mlsVal = _mlsValue::create<_mls_ZInt>(); + _mlsValue::cast<_mls_ZInt>(_mlsVal)->z = z % other.z; + return _mlsVal; + } + + _mlsValue operator==(const _mls_ZInt &other) const { + return z == other.z ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue operator>(const _mls_ZInt &other) const { + return z > other.z ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue operator<(const _mls_ZInt &other) const { + return z < other.z ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue operator>=(const _mls_ZInt &other) const { + return z >= other.z ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue operator<=(const _mls_ZInt &other) const { + return z <= other.z ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue toInt() const { + return _mlsValue::fromIntLit(z.convert_to()); + } + + static _mlsValue fromInt(uint64_t i) { + return _mlsValue::create<_mls_ZInt>(_mlsValue::fromIntLit(i)); + } +}; + +__attribute__((noinline)) inline void _mlsNonExhaustiveMatch() { + throw std::runtime_error("Non-exhaustive match"); +} + +inline _mlsValue _mls_builtin_z_add(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) + *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_sub(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) - *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_mul(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) * *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_div(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) / *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_mod(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) % *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_equal(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) == *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_gt(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) > *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_lt(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) < *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_geq(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) >= *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_leq(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) <= *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_to_int(_mlsValue a) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + return _mlsValue::cast<_mls_ZInt>(a)->toInt(); +} + +inline _mlsValue _mls_builtin_z_of_int(_mlsValue a) { + assert(_mlsValue::isIntLit(a)); + return _mlsValue::create<_mls_ZInt>(a); +} + +inline _mlsValue _mls_builtin_print(_mlsValue a) { + a.print(); + return _mlsValue::create<_mls_Unit>(); +} + +inline _mlsValue _mls_builtin_println(_mlsValue a) { + a.print(); + std::puts(""); + return _mlsValue::create<_mls_Unit>(); +} + +inline _mlsValue _mls_builtin_debug(_mlsValue a) { + a.print(); + std::puts(""); + return a; +} diff --git a/compiler/shared/test/diff-ir/gcd.mls b/compiler/shared/test/diff-ir/gcd.mls new file mode 100644 index 0000000000..1a1c3b6cf5 --- /dev/null +++ b/compiler/shared/test/diff-ir/gcd.mls @@ -0,0 +1,823 @@ +:NewDefs +:ParseOnly +:UseIR +:NoTailRec + +:prelude +module True +module False +module Callable { + fun apply0() = 0 + fun apply1(x0) = 0 + fun apply2(x0,x1) = 0 + fun apply3(x0,x1,x2) = 0 + fun apply4(x0,x1,x2,x3) = 0 + fun apply5(x0,x1,x2,x3,x4) = 0 +} +module List[A, B] +class Cons[A, B](h: A, t: Cons[A, B]) extends List[A, B] +module Nil[A, B] extends List[A, B] +module Option[A] +class Some[A](x: A) extends Option[A] +module None[A] extends Option[A] +class Pair[A, B](x: A, y: B) +class Tuple2[A, B](x: A, y: B) +class Tuple3[A, B, C](x: A, y: B, z: C) +module Nat +class S(s: Nat) extends Nat +module O extends Nat +class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O) +//│ |#module| |True|↵|#module| |False|↵|#module| |Callable| |{|→|#fun| |apply0|(||)| |#=| |0|↵|#fun| |apply1|(|x0|)| |#=| |0|↵|#fun| |apply2|(|x0|,|x1|)| |#=| |0|↵|#fun| |apply3|(|x0|,|x1|,|x2|)| |#=| |0|↵|#fun| |apply4|(|x0|,|x1|,|x2|,|x3|)| |#=| |0|↵|#fun| |apply5|(|x0|,|x1|,|x2|,|x3|,|x4|)| |#=| |0|←|↵|}|↵|#module| |List|[|A|,| |B|]|↵|#class| |Cons|[|A|,| |B|]|(|h|#:| |A|,| |t|#:| |Cons|[|A|,| |B|]|)| |#extends| |List|[|A|,| |B|]|↵|#module| |Nil|[|A|,| |B|]| |#extends| |List|[|A|,| |B|]|↵|#module| |Option|[|A|]|↵|#class| |Some|[|A|]|(|x|#:| |A|)| |#extends| |Option|[|A|]|↵|#module| |None|[|A|]| |#extends| |Option|[|A|]|↵|#class| |Pair|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple2|[|A|,| |B|]|(|x|#:| |A|,| |y|#:| |B|)|↵|#class| |Tuple3|[|A|,| |B|,| |C|]|(|x|#:| |A|,| |y|#:| |B|,| |z|#:| |C|)|↵|#module| |Nat|↵|#class| |S|(|s|#:| |Nat|)| |#extends| |Nat|↵|#module| |O| |#extends| |Nat|↵|#class| |HiddenTheseEntities|(|_0|#:| |HiddenTheseEntities|,| |_1|#:| |True|,| |_2|#:| |False|,| |_3|#:| |Callable|,| |_4|#:| |List|,| |_5|#:| |Cons|,| |_6|#:| |Nil|,| |_7|#:| |Option|,| |_8|#:| |Some|,| |_9|#:| |None|,| |_10|#:| |Pair|,| |_11|#:| |Tuple2|,| |_12|#:| |Tuple3|,| |_13|#:| |Nat|,| |_14|#:| |S|,| |_15|#:| |O|)| +//│ Parsed: {module True {}; module False {}; module Callable {fun apply0 = () => 0; fun apply1 = (x0,) => 0; fun apply2 = (x0, x1,) => 0; fun apply3 = (x0, x1, x2,) => 0; fun apply4 = (x0, x1, x2, x3,) => 0; fun apply5 = (x0, x1, x2, x3, x4,) => 0}; module List‹A, B› {}; class Cons‹A, B›(h: A, t: Cons‹A, B›,): List‹A, B› {}; module Nil‹A, B›: List‹A, B› {}; module Option‹A› {}; class Some‹A›(x: A,): Option‹A› {}; module None‹A›: Option‹A› {}; class Pair‹A, B›(x: A, y: B,) {}; class Tuple2‹A, B›(x: A, y: B,) {}; class Tuple3‹A, B, C›(x: A, y: B, z: C,) {}; module Nat {}; class S(s: Nat,): Nat {}; module O: Nat {}; class HiddenTheseEntities(_0: HiddenTheseEntities, _1: True, _2: False, _3: Callable, _4: List, _5: Cons, _6: Nil, _7: Option, _8: Some, _9: None, _10: Pair, _11: Tuple2, _12: Tuple3, _13: Nat, _14: S, _15: O,) {}} +//│ +//│ Preluded. +//│ + +:genCpp +:runCpp +fun error() = builtin("error") +fun z_of_int(x) = builtin("z_of_int", x) +fun z_to_int(x) = builtin("z_to_int", x) +fun z_add(x, y) = builtin("z_add", x, y) +fun z_sub(x, y) = builtin("z_sub", x, y) +fun z_div(x, y) = builtin("z_div", x, y) +fun z_mul(x, y) = builtin("z_mul", x, y) +fun z_mod(x, y) = builtin("z_mod", x, y) +fun z_lt(x, y) = builtin("z_lt", x, y) +fun z_leq(x, y) = builtin("z_leq", x, y) +fun z_equal(x, y) = builtin("z_equal", x, y) +fun z_gt(x, y) = builtin("z_gt", x, y) +fun z_geq(x, y) = builtin("z_geq", x, y) +fun println(x) = builtin("println", x) +fun print(x) = builtin("print", x) +fun debug(x) = builtin("debug", x) +fun map(f, ls) = + if ls is + Cons (h, t) then + Cons (f(h), map(f, t)) + Nil then + Nil +fun filter(f_2, ls_2) = + if ls_2 is + Cons (h_2, t_2) then + if f_2(h_2) then + Cons (h_2, filter(f_2, t_2)) + else + (filter(f_2, t_2)) + Nil then + Nil +fun foldl(f_4, i, ls_4) = + if ls_4 is + Cons (h_4, t_4) then + foldl(f_4, f_4(i, h_4), t_4) + Nil then + i +fun foldr(f_5, i_1, ls_5) = + if ls_5 is + Cons (h_5, t_5) then + f_5(h_5, foldr(f_5, i_1, t_5)) + Nil then + i_1 +fun zip(xs, ys) = + if xs is + Cons (hx, tx) then + if ys is + Cons (hy, ty) then + Cons (Tuple2 (hx, hy), zip(tx, ty)) + Nil then + Nil + Nil then + Nil +fun zipWith(f_7, xs_4, ys_4) = + if xs_4 is + Cons (hx_4, tx_4) then + if ys_4 is + Cons (hy_4, ty_4) then + Cons (f_7(hx_4, hy_4), zipWith(f_7, tx_4, ty_4)) + Nil then + Nil + Nil then + Nil +fun head(ls_7) = + if ls_7 is + Cons (h_7, t_7) then + h_7 + Nil then + error +fun tail(ls_9) = + if ls_9 is + Cons (h_9, t_9) then + t_9 + Nil then + error +fun enumFromTo(a, b) = + if a <= b then + Cons (a, enumFromTo(a + 1, b)) + else + (Nil) +fun enumFromThenTo(a_1, t_11, b_1) = + if a_1 <= b_1 then + Cons (a_1, enumFromThenTo(t_11, 2 * t_11 - a_1, b_1)) + else + (Nil) +fun take(n, ls_11) = + if n > 0 then + if ls_11 is + Cons (h_11, t_13) then + Cons (h_11, take(n - 1, t_13)) + Nil then + Nil + else + (Nil) +fun length(ls_13) = + if ls_13 is + Cons (h_13, t_15) then + 1 + (length(t_15)) + Nil then + 0 +fun mappend(xs_8, ys_8) = + if xs_8 is + Cons (h_14, t_16) then + Cons (h_14, mappend(t_16, ys_8)) + Nil then + ys_8 +fun sum(ls_14) = + sumAux(ls_14, 0) +fun sumAux(ls_15, a_4) = + if ls_15 is + Nil then + a_4 + Cons (h_15, t_17) then + sumAux(t_17, a_4 + h_15) +fun atIndex(n_2, ls_16) = + if n_2 < 0 then + error + else + if ls_16 is + Cons (h_16, t_18) then + if n_2 == 0 then + h_16 + else + (atIndex(n_2 - 1, t_18)) + Nil then + error +fun concat(lss) = + if lss is + Cons (h_18, t_20) then + mappend(h_18, concat(t_20)) + Nil then + Nil +fun reverse(ls_18) = + reverse_helper(ls_18, Nil) +fun reverse_helper(ls_19, a_5) = + if ls_19 is + Cons (h_19, t_21) then + reverse_helper(t_21, Cons (h_19, a_5)) + Nil then + a_5 +fun listcomp_fun1(ms, listcomp_fun_para) = + if listcomp_fun_para is + Cons(listcomp_fun_ls_h, listcomp_fun_ls_t) then + listcomp_fun2(ms, listcomp_fun_ls_h, listcomp_fun_ls_t, ms) + Nil then + Nil +fun listcomp_fun2(ms, listcomp_fun_ls_h_out, listcomp_fun_ls_t_out, listcomp_fun_para) = + if listcomp_fun_para is + Cons(listcomp_fun_ls_h, listcomp_fun_ls_t) then + Cons(Tuple2 (listcomp_fun_ls_h_out, listcomp_fun_ls_h), listcomp_fun2(ms, listcomp_fun_ls_h_out, listcomp_fun_ls_t_out, listcomp_fun_ls_t)) + Nil then + listcomp_fun1(ms, listcomp_fun_ls_t_out) +fun test(test_arg1) = + let ns = z_enumFromTo(const5000(), z_add(const5000(), test_arg1)) + let ms = z_enumFromTo(const10000(), z_add(const10000(), test_arg1)) + let tripls = map(f1, listcomp_fun1(ms, ns)) + let rs = map(f2, tripls) + max'(rs) +fun const10000() = + z_of_int(10000) +fun f1(f1_arg1) = + if f1_arg1 is + Tuple2 (f1_Tuple2_0, f1_Tuple2_1) then + Tuple3 (f1_Tuple2_0, f1_Tuple2_1, gcdE(f1_Tuple2_0, f1_Tuple2_1)) +fun quotRem(quotRem_arg1, quotRem_arg2) = + Tuple2 (z_div(quotRem_arg1, quotRem_arg2), z_mod(quotRem_arg1, quotRem_arg2)) +fun max'(max'_arg1) = + if max'_arg1 is + Cons (max'_Cons_0, max'_Cons_1) then + if max'_Cons_1 is + Nil then + max'_Cons_0 + Cons (max'_Cons_0_1, max'_Cons_1_1) then + if z_lt(max'_Cons_0, max'_Cons_0_1) then + max'(Cons (max'_Cons_0_1, max'_Cons_1_1)) + else + (max'(Cons (max'_Cons_0, max'_Cons_1_1))) +fun g(g_arg1, g_arg2) = + if g_arg1 is + Tuple3 (g_Tuple3_0, g_Tuple3_1, g_Tuple3_2) then + if g_arg2 is + Tuple3 (g_Tuple3_0_1, g_Tuple3_1_1, g_Tuple3_2_1) then + if z_equal(g_Tuple3_2_1, const0()) then + Tuple3 (g_Tuple3_2, g_Tuple3_0, g_Tuple3_1) + else + let matchIdent = quotRem(g_Tuple3_2, g_Tuple3_2_1) + if matchIdent is + Tuple2 (g_Tuple2_0, g_Tuple2_1) then + g(Tuple3 (g_Tuple3_0_1, g_Tuple3_1_1, g_Tuple3_2_1), Tuple3 (z_sub(g_Tuple3_0, z_mul(g_Tuple2_0, g_Tuple3_0_1)), z_sub(g_Tuple3_1, z_mul(g_Tuple2_0, g_Tuple3_1_1)), g_Tuple2_1)) +fun abs(abs_arg1) = + if z_lt(abs_arg1, const0()) then + z_sub(const0(), abs_arg1) + else + abs_arg1 +fun f2(f2_arg1) = + if f2_arg1 is + Tuple3 (f2_Tuple3_0, f2_Tuple3_1, f2_Tuple3_2) then + if f2_Tuple3_2 is + Tuple3 (f2_Tuple3_0_1, f2_Tuple3_1_1, f2_Tuple3_2_1) then + abs(z_add(z_add(f2_Tuple3_0_1, f2_Tuple3_1_1), f2_Tuple3_2_1)) +fun const0() = + z_of_int(0) +fun gcdE(gcdE_arg1, gcdE_arg2) = + if z_equal(gcdE_arg1, const0()) then + Tuple3 (gcdE_arg2, const0(), const1()) + else + (g(Tuple3 (const1(), const0(), gcdE_arg1), Tuple3 (const0(), const1(), gcdE_arg2))) +fun const1() = + z_of_int(1) +fun const5000() = + z_of_int(5000) +fun testGcd_nofib(testGcd_nofib_arg1) = + test(testGcd_nofib_arg1) +fun z_enumFromTo(z_enumFromTo_arg1, z_enumFromTo_arg2) = + if z_leq(z_enumFromTo_arg1, z_enumFromTo_arg2) then + Cons (z_enumFromTo_arg1, z_enumFromTo(z_add(z_enumFromTo_arg1, const1()), z_enumFromTo_arg2)) + else + (Nil) +testGcd_nofib(z_of_int(400)) +//│ |#fun| |error|(||)| |#=| |builtin|(|"error"|)|↵|#fun| |z_of_int|(|x|)| |#=| |builtin|(|"z_of_int"|,| |x|)|↵|#fun| |z_to_int|(|x|)| |#=| |builtin|(|"z_to_int"|,| |x|)|↵|#fun| |z_add|(|x|,| |y|)| |#=| |builtin|(|"z_add"|,| |x|,| |y|)|↵|#fun| |z_sub|(|x|,| |y|)| |#=| |builtin|(|"z_sub"|,| |x|,| |y|)|↵|#fun| |z_div|(|x|,| |y|)| |#=| |builtin|(|"z_div"|,| |x|,| |y|)|↵|#fun| |z_mul|(|x|,| |y|)| |#=| |builtin|(|"z_mul"|,| |x|,| |y|)|↵|#fun| |z_mod|(|x|,| |y|)| |#=| |builtin|(|"z_mod"|,| |x|,| |y|)|↵|#fun| |z_lt|(|x|,| |y|)| |#=| |builtin|(|"z_lt"|,| |x|,| |y|)|↵|#fun| |z_leq|(|x|,| |y|)| |#=| |builtin|(|"z_leq"|,| |x|,| |y|)|↵|#fun| |z_equal|(|x|,| |y|)| |#=| |builtin|(|"z_equal"|,| |x|,| |y|)|↵|#fun| |z_gt|(|x|,| |y|)| |#=| |builtin|(|"z_gt"|,| |x|,| |y|)|↵|#fun| |z_geq|(|x|,| |y|)| |#=| |builtin|(|"z_geq"|,| |x|,| |y|)|↵|#fun| |println|(|x|)| |#=| |builtin|(|"println"|,| |x|)|↵|#fun| |print|(|x|)| |#=| |builtin|(|"print"|,| |x|)|↵|#fun| |debug|(|x|)| |#=| |builtin|(|"debug"|,| |x|)|↵|#fun| |map|(|f|,| |ls|)| |#=|→|#if| |ls| |is|→|Cons| |(|h|,| |t|)| |#then|→|Cons| |(|f|(|h|)|,| |map|(|f|,| |t|)|)|←|↵|Nil| |#then|→|Nil|←|←|←|↵|#fun| |filter|(|f_2|,| |ls_2|)| |#=|→|#if| |ls_2| |is|→|Cons| |(|h_2|,| |t_2|)| |#then|→|#if| |f_2|(|h_2|)| |#then|→|Cons| |(|h_2|,| |filter|(|f_2|,| |t_2|)|)|←|↵|#else|→|(|filter|(|f_2|,| |t_2|)|)|←|←|↵|Nil| |#then|→|Nil|←|←|←|↵|#fun| |foldl|(|f_4|,| |i|,| |ls_4|)| |#=|→|#if| |ls_4| |is|→|Cons| |(|h_4|,| |t_4|)| |#then|→|foldl|(|f_4|,| |f_4|(|i|,| |h_4|)|,| |t_4|)|←|↵|Nil| |#then|→|i|←|←|←|↵|#fun| |foldr|(|f_5|,| |i_1|,| |ls_5|)| |#=|→|#if| |ls_5| |is|→|Cons| |(|h_5|,| |t_5|)| |#then|→|f_5|(|h_5|,| |foldr|(|f_5|,| |i_1|,| |t_5|)|)|←|↵|Nil| |#then|→|i_1|←|←|←|↵|#fun| |zip|(|xs|,| |ys|)| |#=|→|#if| |xs| |is|→|Cons| |(|hx|,| |tx|)| |#then|→|#if| |ys| |is|→|Cons| |(|hy|,| |ty|)| |#then|→|Cons| |(|Tuple2| |(|hx|,| |hy|)|,| |zip|(|tx|,| |ty|)|)|←|↵|Nil| |#then|→|Nil|←|←|←|↵|Nil| |#then|→|Nil|←|←|←|↵|#fun| |zipWith|(|f_7|,| |xs_4|,| |ys_4|)| |#=|→|#if| |xs_4| |is|→|Cons| |(|hx_4|,| |tx_4|)| |#then|→|#if| |ys_4| |is|→|Cons| |(|hy_4|,| |ty_4|)| |#then|→|Cons| |(|f_7|(|hx_4|,| |hy_4|)|,| |zipWith|(|f_7|,| |tx_4|,| |ty_4|)|)|←|↵|Nil| |#then|→|Nil|←|←|←|↵|Nil| |#then|→|Nil|←|←|←|↵|#fun| |head|(|ls_7|)| |#=|→|#if| |ls_7| |is|→|Cons| |(|h_7|,| |t_7|)| |#then|→|h_7|←|↵|Nil| |#then|→|error|←|←|←|↵|#fun| |tail|(|ls_9|)| |#=|→|#if| |ls_9| |is|→|Cons| |(|h_9|,| |t_9|)| |#then|→|t_9|←|↵|Nil| |#then|→|error|←|←|←|↵|#fun| |enumFromTo|(|a|,| |b|)| |#=|→|#if| |a| |<=| |b| |#then|→|Cons| |(|a|,| |enumFromTo|(|a| |+| |1|,| |b|)|)|←|↵|#else|→|(|Nil|)|←|←|↵|#fun| |enumFromThenTo|(|a_1|,| |t_11|,| |b_1|)| |#=|→|#if| |a_1| |<=| |b_1| |#then|→|Cons| |(|a_1|,| |enumFromThenTo|(|t_11|,| |2| |*| |t_11| |-| |a_1|,| |b_1|)|)|←|↵|#else|→|(|Nil|)|←|←|↵|#fun| |take|(|n|,| |ls_11|)| |#=|→|#if| |n| |>| |0| |#then|→|#if| |ls_11| |is|→|Cons| |(|h_11|,| |t_13|)| |#then|→|Cons| |(|h_11|,| |take|(|n| |-| |1|,| |t_13|)|)|←|↵|Nil| |#then|→|Nil|←|←|←|↵|#else|→|(|Nil|)|←|←|↵|#fun| |length|(|ls_13|)| |#=|→|#if| |ls_13| |is|→|Cons| |(|h_13|,| |t_15|)| |#then|→|1| |+| |(|length|(|t_15|)|)|←|↵|Nil| |#then|→|0|←|←|←|↵|#fun| |mappend|(|xs_8|,| |ys_8|)| |#=|→|#if| |xs_8| |is|→|Cons| |(|h_14|,| |t_16|)| |#then|→|Cons| |(|h_14|,| |mappend|(|t_16|,| |ys_8|)|)|←|↵|Nil| |#then|→|ys_8|←|←|←|↵|#fun| |sum|(|ls_14|)| |#=|→|sumAux|(|ls_14|,| |0|)|←|↵|#fun| |sumAux|(|ls_15|,| |a_4|)| |#=|→|#if| |ls_15| |is|→|Nil| |#then|→|a_4|←|↵|Cons| |(|h_15|,| |t_17|)| |#then|→|sumAux|(|t_17|,| |a_4| |+| |h_15|)|←|←|←|↵|#fun| |atIndex|(|n_2|,| |ls_16|)| |#=|→|#if| |n_2| |<| |0| |#then|→|error|←|↵|#else|→|#if| |ls_16| |is|→|Cons| |(|h_16|,| |t_18|)| |#then|→|#if| |n_2| |==| |0| |#then|→|h_16|←|↵|#else|→|(|atIndex|(|n_2| |-| |1|,| |t_18|)|)|←|←|↵|Nil| |#then|→|error|←|←|←|←|↵|#fun| |concat|(|lss|)| |#=|→|#if| |lss| |is|→|Cons| |(|h_18|,| |t_20|)| |#then|→|mappend|(|h_18|,| |concat|(|t_20|)|)|←|↵|Nil| |#then|→|Nil|←|←|←|↵|#fun| |reverse|(|ls_18|)| |#=|→|reverse_helper|(|ls_18|,| |Nil|)|←|↵|#fun| |reverse_helper|(|ls_19|,| |a_5|)| |#=|→|#if| |ls_19| |is|→|Cons| |(|h_19|,| |t_21|)| |#then|→|reverse_helper|(|t_21|,| |Cons| |(|h_19|,| |a_5|)|)|←|↵|Nil| |#then|→|a_5|←|←|←|↵|#fun| |listcomp_fun1|(|ms|,| |listcomp_fun_para|)| |#=|→|#if| |listcomp_fun_para| |is|→|Cons|(|listcomp_fun_ls_h|,| |listcomp_fun_ls_t|)| |#then|→|listcomp_fun2|(|ms|,| |listcomp_fun_ls_h|,| |listcomp_fun_ls_t|,| |ms|)|←|↵|Nil| |#then|→|Nil|←|←|←|↵|#fun| |listcomp_fun2|(|ms|,| |listcomp_fun_ls_h_out|,| |listcomp_fun_ls_t_out|,| |listcomp_fun_para|)| |#=|→|#if| |listcomp_fun_para| |is|→|Cons|(|listcomp_fun_ls_h|,| |listcomp_fun_ls_t|)| |#then|→|Cons|(|Tuple2| |(|listcomp_fun_ls_h_out|,| |listcomp_fun_ls_h|)|,| |listcomp_fun2|(|ms|,| |listcomp_fun_ls_h_out|,| |listcomp_fun_ls_t_out|,| |listcomp_fun_ls_t|)|)|←|↵|Nil| |#then|→|listcomp_fun1|(|ms|,| |listcomp_fun_ls_t_out|)|←|←|←|↵|#fun| |test|(|test_arg1|)| |#=|→|#let| |ns| |#=| |z_enumFromTo|(|const5000|(||)|,| |z_add|(|const5000|(||)|,| |test_arg1|)|)|↵|#let| |ms| |#=| |z_enumFromTo|(|const10000|(||)|,| |z_add|(|const10000|(||)|,| |test_arg1|)|)|↵|#let| |tripls| |#=| |map|(|f1|,| |listcomp_fun1|(|ms|,| |ns|)|)|↵|#let| |rs| |#=| |map|(|f2|,| |tripls|)|↵|max'|(|rs|)|←|↵|#fun| |const10000|(||)| |#=|→|z_of_int|(|10000|)|←|↵|#fun| |f1|(|f1_arg1|)| |#=|→|#if| |f1_arg1| |is|→|Tuple2| |(|f1_Tuple2_0|,| |f1_Tuple2_1|)| |#then|→|Tuple3| |(|f1_Tuple2_0|,| |f1_Tuple2_1|,| |gcdE|(|f1_Tuple2_0|,| |f1_Tuple2_1|)|)|←|←|←|↵|#fun| |quotRem|(|quotRem_arg1|,| |quotRem_arg2|)| |#=|→|Tuple2| |(|z_div|(|quotRem_arg1|,| |quotRem_arg2|)|,| |z_mod|(|quotRem_arg1|,| |quotRem_arg2|)|)|←|↵|#fun| |max'|(|max'_arg1|)| |#=|→|#if| |max'_arg1| |is|→|Cons| |(|max'_Cons_0|,| |max'_Cons_1|)| |#then|→|#if| |max'_Cons_1| |is|→|Nil| |#then|→|max'_Cons_0|←|↵|Cons| |(|max'_Cons_0_1|,| |max'_Cons_1_1|)| |#then|→|#if| |z_lt|(|max'_Cons_0|,| |max'_Cons_0_1|)| |#then|→|max'|(|Cons| |(|max'_Cons_0_1|,| |max'_Cons_1_1|)|)|←|↵|#else|→|(|max'|(|Cons| |(|max'_Cons_0|,| |max'_Cons_1_1|)|)|)|←|←|←|←|←|←|↵|#fun| |g|(|g_arg1|,| |g_arg2|)| |#=|→|#if| |g_arg1| |is|→|Tuple3| |(|g_Tuple3_0|,| |g_Tuple3_1|,| |g_Tuple3_2|)| |#then|→|#if| |g_arg2| |is|→|Tuple3| |(|g_Tuple3_0_1|,| |g_Tuple3_1_1|,| |g_Tuple3_2_1|)| |#then|→|#if| |z_equal|(|g_Tuple3_2_1|,| |const0|(||)|)| |#then|→|Tuple3| |(|g_Tuple3_2|,| |g_Tuple3_0|,| |g_Tuple3_1|)|←|↵|#else|→|#let| |matchIdent| |#=| |quotRem|(|g_Tuple3_2|,| |g_Tuple3_2_1|)|↵|#if| |matchIdent| |is|→|Tuple2| |(|g_Tuple2_0|,| |g_Tuple2_1|)| |#then|→|g|(|Tuple3| |(|g_Tuple3_0_1|,| |g_Tuple3_1_1|,| |g_Tuple3_2_1|)|,| |Tuple3| |(|z_sub|(|g_Tuple3_0|,| |z_mul|(|g_Tuple2_0|,| |g_Tuple3_0_1|)|)|,| |z_sub|(|g_Tuple3_1|,| |z_mul|(|g_Tuple2_0|,| |g_Tuple3_1_1|)|)|,| |g_Tuple2_1|)|)|←|←|←|←|←|←|←|←|↵|#fun| |abs|(|abs_arg1|)| |#=|→|#if| |z_lt|(|abs_arg1|,| |const0|(||)|)| |#then|→|z_sub|(|const0|(||)|,| |abs_arg1|)|←|↵|#else|→|abs_arg1|←|←|↵|#fun| |f2|(|f2_arg1|)| |#=|→|#if| |f2_arg1| |is|→|Tuple3| |(|f2_Tuple3_0|,| |f2_Tuple3_1|,| |f2_Tuple3_2|)| |#then|→|#if| |f2_Tuple3_2| |is|→|Tuple3| |(|f2_Tuple3_0_1|,| |f2_Tuple3_1_1|,| |f2_Tuple3_2_1|)| |#then|→|abs|(|z_add|(|z_add|(|f2_Tuple3_0_1|,| |f2_Tuple3_1_1|)|,| |f2_Tuple3_2_1|)|)|←|←|←|←|←|↵|#fun| |const0|(||)| |#=|→|z_of_int|(|0|)|←|↵|#fun| |gcdE|(|gcdE_arg1|,| |gcdE_arg2|)| |#=|→|#if| |z_equal|(|gcdE_arg1|,| |const0|(||)|)| |#then|→|Tuple3| |(|gcdE_arg2|,| |const0|(||)|,| |const1|(||)|)|←|↵|#else|→|(|g|(|Tuple3| |(|const1|(||)|,| |const0|(||)|,| |gcdE_arg1|)|,| |Tuple3| |(|const0|(||)|,| |const1|(||)|,| |gcdE_arg2|)|)|)|←|←|↵|#fun| |const1|(||)| |#=|→|z_of_int|(|1|)|←|↵|#fun| |const5000|(||)| |#=|→|z_of_int|(|5000|)|←|↵|#fun| |testGcd_nofib|(|testGcd_nofib_arg1|)| |#=|→|test|(|testGcd_nofib_arg1|)|←|↵|#fun| |z_enumFromTo|(|z_enumFromTo_arg1|,| |z_enumFromTo_arg2|)| |#=|→|#if| |z_leq|(|z_enumFromTo_arg1|,| |z_enumFromTo_arg2|)| |#then|→|Cons| |(|z_enumFromTo_arg1|,| |z_enumFromTo|(|z_add|(|z_enumFromTo_arg1|,| |const1|(||)|)|,| |z_enumFromTo_arg2|)|)|←|↵|#else|→|(|Nil|)|←|←|↵|testGcd_nofib|(|z_of_int|(|400|)|)| +//│ Parsed: {fun error = () => builtin("error",); fun z_of_int = (x,) => builtin("z_of_int", x,); fun z_to_int = (x,) => builtin("z_to_int", x,); fun z_add = (x, y,) => builtin("z_add", x, y,); fun z_sub = (x, y,) => builtin("z_sub", x, y,); fun z_div = (x, y,) => builtin("z_div", x, y,); fun z_mul = (x, y,) => builtin("z_mul", x, y,); fun z_mod = (x, y,) => builtin("z_mod", x, y,); fun z_lt = (x, y,) => builtin("z_lt", x, y,); fun z_leq = (x, y,) => builtin("z_leq", x, y,); fun z_equal = (x, y,) => builtin("z_equal", x, y,); fun z_gt = (x, y,) => builtin("z_gt", x, y,); fun z_geq = (x, y,) => builtin("z_geq", x, y,); fun println = (x,) => builtin("println", x,); fun print = (x,) => builtin("print", x,); fun debug = (x,) => builtin("debug", x,); fun map = (f, ls,) => {if ls is ‹(Cons(h, t,)) then {Cons(f(h,), map(f, t,),)}; (Nil) then {Nil}›}; fun filter = (f_2, ls_2,) => {if ls_2 is ‹(Cons(h_2, t_2,)) then {if (f_2(h_2,)) then {Cons(h_2, filter(f_2, t_2,),)} else {'(' filter(f_2, t_2,) ')'}}; (Nil) then {Nil}›}; fun foldl = (f_4, i, ls_4,) => {if ls_4 is ‹(Cons(h_4, t_4,)) then {foldl(f_4, f_4(i, h_4,), t_4,)}; (Nil) then {i}›}; fun foldr = (f_5, i_1, ls_5,) => {if ls_5 is ‹(Cons(h_5, t_5,)) then {f_5(h_5, foldr(f_5, i_1, t_5,),)}; (Nil) then {i_1}›}; fun zip = (xs, ys,) => {if xs is ‹(Cons(hx, tx,)) then {if ys is ‹(Cons(hy, ty,)) then {Cons(Tuple2(hx, hy,), zip(tx, ty,),)}; (Nil) then {Nil}›}; (Nil) then {Nil}›}; fun zipWith = (f_7, xs_4, ys_4,) => {if xs_4 is ‹(Cons(hx_4, tx_4,)) then {if ys_4 is ‹(Cons(hy_4, ty_4,)) then {Cons(f_7(hx_4, hy_4,), zipWith(f_7, tx_4, ty_4,),)}; (Nil) then {Nil}›}; (Nil) then {Nil}›}; fun head = (ls_7,) => {if ls_7 is ‹(Cons(h_7, t_7,)) then {h_7}; (Nil) then {error}›}; fun tail = (ls_9,) => {if ls_9 is ‹(Cons(h_9, t_9,)) then {t_9}; (Nil) then {error}›}; fun enumFromTo = (a, b,) => {if (<=(a, b,)) then {Cons(a, enumFromTo(+(a, 1,), b,),)} else {'(' Nil ')'}}; fun enumFromThenTo = (a_1, t_11, b_1,) => {if (<=(a_1, b_1,)) then {Cons(a_1, enumFromThenTo(t_11, -(*(2, t_11,), a_1,), b_1,),)} else {'(' Nil ')'}}; fun take = (n, ls_11,) => {if (>(n, 0,)) then {if ls_11 is ‹(Cons(h_11, t_13,)) then {Cons(h_11, take(-(n, 1,), t_13,),)}; (Nil) then {Nil}›} else {'(' Nil ')'}}; fun length = (ls_13,) => {if ls_13 is ‹(Cons(h_13, t_15,)) then {+(1, '(' length(t_15,) ')',)}; (Nil) then {0}›}; fun mappend = (xs_8, ys_8,) => {if xs_8 is ‹(Cons(h_14, t_16,)) then {Cons(h_14, mappend(t_16, ys_8,),)}; (Nil) then {ys_8}›}; fun sum = (ls_14,) => {sumAux(ls_14, 0,)}; fun sumAux = (ls_15, a_4,) => {if ls_15 is ‹(Nil) then {a_4}; (Cons(h_15, t_17,)) then {sumAux(t_17, +(a_4, h_15,),)}›}; fun atIndex = (n_2, ls_16,) => {if (<(n_2, 0,)) then {error} else {if ls_16 is ‹(Cons(h_16, t_18,)) then {if (==(n_2, 0,)) then {h_16} else {'(' atIndex(-(n_2, 1,), t_18,) ')'}}; (Nil) then {error}›}}; fun concat = (lss,) => {if lss is ‹(Cons(h_18, t_20,)) then {mappend(h_18, concat(t_20,),)}; (Nil) then {Nil}›}; fun reverse = (ls_18,) => {reverse_helper(ls_18, Nil,)}; fun reverse_helper = (ls_19, a_5,) => {if ls_19 is ‹(Cons(h_19, t_21,)) then {reverse_helper(t_21, Cons(h_19, a_5,),)}; (Nil) then {a_5}›}; fun listcomp_fun1 = (ms, listcomp_fun_para,) => {if listcomp_fun_para is ‹(Cons(listcomp_fun_ls_h, listcomp_fun_ls_t,)) then {listcomp_fun2(ms, listcomp_fun_ls_h, listcomp_fun_ls_t, ms,)}; (Nil) then {Nil}›}; fun listcomp_fun2 = (ms, listcomp_fun_ls_h_out, listcomp_fun_ls_t_out, listcomp_fun_para,) => {if listcomp_fun_para is ‹(Cons(listcomp_fun_ls_h, listcomp_fun_ls_t,)) then {Cons(Tuple2(listcomp_fun_ls_h_out, listcomp_fun_ls_h,), listcomp_fun2(ms, listcomp_fun_ls_h_out, listcomp_fun_ls_t_out, listcomp_fun_ls_t,),)}; (Nil) then {listcomp_fun1(ms, listcomp_fun_ls_t_out,)}›}; fun test = (test_arg1,) => {let ns = z_enumFromTo(const5000(), z_add(const5000(), test_arg1,),); let ms = z_enumFromTo(const10000(), z_add(const10000(), test_arg1,),); let tripls = map(f1, listcomp_fun1(ms, ns,),); let rs = map(f2, tripls,); max'(rs,)}; fun const10000 = () => {z_of_int(10000,)}; fun f1 = (f1_arg1,) => {if f1_arg1 is ‹(Tuple2(f1_Tuple2_0, f1_Tuple2_1,)) then {Tuple3(f1_Tuple2_0, f1_Tuple2_1, gcdE(f1_Tuple2_0, f1_Tuple2_1,),)}›}; fun quotRem = (quotRem_arg1, quotRem_arg2,) => {Tuple2(z_div(quotRem_arg1, quotRem_arg2,), z_mod(quotRem_arg1, quotRem_arg2,),)}; fun max' = (max'_arg1,) => {if max'_arg1 is ‹(Cons(max'_Cons_0, max'_Cons_1,)) then {if max'_Cons_1 is ‹(Nil) then {max'_Cons_0}; (Cons(max'_Cons_0_1, max'_Cons_1_1,)) then {if (z_lt(max'_Cons_0, max'_Cons_0_1,)) then {max'(Cons(max'_Cons_0_1, max'_Cons_1_1,),)} else {'(' max'(Cons(max'_Cons_0, max'_Cons_1_1,),) ')'}}›}›}; fun g = (g_arg1, g_arg2,) => {if g_arg1 is ‹(Tuple3(g_Tuple3_0, g_Tuple3_1, g_Tuple3_2,)) then {if g_arg2 is ‹(Tuple3(g_Tuple3_0_1, g_Tuple3_1_1, g_Tuple3_2_1,)) then {if (z_equal(g_Tuple3_2_1, const0(),)) then {Tuple3(g_Tuple3_2, g_Tuple3_0, g_Tuple3_1,)} else {let matchIdent = quotRem(g_Tuple3_2, g_Tuple3_2_1,); if matchIdent is ‹(Tuple2(g_Tuple2_0, g_Tuple2_1,)) then {g(Tuple3(g_Tuple3_0_1, g_Tuple3_1_1, g_Tuple3_2_1,), Tuple3(z_sub(g_Tuple3_0, z_mul(g_Tuple2_0, g_Tuple3_0_1,),), z_sub(g_Tuple3_1, z_mul(g_Tuple2_0, g_Tuple3_1_1,),), g_Tuple2_1,),)}›}}›}›}; fun abs = (abs_arg1,) => {if (z_lt(abs_arg1, const0(),)) then {z_sub(const0(), abs_arg1,)} else {abs_arg1}}; fun f2 = (f2_arg1,) => {if f2_arg1 is ‹(Tuple3(f2_Tuple3_0, f2_Tuple3_1, f2_Tuple3_2,)) then {if f2_Tuple3_2 is ‹(Tuple3(f2_Tuple3_0_1, f2_Tuple3_1_1, f2_Tuple3_2_1,)) then {abs(z_add(z_add(f2_Tuple3_0_1, f2_Tuple3_1_1,), f2_Tuple3_2_1,),)}›}›}; fun const0 = () => {z_of_int(0,)}; fun gcdE = (gcdE_arg1, gcdE_arg2,) => {if (z_equal(gcdE_arg1, const0(),)) then {Tuple3(gcdE_arg2, const0(), const1(),)} else {'(' g(Tuple3(const1(), const0(), gcdE_arg1,), Tuple3(const0(), const1(), gcdE_arg2,),) ')'}}; fun const1 = () => {z_of_int(1,)}; fun const5000 = () => {z_of_int(5000,)}; fun testGcd_nofib = (testGcd_nofib_arg1,) => {test(testGcd_nofib_arg1,)}; fun z_enumFromTo = (z_enumFromTo_arg1, z_enumFromTo_arg2,) => {if (z_leq(z_enumFromTo_arg1, z_enumFromTo_arg2,)) then {Cons(z_enumFromTo_arg1, z_enumFromTo(z_add(z_enumFromTo_arg1, const1(),), z_enumFromTo_arg2,),)} else {'(' Nil ')'}}; testGcd_nofib(z_of_int(400,),)} +//│ +//│ +//│ IR: +//│ Program: +//│ class Lambda$0() extends Callable { +//│ def apply0() = +//│ let* (x$270) = error() in -- #1354 +//│ x$270 -- #1353 +//│ } +//│ class Lambda$1() extends Callable { +//│ def apply0() = +//│ let* (x$271) = error() in -- #1357 +//│ x$271 -- #1356 +//│ } +//│ class Lambda$2() extends Callable { +//│ def apply0() = +//│ let* (x$272) = error() in -- #1360 +//│ x$272 -- #1359 +//│ } +//│ class Lambda$3() extends Callable { +//│ def apply0() = +//│ let* (x$273) = error() in -- #1363 +//│ x$273 -- #1362 +//│ } +//│ class Lambda$4() extends Callable { +//│ def apply1(x$274) = +//│ let* (x$275) = f1(x$274) in -- #1368 +//│ x$275 -- #1367 +//│ } +//│ class Lambda$5() extends Callable { +//│ def apply1(x$276) = +//│ let* (x$277) = f2(x$276) in -- #1373 +//│ x$277 -- #1372 +//│ } +//│ def error() = +//│ let x$2 = Callable.apply1(builtin,error) in -- #14 +//│ x$2 -- #13 +//│ def z_of_int(x$3) = +//│ let x$4 = Callable.apply2(builtin,z_of_int,x$3) in -- #22 +//│ x$4 -- #21 +//│ def z_to_int(x$5) = +//│ let x$6 = Callable.apply2(builtin,z_to_int,x$5) in -- #30 +//│ x$6 -- #29 +//│ def z_add(x$7,y$0) = +//│ let x$8 = Callable.apply3(builtin,z_add,x$7,y$0) in -- #40 +//│ x$8 -- #39 +//│ def z_sub(x$9,y$1) = +//│ let x$10 = Callable.apply3(builtin,z_sub,x$9,y$1) in -- #50 +//│ x$10 -- #49 +//│ def z_div(x$11,y$2) = +//│ let x$12 = Callable.apply3(builtin,z_div,x$11,y$2) in -- #60 +//│ x$12 -- #59 +//│ def z_mul(x$13,y$3) = +//│ let x$14 = Callable.apply3(builtin,z_mul,x$13,y$3) in -- #70 +//│ x$14 -- #69 +//│ def z_mod(x$15,y$4) = +//│ let x$16 = Callable.apply3(builtin,z_mod,x$15,y$4) in -- #80 +//│ x$16 -- #79 +//│ def z_lt(x$17,y$5) = +//│ let x$18 = Callable.apply3(builtin,z_lt,x$17,y$5) in -- #90 +//│ x$18 -- #89 +//│ def z_leq(x$19,y$6) = +//│ let x$20 = Callable.apply3(builtin,z_leq,x$19,y$6) in -- #100 +//│ x$20 -- #99 +//│ def z_equal(x$21,y$7) = +//│ let x$22 = Callable.apply3(builtin,z_equal,x$21,y$7) in -- #110 +//│ x$22 -- #109 +//│ def z_gt(x$23,y$8) = +//│ let x$24 = Callable.apply3(builtin,z_gt,x$23,y$8) in -- #120 +//│ x$24 -- #119 +//│ def z_geq(x$25,y$9) = +//│ let x$26 = Callable.apply3(builtin,z_geq,x$25,y$9) in -- #130 +//│ x$26 -- #129 +//│ def println(x$27) = +//│ let x$28 = Callable.apply2(builtin,println,x$27) in -- #138 +//│ x$28 -- #137 +//│ def print(x$29) = +//│ let x$30 = Callable.apply2(builtin,print,x$29) in -- #146 +//│ x$30 -- #145 +//│ def debug(x$31) = +//│ let x$32 = Callable.apply2(builtin,debug,x$31) in -- #154 +//│ x$32 -- #153 +//│ def map(f$0,ls$0) = +//│ case ls$0 of -- #189 +//│ Cons => +//│ let x$34 = Cons.t(ls$0) in -- #185 +//│ let x$35 = Cons.h(ls$0) in -- #184 +//│ let x$36 = Callable.apply1(f$0,x$35) in -- #183 +//│ let* (x$37) = map(f$0,x$34) in -- #182 +//│ let x$38 = Cons(x$36,x$37) in -- #181 +//│ jump j$0(x$38) -- #180 +//│ Nil => +//│ let x$39 = Nil() in -- #188 +//│ jump j$0(x$39) -- #187 +//│ def j$0(x$33) = +//│ x$33 -- #156 +//│ def filter(f_2$0,ls_2$0) = +//│ case ls_2$0 of -- #236 +//│ Cons => +//│ let x$41 = Cons.t(ls_2$0) in -- #232 +//│ let x$42 = Cons.h(ls_2$0) in -- #231 +//│ let x$43 = Callable.apply1(f_2$0,x$42) in -- #230 +//│ if x$43 -- #229 +//│ true => +//│ let* (x$45) = filter(f_2$0,x$41) in -- #220 +//│ let x$46 = Cons(x$42,x$45) in -- #219 +//│ jump j$2(x$46) -- #218 +//│ false => +//│ let* (x$47) = filter(f_2$0,x$41) in -- #228 +//│ jump j$2(x$47) -- #227 +//│ Nil => +//│ let x$48 = Nil() in -- #235 +//│ jump j$1(x$48) -- #234 +//│ def j$1(x$40) = +//│ x$40 -- #191 +//│ def j$2(x$44) = +//│ jump j$1(x$44) -- #206 +//│ def foldl(f_4$0,i$0,ls_4$0) = +//│ case ls_4$0 of -- #268 +//│ Cons => +//│ let x$50 = Cons.t(ls_4$0) in -- #265 +//│ let x$51 = Cons.h(ls_4$0) in -- #264 +//│ let x$52 = Callable.apply2(f_4$0,i$0,x$51) in -- #263 +//│ let* (x$53) = foldl(f_4$0,x$52,x$50) in -- #262 +//│ jump j$3(x$53) -- #261 +//│ Nil => +//│ jump j$3(i$0) -- #267 +//│ def j$3(x$49) = +//│ x$49 -- #238 +//│ def foldr(f_5$0,i_1$0,ls_5$0) = +//│ case ls_5$0 of -- #300 +//│ Cons => +//│ let x$55 = Cons.t(ls_5$0) in -- #297 +//│ let x$56 = Cons.h(ls_5$0) in -- #296 +//│ let* (x$57) = foldr(f_5$0,i_1$0,x$55) in -- #295 +//│ let x$58 = Callable.apply2(f_5$0,x$56,x$57) in -- #294 +//│ jump j$4(x$58) -- #293 +//│ Nil => +//│ jump j$4(i_1$0) -- #299 +//│ def j$4(x$54) = +//│ x$54 -- #270 +//│ def zip(xs$0,ys$0) = +//│ case xs$0 of -- #353 +//│ Cons => +//│ let x$60 = Cons.t(xs$0) in -- #349 +//│ let x$61 = Cons.h(xs$0) in -- #348 +//│ case ys$0 of -- #347 +//│ Cons => +//│ let x$63 = Cons.t(ys$0) in -- #343 +//│ let x$64 = Cons.h(ys$0) in -- #342 +//│ let x$65 = Tuple2(x$61,x$64) in -- #341 +//│ let* (x$66) = zip(x$60,x$63) in -- #340 +//│ let x$67 = Cons(x$65,x$66) in -- #339 +//│ jump j$6(x$67) -- #338 +//│ Nil => +//│ let x$68 = Nil() in -- #346 +//│ jump j$6(x$68) -- #345 +//│ Nil => +//│ let x$69 = Nil() in -- #352 +//│ jump j$5(x$69) -- #351 +//│ def j$5(x$59) = +//│ x$59 -- #302 +//│ def j$6(x$62) = +//│ jump j$5(x$62) -- #313 +//│ def zipWith(f_7$0,xs_4$0,ys_4$0) = +//│ case xs_4$0 of -- #409 +//│ Cons => +//│ let x$71 = Cons.t(xs_4$0) in -- #405 +//│ let x$72 = Cons.h(xs_4$0) in -- #404 +//│ case ys_4$0 of -- #403 +//│ Cons => +//│ let x$74 = Cons.t(ys_4$0) in -- #399 +//│ let x$75 = Cons.h(ys_4$0) in -- #398 +//│ let x$76 = Callable.apply2(f_7$0,x$72,x$75) in -- #397 +//│ let* (x$77) = zipWith(f_7$0,x$71,x$74) in -- #396 +//│ let x$78 = Cons(x$76,x$77) in -- #395 +//│ jump j$8(x$78) -- #394 +//│ Nil => +//│ let x$79 = Nil() in -- #402 +//│ jump j$8(x$79) -- #401 +//│ Nil => +//│ let x$80 = Nil() in -- #408 +//│ jump j$7(x$80) -- #407 +//│ def j$7(x$70) = +//│ x$70 -- #355 +//│ def j$8(x$73) = +//│ jump j$7(x$73) -- #366 +//│ def head(ls_7$0) = +//│ case ls_7$0 of -- #427 +//│ Cons => +//│ let x$82 = Cons.t(ls_7$0) in -- #423 +//│ let x$83 = Cons.h(ls_7$0) in -- #422 +//│ jump j$9(x$83) -- #421 +//│ Nil => +//│ let x$85 = Lambda$0() in -- #426 +//│ jump j$9(x$85) -- #425 +//│ def j$9(x$81) = +//│ x$81 -- #411 +//│ def tail(ls_9$0) = +//│ case ls_9$0 of -- #445 +//│ Cons => +//│ let x$87 = Cons.t(ls_9$0) in -- #441 +//│ let x$88 = Cons.h(ls_9$0) in -- #440 +//│ jump j$10(x$87) -- #439 +//│ Nil => +//│ let x$90 = Lambda$1() in -- #444 +//│ jump j$10(x$90) -- #443 +//│ def j$10(x$86) = +//│ x$86 -- #429 +//│ def enumFromTo(a$0,b$0) = +//│ let x$91 = <=(a$0,b$0) in -- #477 +//│ if x$91 -- #476 +//│ true => +//│ let x$93 = +(a$0,1) in -- #472 +//│ let* (x$94) = enumFromTo(x$93,b$0) in -- #471 +//│ let x$95 = Cons(a$0,x$94) in -- #470 +//│ jump j$11(x$95) -- #469 +//│ false => +//│ let x$96 = Nil() in -- #475 +//│ jump j$11(x$96) -- #474 +//│ def j$11(x$92) = +//│ x$92 -- #452 +//│ def enumFromThenTo(a_1$0,t_11$0,b_1$0) = +//│ let x$97 = <=(a_1$0,b_1$0) in -- #517 +//│ if x$97 -- #516 +//│ true => +//│ let x$99 = *(2,t_11$0) in -- #512 +//│ let x$100 = -(x$99,a_1$0) in -- #511 +//│ let* (x$101) = enumFromThenTo(t_11$0,x$100,b_1$0) in -- #510 +//│ let x$102 = Cons(a_1$0,x$101) in -- #509 +//│ jump j$12(x$102) -- #508 +//│ false => +//│ let x$103 = Nil() in -- #515 +//│ jump j$12(x$103) -- #514 +//│ def j$12(x$98) = +//│ x$98 -- #484 +//│ def take(n$0,ls_11$0) = +//│ let x$104 = >(n$0,0) in -- #566 +//│ if x$104 -- #565 +//│ true => +//│ case ls_11$0 of -- #561 +//│ Cons => +//│ let x$107 = Cons.t(ls_11$0) in -- #557 +//│ let x$108 = Cons.h(ls_11$0) in -- #556 +//│ let x$109 = -(n$0,1) in -- #555 +//│ let* (x$110) = take(x$109,x$107) in -- #554 +//│ let x$111 = Cons(x$108,x$110) in -- #553 +//│ jump j$14(x$111) -- #552 +//│ Nil => +//│ let x$112 = Nil() in -- #560 +//│ jump j$14(x$112) -- #559 +//│ false => +//│ let x$113 = Nil() in -- #564 +//│ jump j$13(x$113) -- #563 +//│ def j$13(x$105) = +//│ x$105 -- #524 +//│ def j$14(x$106) = +//│ jump j$13(x$106) -- #527 +//│ def length(ls_13$0) = +//│ case ls_13$0 of -- #593 +//│ Cons => +//│ let x$115 = Cons.t(ls_13$0) in -- #590 +//│ let x$116 = Cons.h(ls_13$0) in -- #589 +//│ let* (x$117) = length(x$115) in -- #588 +//│ let x$118 = +(1,x$117) in -- #587 +//│ jump j$15(x$118) -- #586 +//│ Nil => +//│ jump j$15(0) -- #592 +//│ def j$15(x$114) = +//│ x$114 -- #568 +//│ def mappend(xs_8$0,ys_8$0) = +//│ case xs_8$0 of -- #622 +//│ Cons => +//│ let x$120 = Cons.t(xs_8$0) in -- #619 +//│ let x$121 = Cons.h(xs_8$0) in -- #618 +//│ let* (x$122) = mappend(x$120,ys_8$0) in -- #617 +//│ let x$123 = Cons(x$121,x$122) in -- #616 +//│ jump j$16(x$123) -- #615 +//│ Nil => +//│ jump j$16(ys_8$0) -- #621 +//│ def j$16(x$119) = +//│ x$119 -- #595 +//│ def sum(ls_14$0) = +//│ let* (x$124) = sumAux(ls_14$0,0) in -- #629 +//│ x$124 -- #628 +//│ def sumAux(ls_15$0,a_4$0) = +//│ case ls_15$0 of -- #658 +//│ Nil => +//│ jump j$17(a_4$0) -- #633 +//│ Cons => +//│ let x$126 = Cons.t(ls_15$0) in -- #657 +//│ let x$127 = Cons.h(ls_15$0) in -- #656 +//│ let x$128 = +(a_4$0,x$127) in -- #655 +//│ let* (x$129) = sumAux(x$126,x$128) in -- #654 +//│ jump j$17(x$129) -- #653 +//│ def j$17(x$125) = +//│ x$125 -- #631 +//│ def atIndex(n_2$0,ls_16$0) = +//│ let x$130 = <(n_2$0,0) in -- #713 +//│ if x$130 -- #712 +//│ true => +//│ let x$133 = Lambda$2() in -- #668 +//│ jump j$18(x$133) -- #667 +//│ false => +//│ case ls_16$0 of -- #711 +//│ Cons => +//│ let x$135 = Cons.t(ls_16$0) in -- #707 +//│ let x$136 = Cons.h(ls_16$0) in -- #706 +//│ let x$137 = ==(n_2$0,0) in -- #705 +//│ if x$137 -- #704 +//│ true => +//│ jump j$20(x$136) -- #689 +//│ false => +//│ let x$139 = -(n_2$0,1) in -- #703 +//│ let* (x$140) = atIndex(x$139,x$135) in -- #702 +//│ jump j$20(x$140) -- #701 +//│ Nil => +//│ let x$142 = Lambda$3() in -- #710 +//│ jump j$19(x$142) -- #709 +//│ def j$18(x$131) = +//│ x$131 -- #665 +//│ def j$19(x$134) = +//│ jump j$18(x$134) -- #671 +//│ def j$20(x$138) = +//│ jump j$19(x$138) -- #687 +//│ def concat(lss$0) = +//│ case lss$0 of -- #741 +//│ Cons => +//│ let x$144 = Cons.t(lss$0) in -- #737 +//│ let x$145 = Cons.h(lss$0) in -- #736 +//│ let* (x$146) = concat(x$144) in -- #735 +//│ let* (x$147) = mappend(x$145,x$146) in -- #734 +//│ jump j$21(x$147) -- #733 +//│ Nil => +//│ let x$148 = Nil() in -- #740 +//│ jump j$21(x$148) -- #739 +//│ def j$21(x$143) = +//│ x$143 -- #715 +//│ def reverse(ls_18$0) = +//│ let x$149 = Nil() in -- #749 +//│ let* (x$150) = reverse_helper(ls_18$0,x$149) in -- #748 +//│ x$150 -- #747 +//│ def reverse_helper(ls_19$0,a_5$0) = +//│ case ls_19$0 of -- #778 +//│ Cons => +//│ let x$152 = Cons.t(ls_19$0) in -- #775 +//│ let x$153 = Cons.h(ls_19$0) in -- #774 +//│ let x$154 = Cons(x$153,a_5$0) in -- #773 +//│ let* (x$155) = reverse_helper(x$152,x$154) in -- #772 +//│ jump j$22(x$155) -- #771 +//│ Nil => +//│ jump j$22(a_5$0) -- #777 +//│ def j$22(x$151) = +//│ x$151 -- #751 +//│ def listcomp_fun1(ms$0,listcomp_fun_para$0) = +//│ case listcomp_fun_para$0 of -- #806 +//│ Cons => +//│ let x$157 = Cons.t(listcomp_fun_para$0) in -- #802 +//│ let x$158 = Cons.h(listcomp_fun_para$0) in -- #801 +//│ let* (x$159) = listcomp_fun2(ms$0,x$158,x$157,ms$0) in -- #800 +//│ jump j$23(x$159) -- #799 +//│ Nil => +//│ let x$160 = Nil() in -- #805 +//│ jump j$23(x$160) -- #804 +//│ def j$23(x$156) = +//│ x$156 -- #780 +//│ def listcomp_fun2(ms$1,listcomp_fun_ls_h_out$0,listcomp_fun_ls_t_out$0,listcomp_fun_para$1) = +//│ case listcomp_fun_para$1 of -- #851 +//│ Cons => +//│ let x$162 = Cons.t(listcomp_fun_para$1) in -- #842 +//│ let x$163 = Cons.h(listcomp_fun_para$1) in -- #841 +//│ let x$164 = Tuple2(listcomp_fun_ls_h_out$0,x$163) in -- #840 +//│ let* (x$165) = listcomp_fun2(ms$1,listcomp_fun_ls_h_out$0,listcomp_fun_ls_t_out$0,x$162) in -- #839 +//│ let x$166 = Cons(x$164,x$165) in -- #838 +//│ jump j$24(x$166) -- #837 +//│ Nil => +//│ let* (x$167) = listcomp_fun1(ms$1,listcomp_fun_ls_t_out$0) in -- #850 +//│ jump j$24(x$167) -- #849 +//│ def j$24(x$161) = +//│ x$161 -- #808 +//│ def test(test_arg1$0) = +//│ let* (x$168) = const5000() in -- #912 +//│ let* (x$169) = const5000() in -- #911 +//│ let* (x$170) = z_add(x$169,test_arg1$0) in -- #910 +//│ let* (x$171) = z_enumFromTo(x$168,x$170) in -- #909 +//│ let* (x$172) = const10000() in -- #908 +//│ let* (x$173) = const10000() in -- #907 +//│ let* (x$174) = z_add(x$173,test_arg1$0) in -- #906 +//│ let* (x$175) = z_enumFromTo(x$172,x$174) in -- #905 +//│ let x$178 = Lambda$4() in -- #904 +//│ let* (x$179) = listcomp_fun1(x$175,x$171) in -- #903 +//│ let* (x$180) = map(x$178,x$179) in -- #902 +//│ let x$183 = Lambda$5() in -- #901 +//│ let* (x$184) = map(x$183,x$180) in -- #900 +//│ let* (x$185) = max'(x$184) in -- #899 +//│ x$185 -- #898 +//│ def const10000() = +//│ let* (x$186) = z_of_int(10000) in -- #917 +//│ x$186 -- #916 +//│ def f1(f1_arg1$0) = +//│ case f1_arg1$0 of -- #946 +//│ Tuple2 => +//│ let x$188 = Tuple2.y(f1_arg1$0) in -- #945 +//│ let x$189 = Tuple2.x(f1_arg1$0) in -- #944 +//│ let* (x$190) = gcdE(x$189,x$188) in -- #943 +//│ let x$191 = Tuple3(x$189,x$188,x$190) in -- #942 +//│ jump j$25(x$191) -- #941 +//│ def j$25(x$187) = +//│ x$187 -- #919 +//│ def quotRem(quotRem_arg1$0,quotRem_arg2$0) = +//│ let* (x$192) = z_div(quotRem_arg1$0,quotRem_arg2$0) in -- #965 +//│ let* (x$193) = z_mod(quotRem_arg1$0,quotRem_arg2$0) in -- #964 +//│ let x$194 = Tuple2(x$192,x$193) in -- #963 +//│ x$194 -- #962 +//│ def max'(max'_arg1$0) = +//│ case max'_arg1$0 of -- #1028 +//│ Cons => +//│ let x$196 = Cons.t(max'_arg1$0) in -- #1027 +//│ let x$197 = Cons.h(max'_arg1$0) in -- #1026 +//│ case x$196 of -- #1025 +//│ Nil => +//│ jump j$27(x$197) -- #980 +//│ Cons => +//│ let x$199 = Cons.t(x$196) in -- #1024 +//│ let x$200 = Cons.h(x$196) in -- #1023 +//│ let* (x$201) = z_lt(x$197,x$200) in -- #1022 +//│ if x$201 -- #1021 +//│ true => +//│ let x$203 = Cons(x$200,x$199) in -- #1008 +//│ let* (x$204) = max'(x$203) in -- #1007 +//│ jump j$28(x$204) -- #1006 +//│ false => +//│ let x$205 = Cons(x$197,x$199) in -- #1020 +//│ let* (x$206) = max'(x$205) in -- #1019 +//│ jump j$28(x$206) -- #1018 +//│ def j$26(x$195) = +//│ x$195 -- #967 +//│ def j$27(x$198) = +//│ jump j$26(x$198) -- #978 +//│ def j$28(x$202) = +//│ jump j$27(x$202) -- #996 +//│ def g(g_arg1$0,g_arg2$0) = +//│ case g_arg1$0 of -- #1156 +//│ Tuple3 => +//│ let x$208 = Tuple3.z(g_arg1$0) in -- #1155 +//│ let x$209 = Tuple3.y(g_arg1$0) in -- #1154 +//│ let x$210 = Tuple3.x(g_arg1$0) in -- #1153 +//│ case g_arg2$0 of -- #1152 +//│ Tuple3 => +//│ let x$212 = Tuple3.z(g_arg2$0) in -- #1151 +//│ let x$213 = Tuple3.y(g_arg2$0) in -- #1150 +//│ let x$214 = Tuple3.x(g_arg2$0) in -- #1149 +//│ let* (x$215) = const0() in -- #1148 +//│ let* (x$216) = z_equal(x$212,x$215) in -- #1147 +//│ if x$216 -- #1146 +//│ true => +//│ let x$218 = Tuple3(x$208,x$210,x$209) in -- #1076 +//│ jump j$31(x$218) -- #1075 +//│ false => +//│ let* (x$219) = quotRem(x$208,x$212) in -- #1145 +//│ case x$219 of -- #1144 +//│ Tuple2 => +//│ let x$221 = Tuple2.y(x$219) in -- #1143 +//│ let x$222 = Tuple2.x(x$219) in -- #1142 +//│ let x$223 = Tuple3(x$214,x$213,x$212) in -- #1141 +//│ let* (x$224) = z_mul(x$222,x$214) in -- #1140 +//│ let* (x$225) = z_sub(x$210,x$224) in -- #1139 +//│ let* (x$226) = z_mul(x$222,x$213) in -- #1138 +//│ let* (x$227) = z_sub(x$209,x$226) in -- #1137 +//│ let x$228 = Tuple3(x$225,x$227,x$221) in -- #1136 +//│ let* (x$229) = g(x$223,x$228) in -- #1135 +//│ jump j$32(x$229) -- #1134 +//│ def j$29(x$207) = +//│ x$207 -- #1030 +//│ def j$30(x$211) = +//│ jump j$29(x$211) -- #1045 +//│ def j$31(x$217) = +//│ jump j$30(x$217) -- #1066 +//│ def j$32(x$220) = +//│ jump j$31(x$220) -- #1085 +//│ def abs(abs_arg1$0) = +//│ let* (x$230) = const0() in -- #1179 +//│ let* (x$231) = z_lt(abs_arg1$0,x$230) in -- #1178 +//│ if x$231 -- #1177 +//│ true => +//│ let* (x$233) = const0() in -- #1174 +//│ let* (x$234) = z_sub(x$233,abs_arg1$0) in -- #1173 +//│ jump j$33(x$234) -- #1172 +//│ false => +//│ jump j$33(abs_arg1$0) -- #1176 +//│ def j$33(x$232) = +//│ x$232 -- #1164 +//│ def f2(f2_arg1$0) = +//│ case f2_arg1$0 of -- #1234 +//│ Tuple3 => +//│ let x$236 = Tuple3.z(f2_arg1$0) in -- #1233 +//│ let x$237 = Tuple3.y(f2_arg1$0) in -- #1232 +//│ let x$238 = Tuple3.x(f2_arg1$0) in -- #1231 +//│ case x$236 of -- #1230 +//│ Tuple3 => +//│ let x$240 = Tuple3.z(x$236) in -- #1229 +//│ let x$241 = Tuple3.y(x$236) in -- #1228 +//│ let x$242 = Tuple3.x(x$236) in -- #1227 +//│ let* (x$243) = z_add(x$242,x$241) in -- #1226 +//│ let* (x$244) = z_add(x$243,x$240) in -- #1225 +//│ let* (x$245) = abs(x$244) in -- #1224 +//│ jump j$35(x$245) -- #1223 +//│ def j$34(x$235) = +//│ x$235 -- #1181 +//│ def j$35(x$239) = +//│ jump j$34(x$239) -- #1196 +//│ def const0() = +//│ let* (x$246) = z_of_int(0) in -- #1239 +//│ x$246 -- #1238 +//│ def gcdE(gcdE_arg1$0,gcdE_arg2$0) = +//│ let* (x$247) = const0() in -- #1296 +//│ let* (x$248) = z_equal(gcdE_arg1$0,x$247) in -- #1295 +//│ if x$248 -- #1294 +//│ true => +//│ let* (x$250) = const0() in -- #1261 +//│ let* (x$251) = const1() in -- #1260 +//│ let x$252 = Tuple3(gcdE_arg2$0,x$250,x$251) in -- #1259 +//│ jump j$36(x$252) -- #1258 +//│ false => +//│ let* (x$253) = const1() in -- #1293 +//│ let* (x$254) = const0() in -- #1292 +//│ let x$255 = Tuple3(x$253,x$254,gcdE_arg1$0) in -- #1291 +//│ let* (x$256) = const0() in -- #1290 +//│ let* (x$257) = const1() in -- #1289 +//│ let x$258 = Tuple3(x$256,x$257,gcdE_arg2$0) in -- #1288 +//│ let* (x$259) = g(x$255,x$258) in -- #1287 +//│ jump j$36(x$259) -- #1286 +//│ def j$36(x$249) = +//│ x$249 -- #1247 +//│ def const1() = +//│ let* (x$260) = z_of_int(1) in -- #1301 +//│ x$260 -- #1300 +//│ def const5000() = +//│ let* (x$261) = z_of_int(5000) in -- #1306 +//│ x$261 -- #1305 +//│ def testGcd_nofib(testGcd_nofib_arg1$0) = +//│ let* (x$262) = test(testGcd_nofib_arg1$0) in -- #1311 +//│ x$262 -- #1310 +//│ def z_enumFromTo(z_enumFromTo_arg1$0,z_enumFromTo_arg2$0) = +//│ let* (x$263) = z_leq(z_enumFromTo_arg1$0,z_enumFromTo_arg2$0) in -- #1345 +//│ if x$263 -- #1344 +//│ true => +//│ let* (x$265) = const1() in -- #1340 +//│ let* (x$266) = z_add(z_enumFromTo_arg1$0,x$265) in -- #1339 +//│ let* (x$267) = z_enumFromTo(x$266,z_enumFromTo_arg2$0) in -- #1338 +//│ let x$268 = Cons(z_enumFromTo_arg1$0,x$267) in -- #1337 +//│ jump j$37(x$268) -- #1336 +//│ false => +//│ let x$269 = Nil() in -- #1343 +//│ jump j$37(x$269) -- #1342 +//│ def j$37(x$264) = +//│ x$264 -- #1318 +//│ let* (x$0) = z_of_int(400) in -- #8 +//│ let* (x$1) = testGcd_nofib(x$0) in -- #7 +//│ x$1 -- #6 +//│ +//│ +//│ Execution succeeded: +//│ Z(5201) +//│ diff --git a/compiler/shared/test/scala/mlscript/compiler/Test.scala b/compiler/shared/test/scala/mlscript/compiler/Test.scala index 752dc909e2..343de6b9f9 100644 --- a/compiler/shared/test/scala/mlscript/compiler/Test.scala +++ b/compiler/shared/test/scala/mlscript/compiler/Test.scala @@ -1,7 +1,7 @@ package mlscript package compiler -import utils.shorthands.* +import mlscript.utils.shorthands._ import scala.util.control.NonFatal import scala.collection.mutable.StringBuilder import mlscript.compiler.TreeDebug diff --git a/compiler/shared/test/scala/mlscript/compiler/TestIR.scala b/compiler/shared/test/scala/mlscript/compiler/TestIR.scala index 565769be1d..29f74f715c 100644 --- a/compiler/shared/test/scala/mlscript/compiler/TestIR.scala +++ b/compiler/shared/test/scala/mlscript/compiler/TestIR.scala @@ -1,63 +1,83 @@ -package mlscript -package compiler +package mlscript.compiler + import mlscript.utils.shorthands._ import mlscript.compiler.ir._ -import scala.collection.mutable.StringBuilder +import scala.collection.mutable.{ListBuffer, StringBuilder} +import mlscript.Statement +import mlscript.{DiffTests, ModeType, TypingUnit} +import mlscript.compiler.ir.{Fresh, FreshInt, Builder} +import mlscript.compiler.codegen.cpp._ +import mlscript.Diagnostic import mlscript.compiler.optimizer.TailRecOpt import IRDiffTestCompiler.* class IRDiffTestCompiler extends DiffTests(State) { + def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) = { + val p = new java.io.PrintWriter(f) + try { op(p) } finally { p.close() } + } + + val preludeSource = ListBuffer[Statement]() - override def postProcess(mode: ModeType, basePath: List[Str], testName: Str, unit: TypingUnit, output: Str => Unit, raise: Diagnostic => Unit): (List[Str], Option[TypingUnit]) = + override def postProcess(mode: ModeType, basePath: List[Str], testName: Str, originalUnit: TypingUnit, output: Str => Unit, raise: Diagnostic => Unit): (List[Str], Option[TypingUnit]) = val outputBuilder = StringBuilder() - if (mode.useIR || mode.irVerbose) + if (mode.prelude) + preludeSource.addAll(originalUnit.rawEntities) + output("\nPreluded.") + else if (mode.useIR || mode.irVerbose) try - val fnUid = FreshInt() - val classUid = FreshInt() - val tag = FreshInt() - - val gb = Builder(Fresh(), fnUid, classUid, tag, raise) - val graph_ = gb.buildGraph(unit) - - if !mode.noTailRecOpt then - output("\nIR:") - output(graph_.toString()) - - val graph = - if !mode.noTailRecOpt then - val tailRecOpt = new TailRecOpt(fnUid, classUid, tag, raise) - val (g, comps) = tailRecOpt.run_debug(graph_) - output("\nStrongly Connected Tail Calls:") - output(comps.toString) - g - else - graph_ + val (fresh, freshFnId, freshClassId, freshTag) = (Fresh(), FreshInt(), FreshInt(), FreshInt()) + val gb = Builder(fresh, freshFnId, freshClassId, freshTag, raise, mode.irVerbose) + val prelude = TypingUnit(preludeSource.toList) + var graph = gb.buildGraph(prelude, originalUnit) + val hiddenNames = gb.getHiddenNames(prelude) + output("\n\nIR:") + output(graph.show(hiddenNames)) if !mode.noTailRecOpt then - output(graph.toString()) - - output("\nPromoted:") - output(graph.toString()) + val tailRecOpt = new TailRecOpt(freshFnId, freshClassId, freshTag, raise) + val (g, comps) = tailRecOpt.run_debug(graph) + output("\n\nStrongly Connected Tail Calls:") + output(comps.toString) + graph = g + output(graph.show(hiddenNames)) var interp_result: Opt[Str] = None if (mode.interpIR) output("\nInterpreted:") val ir = Interpreter(mode.irVerbose).interpret(graph) interp_result = Some(ir) output(ir) - + if (mode.genCpp) + val cpp = codegen(graph) + if (mode.showCpp) + output("\nCpp:") + if (mode.irVerbose) + output(cpp.toDocument.print) + else + output(cpp.toDocumentWithoutHidden.print) + if (mode.writeCpp) + printToFile(java.io.File(s"compiler/shared/test/diff-ir/cpp/${testName}.cpp")) { p => + p.println(cpp.toDocument.print) + } + if (mode.runCpp) + val auxPath = os.pwd/"compiler"/"shared"/"test"/"diff-ir"/"cpp" + val cppHost = CppCompilerHost(auxPath.toString) + if !cppHost.ready then + output("\nCpp Compilation Failed: Cpp compiler or GNU Make not found") + else + output("\n") + cppHost.compileAndRun(cpp.toDocument.print, output) catch case err: Exception => output(s"\nIR Processing Failed: ${err.getMessage()}") - if (mode.irVerbose) then - output("\n" ++ err.getStackTrace().map(_.toString()).mkString("\n")) + output("\n" ++ err.getStackTrace().mkString("\n")) case err: StackOverflowError => output(s"\nIR Processing Failed: ${err.getMessage()}") - if (mode.irVerbose) then - output("\n" ++ err.getStackTrace().map(_.toString()).mkString("\n")) + output("\n" ++ err.getStackTrace().mkString("\n")) - (outputBuilder.toString().linesIterator.toList, None) + (outputBuilder.toString.linesIterator.toList, None) } diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000000..f4f8a7fafc --- /dev/null +++ b/flake.lock @@ -0,0 +1,97 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1723256269, + "narHash": "sha256-9jxxtPKq4n+F8+BPt706gtbdpDt8+DtmY8oDMi9Vh9Q=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "36d2587498cbb61b129149fb9050361d73e1f7c4", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "sbt-deriv": "sbt-deriv" + } + }, + "sbt-deriv": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1698464090, + "narHash": "sha256-Pnej7WZIPomYWg8f/CZ65sfW85IfIUjYhphMMg7/LT0=", + "owner": "zaninime", + "repo": "sbt-derivation", + "rev": "6762cf2c31de50efd9ff905cbcc87239995a4ef9", + "type": "github" + }, + "original": { + "owner": "zaninime", + "repo": "sbt-derivation", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000000..5619a8410d --- /dev/null +++ b/flake.nix @@ -0,0 +1,34 @@ +{ + description = "mlscript"; + + inputs.nixpkgs.url = "github:NixOS/nixpkgs"; + inputs.flake-utils.url = "github:numtide/flake-utils"; + inputs.sbt-deriv.url = "github:zaninime/sbt-derivation"; + inputs.sbt-deriv.inputs.nixpkgs.follows = "nixpkgs"; + + outputs = { self, nixpkgs, flake-utils, sbt-deriv }: + flake-utils.lib.eachDefaultSystem + (system: + let + sbtOverlay = self: super: { + sbt = super.sbt.override { jre = super.jdk8_headless; }; + }; + pkgs = import nixpkgs { + inherit system; + overlays = [ sbtOverlay ]; + }; + in with pkgs; { + devShells.default = mkShell { + buildInputs = [ + clang + gcc + gnumake + boost + gmp + mimalloc + sbt + nodejs_22 + ]; + }; + }); +} \ No newline at end of file diff --git a/project/build.properties b/project/build.properties index e8a1e246e8..ee4c672cd0 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.9.7 +sbt.version=1.10.1 diff --git a/project/plugins.sbt b/project/plugins.sbt index 3d01a25463..6012dc30ef 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,3 @@ -addSbtPlugin("org.wartremover" % "sbt-wartremover" % "3.1.5") -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.11.0") +addSbtPlugin("org.wartremover" % "sbt-wartremover" % "3.2.0") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.2.0") diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 0c6bc7d8e7..a42ffb7cad 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -161,6 +161,60 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { } } + final + def char(i: Int): (Char, Int) = { + if (i < length) { + bytes(i) match { + case '\\' => { + val j = i + 1 + if (j < length) + bytes(j) match { + case 'n' => ('\n', j + 1) + case 't' => ('\t', j + 1) + case 'r' => ('\r', j + 1) + case 'b' => ('\b', j + 1) + case 'f' => ('\f', j + 1) + case '\'' => ('\'', j + 1) + case '"' => ('"', j + 1) + case '\\' => ('\\', j + 1) + case ch => + raise(ErrorReport(msg"Invalid escape character" -> S(loc(j, j + 1)) :: Nil, + newDefs = true, source = Lexing)) + ('\u0000', j + 1) + } + else { + raise(ErrorReport(msg"Expect an escape character" -> S(loc(i, i + 1)) :: Nil, + newDefs = true, source = Lexing)) + ('\u0000', i + 1) + } + } + case '\n' | '\r' => + raise(ErrorReport(msg"Unexpected newline in a char literal" -> S(loc(i, i + 1)) :: Nil, + newDefs = true, source = Lexing)) + ('\u0000', i + 1) + case '\"' => + raise(ErrorReport(msg"Empty character literal" -> S(loc(i, i + 1)) :: Nil, + newDefs = true, source = Lexing)) + ('\u0000', i + 1) + case ch => + (ch, i + 1) + } + } + else { + raise(ErrorReport(msg"Expect a character literal" -> S(loc(i, i + 1)) :: Nil, + newDefs = true, source = Lexing)) + ('\u0000', i) + } + } + + final def closeChar(i: Int): Int = + if (bytes.lift(i) === Some('\"')) i + 1 + else { + raise(ErrorReport(msg"Unclosed character literal" -> S(loc(i, i + 1)) :: Nil, + newDefs = true, source = Lexing)) + i + } + // * Check the end of a string (either single quotation or triple quotation) final def closeStr(i: Int, isTriple: Bool): Int = if (!isTriple && bytes.lift(i) === Some('"')) i + 1 diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 8fb9ad1c2e..5e3076d28f 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -43,12 +43,17 @@ abstract class ModeType { def showRepl: Bool def allowEscape: Bool def useIR: Bool - def noTailRecOpt: Bool def interpIR: Bool def irVerbose: Bool + def genCpp: Bool + def showCpp: Bool + def runCpp: Bool + def writeCpp: Bool + def noTailRecOpt: Bool def simpledef: Bool def lift: Bool def nolift: Bool + def prelude: Bool } class DiffTests(state: DiffTests.State) @@ -185,10 +190,17 @@ class DiffTests(state: DiffTests.State) lift: Bool = false, nolift: Bool = false, // noProvs: Bool = false, - noTailRecOpt: Bool = false, useIR: Bool = false, interpIR: Bool = false, irVerbose: Bool = false, + irOpt: Bool = false, + irOptFuel: Int = 10, + genCpp: Bool = false, + showCpp: Bool = false, + runCpp: Bool = false, + writeCpp: Bool = false, + noTailRecOpt: Bool = false, + prelude: Bool = false, ) extends ModeType { def isDebugging: Bool = dbg || dbgSimplif } @@ -319,6 +331,11 @@ class DiffTests(state: DiffTests.State) case "useIR" => mode.copy(useIR = true) case "interpIR" => mode.copy(interpIR = true) case "irVerbose" => mode.copy(irVerbose = true) + case "genCpp" => mode.copy(genCpp = true) + case "showCpp" => mode.copy(showCpp = true) + case "runCpp" => mode.copy(runCpp = true) + case "writeCpp" => mode.copy(writeCpp = true) + case "prelude" => mode.copy(prelude = true) case _ => failures += allLines.size - lines.size output("/!\\ Unrecognized option " + line) @@ -485,13 +502,13 @@ class DiffTests(state: DiffTests.State) if (mode.showParse) output(s"AST: $res") + val newMode = if (useIR) { mode.copy(useIR = true) } else mode val newNewMode = if (noTailRec) { newMode.copy(noTailRecOpt = true) } else newMode - val (postLines, nuRes) = - postProcess(newNewMode, basePath, testName, res, output, raise) - postLines.foreach(output) - + val (postLines, nuRes) = postProcess(newNewMode, basePath, testName, res, output, raise) + postLines.foreach(output) + if (parseOnly) Success(Pgrm(Nil), 0) else if (mode.lift) {