├── lingua-000-tiger ├── .gitignore ├── 02-lexical-analysis │ ├── .gitignore │ ├── sources.cm │ ├── test1.tig │ ├── driver.sml │ ├── Lexer.sml │ ├── merge.tig │ └── token.sig ├── tiger │ ├── frame.sml │ ├── parse.sml │ ├── semant.sig │ ├── tree-printer.sig │ ├── syntax.sig │ ├── make-graph.sig │ ├── codegen.sig │ ├── free-var-analysis.sig │ ├── escape-analysis.sig │ ├── temp.sig │ ├── reg-alloc.sig │ ├── flow.sml │ ├── showast.sig │ ├── liveness-analysis.sig │ ├── symbol.sig │ ├── color.sig │ ├── env.sig │ ├── temp.sml │ ├── graph.sig │ ├── tree.sig │ ├── symbol.sml │ ├── sources.cm │ ├── syntax.sml │ ├── tree.sml │ ├── main.sml │ ├── types.sml │ ├── mips-register.sml │ ├── topo-sort.sml │ ├── translate.sig │ ├── canon.sig │ ├── env.sml │ ├── assem.sml │ ├── ast.sml │ ├── frame.sig │ ├── escape-analysis.sml │ └── graph.sml └── 01-introduction │ ├── lingua-000.mlb │ ├── sources.cm │ ├── main-mlton.sml │ ├── main-smlnj.sml │ ├── lang.sml │ ├── readme.md │ ├── Makefile │ ├── tree.sml │ └── lingua.sml ├── lingua-004-lisp-parser ├── .gitignore ├── project │ └── build.properties ├── src │ ├── test │ │ └── scala │ │ │ ├── package.scala │ │ │ └── ReaderTest.scala │ └── main │ │ └── scala │ │ └── main.scala ├── readme.md └── build.sbt ├── lingua-007-µml-swift ├── .gitignore ├── SwiftML.xcodeproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── SwiftML │ ├── main.swift │ ├── type.swift │ ├── type-error.swift │ ├── elaborator.swift │ ├── unifier.swift │ ├── value.swift │ ├── dictionary.swift │ ├── result.swift │ ├── stdlib.swift │ ├── substitution.swift │ ├── repl.swift │ └── annotate.swift └── readme.md ├── lingua-009-shunting-yard ├── .gitignore ├── project │ ├── build.properties │ └── build.sbt ├── docs │ ├── shunting-yard.png │ └── ALGOL-60 Translation.pdf ├── src │ ├── main │ │ └── scala │ │ │ └── linguae │ │ │ ├── ExprParser.scala │ │ │ ├── Fixity.scala │ │ │ ├── Expr.scala │ │ │ ├── Token.scala │ │ │ ├── Main.scala │ │ │ ├── ImperativeShuntingYardParser.scala │ │ │ └── FunctionalShuntingYardParser.scala │ └── test │ │ └── scala │ │ └── linguae │ │ └── test │ │ ├── FunctionalShuntingYardParserSuite.scala │ │ ├── ImperativeShuntingYardParserSuite.scala │ │ └── ExprParserSuite.scala ├── readme.md ├── build.sbt └── .scalafmt.conf ├── lingua-001-visitor-interpreter ├── .gitignore ├── project │ ├── build.properties │ ├── plugins.sbt │ └── build.scala ├── readme.md └── src │ ├── main │ └── scala │ │ ├── package.scala │ │ ├── Node.scala │ │ ├── nodes │ │ ├── Num.scala │ │ ├── Bool.scala │ │ ├── Ref.scala │ │ ├── Add.scala │ │ ├── Div.scala │ │ ├── Mul.scala │ │ ├── Seq.scala │ │ ├── Sub.scala │ │ ├── App.scala │ │ ├── Equal.scala │ │ ├── Fun.scala │ │ ├── Set.scala │ │ ├── When.scala │ │ └── Let.scala │ │ ├── NodeVisitor.scala │ │ ├── Lingua001.scala │ │ └── visitors │ │ └── DecoratedVisitor.scala │ └── test │ ├── scala │ ├── package.scala │ ├── logback.scala │ └── JsCompilerTest.scala │ └── resources │ └── logback-test.xml ├── lingua-003-tree-interpreter ├── .gitignore ├── project │ ├── build.properties │ └── build.sbt ├── src │ ├── main │ │ └── scala │ │ │ ├── Evaluation.scala │ │ │ ├── Main.scala │ │ │ ├── Value.scala │ │ │ ├── Environment.scala │ │ │ ├── Result.scala │ │ │ ├── Node.scala │ │ │ └── Store.scala │ └── test │ │ └── scala │ │ └── package.scala ├── build.sbt └── readme.md ├── lingua-005-debugger-scalajs ├── .gitignore ├── project │ ├── build.properties │ └── build.sbt ├── src │ ├── main │ │ ├── scala │ │ │ ├── display │ │ │ │ └── package.scala │ │ │ ├── eval │ │ │ │ ├── package.scala │ │ │ │ ├── Value.scala │ │ │ │ ├── Resumption.scala │ │ │ │ └── Env.scala │ │ │ ├── package.scala │ │ │ ├── typer │ │ │ │ ├── Constraint.scala │ │ │ │ ├── TypeEnv.scala │ │ │ │ ├── Substitution.scala │ │ │ │ ├── TypeScheme.scala │ │ │ │ └── Type.scala │ │ │ └── syntax │ │ │ │ └── Term.scala │ │ └── resources │ │ │ ├── index.html │ │ │ └── css │ │ │ └── main.css │ └── test │ │ └── scala │ │ └── MainTest.scala ├── doc │ ├── debugger.gif │ ├── wip-01.png │ ├── wip-02.png │ └── wip-03.png └── readme.md ├── lingua-006-hm-inference-scala ├── .gitignore ├── project │ ├── build.properties │ └── build.sbt ├── readme.md ├── src │ ├── test │ │ └── scala │ │ │ ├── Test.scala │ │ │ ├── UnifierTest.scala │ │ │ ├── SubstitutionTest.scala │ │ │ ├── InferTest.scala │ │ │ └── parser │ │ │ ├── ScannerTest.scala │ │ │ └── ParserTest.scala │ └── main │ │ └── scala │ │ ├── TypeEnv.scala │ │ ├── Infer.scala │ │ ├── Type.scala │ │ ├── Main.scala │ │ ├── Term.scala │ │ ├── TypedTerm.scala │ │ ├── Constraint.scala │ │ ├── signature │ │ └── Signature.scala │ │ ├── Substitution.scala │ │ ├── Annotate.scala │ │ └── Unifier.scala └── build.sbt ├── lingua-008-partial-evaluation ├── .gitignore ├── project │ ├── build.properties │ └── build.sbt ├── src │ ├── test │ │ ├── resources │ │ │ └── peval │ │ │ │ └── test │ │ │ │ └── data │ │ │ │ ├── test.leesp │ │ │ │ └── exp.leesp │ │ └── scala │ │ │ └── peval │ │ │ └── test │ │ │ ├── BetterSpecializerSuite.scala │ │ │ ├── NaiveSpecializerSuite.scala │ │ │ └── ReaderSuite.scala │ └── main │ │ ├── resources │ │ └── leesp │ │ │ ├── exp.leesp │ │ │ └── mix.leesp │ │ └── scala │ │ └── peval │ │ ├── Main.scala │ │ ├── Parser.scala │ │ ├── NaiveSpecializer.scala │ │ ├── Reader.scala │ │ └── syntax.scala ├── readme.md └── .scalafmt.conf ├── lingua-002-hm-inference-sml ├── .gitignore ├── src │ ├── smlnj │ │ └── main.sml │ ├── type-env.sml │ ├── mlton │ │ └── main.sml │ ├── subst.sig │ ├── type-env.sig │ ├── term.sml │ ├── subst.sml │ ├── basis │ │ ├── show.sig │ │ ├── show.sml │ │ ├── list.sml │ │ └── tuples.sml │ ├── type.sml │ ├── type-env.fun │ ├── constraint.sml │ ├── infer.sml │ └── terms.sml ├── sources.mlb ├── sources.cm └── readme.md ├── lingua-010-jit-hello-world-apple-silicon ├── .gitignore ├── Makefile ├── readme.md └── jitted.c ├── lingua-011-bidirectional-typechecking ├── .gitignore ├── project │ ├── build.properties │ └── build.sbt ├── screenshot.png ├── doc │ └── Bidirectional Typing Rules — A Tutorial.pdf ├── src │ ├── test │ │ └── scala │ │ │ └── linguae │ │ │ └── test │ │ │ └── MainSuite.scala │ └── main │ │ └── scala │ │ └── linguae │ │ └── Color.scala ├── readme.md ├── build.sbt └── .scalafmt.conf ├── lingua-014-simple-bytecode-vm ├── .gitignore ├── .envrc.sample └── lib.cm ├── lingua-013-pattern-match-compiler ├── .gitignore ├── .envrc.sample ├── doc │ └── ml-pattern-match-compilation-and-partial-evaluation.pdf ├── lib.cm ├── src │ ├── common.sml │ └── naive-matcher.sml └── readme.md └── lingua-012-chatgpt-c++-compiler ├── .gitignore ├── print_int.c ├── chats ├── session-00.pdf └── session-01.pdf ├── Makefile └── readme.md /lingua-000-tiger/.gitignore: -------------------------------------------------------------------------------- 1 | .cm/ 2 | build/ 3 | -------------------------------------------------------------------------------- /lingua-004-lisp-parser/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/.gitignore: -------------------------------------------------------------------------------- 1 | xcuserdata 2 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /lingua-003-tree-interpreter/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/.gitignore: -------------------------------------------------------------------------------- 1 | .cm/ 2 | infer 3 | -------------------------------------------------------------------------------- /lingua-010-jit-hello-world-apple-silicon/.gitignore: -------------------------------------------------------------------------------- 1 | jitted 2 | -------------------------------------------------------------------------------- /lingua-011-bidirectional-typechecking/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /lingua-014-simple-bytecode-vm/.gitignore: -------------------------------------------------------------------------------- 1 | .cm/ 2 | .rlwrap/ 3 | -------------------------------------------------------------------------------- /lingua-000-tiger/02-lexical-analysis/.gitignore: -------------------------------------------------------------------------------- 1 | tiger.lex.sml 2 | -------------------------------------------------------------------------------- /lingua-013-pattern-match-compiler/.gitignore: -------------------------------------------------------------------------------- 1 | .cm/ 2 | .rlwrap/ 3 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/frame.sml: -------------------------------------------------------------------------------- 1 | structure Frame :> FRAME = MipsFrame 2 | -------------------------------------------------------------------------------- /lingua-004-lisp-parser/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.7 2 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.6.2 2 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.5 2 | -------------------------------------------------------------------------------- /lingua-003-tree-interpreter/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.7 2 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.6.2 2 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.13 2 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.6.2 2 | -------------------------------------------------------------------------------- /lingua-003-tree-interpreter/project/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions += "-deprecation" 2 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/project/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions += "-deprecation" 2 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/project/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions += "-deprecation" 2 | -------------------------------------------------------------------------------- /lingua-011-bidirectional-typechecking/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.0 2 | -------------------------------------------------------------------------------- /lingua-011-bidirectional-typechecking/project/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions += "-deprecation" 2 | -------------------------------------------------------------------------------- /lingua-012-chatgpt-c++-compiler/.gitignore: -------------------------------------------------------------------------------- 1 | .build/ 2 | *.[o,s] 3 | *.dot 4 | *.pdf 5 | program 6 | !chats/** 7 | -------------------------------------------------------------------------------- /lingua-013-pattern-match-compiler/.envrc.sample: -------------------------------------------------------------------------------- 1 | export RLWRAP_HOME="$PWD/.rlwrap" 2 | export CM_VERBOSE=false 3 | -------------------------------------------------------------------------------- /lingua-014-simple-bytecode-vm/.envrc.sample: -------------------------------------------------------------------------------- 1 | export RLWRAP_HOME="$PWD/.rlwrap" 2 | export CM_VERBOSE=false 3 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/src/test/resources/peval/test/data/test.leesp: -------------------------------------------------------------------------------- 1 | ;; comments are allowed 2 | [atom [atom]] 3 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/parse.sml: -------------------------------------------------------------------------------- 1 | structure Parse = 2 | struct 3 | fun parse file = raise Fail "not implemented" 4 | end 5 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/main/scala/display/package.scala: -------------------------------------------------------------------------------- 1 | package ro.igstan.debugger 2 | 3 | package object display 4 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/semant.sig: -------------------------------------------------------------------------------- 1 | signature SEMANT = 2 | sig 3 | val translateProgram : Ast.exp -> Translate.frag list 4 | end 5 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/tree-printer.sig: -------------------------------------------------------------------------------- 1 | signature TREE_PRINTER = 2 | sig 3 | val print : TextIO.outstream * Tree.stm -> unit 4 | end 5 | -------------------------------------------------------------------------------- /lingua-003-tree-interpreter/src/main/scala/Evaluation.scala: -------------------------------------------------------------------------------- 1 | package toy 2 | 3 | case class Evaluation(value: Value, store: Store) 4 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/doc/debugger.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igstan/linguae/HEAD/lingua-005-debugger-scalajs/doc/debugger.gif -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/doc/wip-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igstan/linguae/HEAD/lingua-005-debugger-scalajs/doc/wip-01.png -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/doc/wip-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igstan/linguae/HEAD/lingua-005-debugger-scalajs/doc/wip-02.png -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/doc/wip-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igstan/linguae/HEAD/lingua-005-debugger-scalajs/doc/wip-03.png -------------------------------------------------------------------------------- /lingua-012-chatgpt-c++-compiler/print_int.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void print_int(long x0) { 4 | printf("%ld\n", x0); 5 | } 6 | -------------------------------------------------------------------------------- /lingua-000-tiger/01-introduction/lingua-000.mlb: -------------------------------------------------------------------------------- 1 | $(SML_LIB)/basis/basis.mlb 2 | 3 | lang.sml 4 | tree.sml 5 | lingua.sml 6 | main-mlton.sml 7 | -------------------------------------------------------------------------------- /lingua-000-tiger/01-introduction/sources.cm: -------------------------------------------------------------------------------- 1 | Group is 2 | 3 | $/basis.cm 4 | 5 | lang.sml 6 | tree.sml 7 | lingua.sml 8 | main-smlnj.sml 9 | -------------------------------------------------------------------------------- /lingua-000-tiger/01-introduction/main-mlton.sml: -------------------------------------------------------------------------------- 1 | val main: unit -> unit = 2 | fn () => Lingua.interp Lingua.prog 3 | 4 | val _ = Tree.main () 5 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/readme.md: -------------------------------------------------------------------------------- 1 | # Lingua 001 2 | 3 | A small interpreter that uses the visitor pattern instead of pattern matching. 4 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/project/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions += "-deprecation" 2 | 3 | addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.9.0") 4 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/docs/shunting-yard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igstan/linguae/HEAD/lingua-009-shunting-yard/docs/shunting-yard.png -------------------------------------------------------------------------------- /lingua-009-shunting-yard/project/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions += "-deprecation" 2 | 3 | addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6") 4 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/syntax.sig: -------------------------------------------------------------------------------- 1 | signature SYNTAX = 2 | sig 3 | val showOper : Ast.oper -> string 4 | val showType : Types.ty -> string 5 | end 6 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/docs/ALGOL-60 Translation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igstan/linguae/HEAD/lingua-009-shunting-yard/docs/ALGOL-60 Translation.pdf -------------------------------------------------------------------------------- /lingua-011-bidirectional-typechecking/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igstan/linguae/HEAD/lingua-011-bidirectional-typechecking/screenshot.png -------------------------------------------------------------------------------- /lingua-012-chatgpt-c++-compiler/chats/session-00.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igstan/linguae/HEAD/lingua-012-chatgpt-c++-compiler/chats/session-00.pdf -------------------------------------------------------------------------------- /lingua-012-chatgpt-c++-compiler/chats/session-01.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igstan/linguae/HEAD/lingua-012-chatgpt-c++-compiler/chats/session-01.pdf -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/make-graph.sig: -------------------------------------------------------------------------------- 1 | signature MAKE_GRAPH = 2 | sig 3 | val instrs2graph : Assem.instr list -> Flow.flowgraph * Flow.Graph.node list 4 | end 5 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/src/main/scala/linguae/ExprParser.scala: -------------------------------------------------------------------------------- 1 | package linguae 2 | 3 | trait ExprParser { 4 | def parse(tokens: List[Token]): Expr 5 | } 6 | -------------------------------------------------------------------------------- /lingua-010-jit-hello-world-apple-silicon/Makefile: -------------------------------------------------------------------------------- 1 | run: jitted 2 | @./jitted 3 | 4 | jitted: jitted.c 5 | gcc -o jitted jitted.c 6 | 7 | clean: 8 | rm jitted 9 | -------------------------------------------------------------------------------- /lingua-014-simple-bytecode-vm/lib.cm: -------------------------------------------------------------------------------- 1 | library (0.1.0) 2 | source (-) 3 | is 4 | $BUCHAREST-ML/sml-foundation/lib.cm 5 | 6 | src ( 7 | main.sml 8 | ) 9 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/codegen.sig: -------------------------------------------------------------------------------- 1 | signature CODEGEN = 2 | sig 3 | structure Frame : FRAME 4 | 5 | val codegen : Frame.frame -> Tree.stm -> Assem.instr list 6 | end 7 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/package.scala: -------------------------------------------------------------------------------- 1 | package object lingua001 { 2 | def logger(name: String) = org.slf4j.LoggerFactory.getLogger(name) 3 | } 4 | -------------------------------------------------------------------------------- /lingua-000-tiger/02-lexical-analysis/sources.cm: -------------------------------------------------------------------------------- 1 | Group is 2 | 3 | $/basis.cm 4 | 5 | driver.sml 6 | lexer.sml 7 | token.sig 8 | token.sml 9 | tiger.lex 10 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/smlnj/main.sml: -------------------------------------------------------------------------------- 1 | structure Main = 2 | struct 3 | fun main () = 4 | print (Infer.typeSignature Terms.compose Terms.predef ^ "\n") 5 | end 6 | -------------------------------------------------------------------------------- /lingua-003-tree-interpreter/src/main/scala/Main.scala: -------------------------------------------------------------------------------- 1 | package toy 2 | 3 | object Main { 4 | def main(args: Array[String]): Unit = { 5 | println("Hello, World!") 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.1.6") 2 | 3 | addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.4") 4 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/type-env.sml: -------------------------------------------------------------------------------- 1 | structure TypeEnv = TypeEnvFn ( 2 | structure TermMap = BinaryMapFn (Term.Var.Key) 3 | structure TypeSet = BinarySetFn (Type.Var.Key) 4 | ) 5 | -------------------------------------------------------------------------------- /lingua-004-lisp-parser/src/test/scala/package.scala: -------------------------------------------------------------------------------- 1 | package leesp 2 | 3 | package object test { 4 | type FunSuite = org.scalatest.FunSuite 5 | type Matchers = org.scalatest.Matchers 6 | } 7 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/readme.md: -------------------------------------------------------------------------------- 1 | # Partial Evaluator 2 | 3 | A basic partial evaluator following a [Tutorial on Online Partial Evaluation][0]. 4 | 5 | [0]: https://arxiv.org/abs/1109.0781 6 | -------------------------------------------------------------------------------- /lingua-000-tiger/01-introduction/main-smlnj.sml: -------------------------------------------------------------------------------- 1 | structure Main = 2 | struct 3 | fun main (name, args) = 4 | let 5 | val _ = Tree.main () 6 | in 7 | 0 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/Node.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | 3 | trait Node { 4 | def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S): (visitor.R, visitor.S) 5 | } 6 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/test/scala/package.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | 3 | package object test { 4 | type FunSuite = org.scalatest.FunSuite 5 | type Matchers = org.scalatest.Matchers 6 | } 7 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/readme.md: -------------------------------------------------------------------------------- 1 | # A Type Inferencer for ML in 200 Lines of Scala 2 | 3 | An implementation of Wand's type inference algorithm, in Scala, for a limited 4 | subset of Standard ML. 5 | -------------------------------------------------------------------------------- /lingua-004-lisp-parser/readme.md: -------------------------------------------------------------------------------- 1 | # Leesp 2 | 3 | A tiny parser for a LISP-like language. 4 | 5 | ### Running 6 | 7 | ``` 8 | $ sbt 9 | > run "(+ a b)" 10 | LIST(ATOM(+), ATOM(a), ATOM(b)) 11 | ``` 12 | -------------------------------------------------------------------------------- /lingua-011-bidirectional-typechecking/doc/Bidirectional Typing Rules — A Tutorial.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igstan/linguae/HEAD/lingua-011-bidirectional-typechecking/doc/Bidirectional Typing Rules — A Tutorial.pdf -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/main/scala/eval/package.scala: -------------------------------------------------------------------------------- 1 | package ro.igstan.debugger 2 | 3 | package object eval { 4 | type Result = Either[String, Value] 5 | type Kont = Resumption.Step => Resumption.Step 6 | } 7 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/test/scala/Test.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | package test 3 | 4 | import org.scalatest.{ FunSuite, Inside, Matchers } 5 | 6 | abstract class Test extends FunSuite with Matchers with Inside 7 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/mlton/main.sml: -------------------------------------------------------------------------------- 1 | structure Main = 2 | struct 3 | fun main args = 4 | print (Infer.typeSignature Terms.compose Terms.predef ^ "\n") 5 | end 6 | 7 | val _ = Main.main (CommandLine.arguments ()) 8 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/readme.md: -------------------------------------------------------------------------------- 1 | # Debugger 2 | 3 | ```bash 4 | $ sbt ~fastOptJS 5 | ``` 6 | 7 | Open `target/scala-2.13/classes/index.html` inside a browser. 8 | 9 | 10 | ![Debugger Screenshot](doc/debugger.gif) 11 | -------------------------------------------------------------------------------- /lingua-011-bidirectional-typechecking/src/test/scala/linguae/test/MainSuite.scala: -------------------------------------------------------------------------------- 1 | package linguae 2 | package test 3 | 4 | final class MainSuite extends munit.FunSuite { 5 | test("main") { 6 | assertEquals(1, 1) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lingua-013-pattern-match-compiler/doc/ml-pattern-match-compilation-and-partial-evaluation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igstan/linguae/HEAD/lingua-013-pattern-match-compiler/doc/ml-pattern-match-compilation-and-partial-evaluation.pdf -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/free-var-analysis.sig: -------------------------------------------------------------------------------- 1 | signature FREE_VAR_ANALYSIS = 2 | sig 3 | val analyseVar : Ast.var -> unit Symbol.table 4 | val analyseExp : Ast.exp -> unit Symbol.table 5 | val analyseDec : Ast.dec -> unit Symbol.table 6 | end 7 | -------------------------------------------------------------------------------- /lingua-003-tree-interpreter/src/main/scala/Value.scala: -------------------------------------------------------------------------------- 1 | package toy 2 | 3 | sealed trait Value 4 | 5 | object Value { 6 | case class Num(value: Int) extends Value 7 | case class Fun(param: String, body: Node, closure: Environment) extends Value 8 | } 9 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/SwiftML.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/escape-analysis.sig: -------------------------------------------------------------------------------- 1 | (** 2 | * Analyses the AST for identifiers accessed in nested functions and marks 3 | * them as such using the mutable `escape` fields. 4 | *) 5 | signature ESCAPE_ANALYSIS = 6 | sig 7 | val analyse : Ast.exp -> unit 8 | end 9 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/test/scala/MainTest.scala: -------------------------------------------------------------------------------- 1 | package ro.igstan.debugger 2 | package test 3 | 4 | import org.scalatest.funsuite.AnyFunSuite 5 | 6 | class MainTest extends AnyFunSuite { 7 | test("tests setup") { 8 | assert(true) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/temp.sig: -------------------------------------------------------------------------------- 1 | signature TEMP = 2 | sig 3 | eqtype temp 4 | val newTemp : unit -> temp 5 | val makeString : temp -> string 6 | 7 | type label = Symbol.symbol 8 | val newLabel : unit -> label 9 | val namedLabel : string -> label 10 | end 11 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/nodes/Num.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package nodes 3 | 4 | case class Num(n: Int) extends Node { 5 | override def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S) = { 6 | visitor.num(n, state) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lingua-000-tiger/02-lexical-analysis/test1.tig: -------------------------------------------------------------------------------- 1 | /* an array t/* ype an 2 | d an array */variable */ 3 | let 4 | type arrtype = array of int 5 | var arr1:arrtype := arrtype [10] of 0 6 | var s = "this is a \n string" 7 | in 8 | arr1 9 | end 10 | 11 | /* foo 12 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/nodes/Bool.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package nodes 3 | 4 | case class Bool(b: Boolean) extends Node { 5 | override def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S) = { 6 | visitor.bool(b, state) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/nodes/Ref.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package nodes 3 | 4 | case class Ref(id: String) extends Node { 5 | override def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S) = { 6 | visitor.ref(id, state) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/nodes/Add.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package nodes 3 | 4 | case class Add(a: Node, b: Node) extends Node { 5 | override def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S) = { 6 | visitor.add(a, b, state) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/nodes/Div.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package nodes 3 | 4 | case class Div(a: Node, b: Node) extends Node { 5 | override def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S) = { 6 | visitor.div(a, b, state) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/nodes/Mul.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package nodes 3 | 4 | case class Mul(a: Node, b: Node) extends Node { 5 | override def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S) = { 6 | visitor.mul(a, b, state) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/nodes/Seq.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package nodes 3 | 4 | case class Seq(a: Node, b: Node) extends Node { 5 | override def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S) = { 6 | visitor.seq(a, b, state) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/nodes/Sub.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package nodes 3 | 4 | case class Sub(a: Node, b: Node) extends Node { 5 | override def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S) = { 6 | visitor.sub(a, b, state) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/nodes/App.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package nodes 3 | 4 | case class App(fn: Node, arg: Node) extends Node { 5 | override def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S) = { 6 | visitor.app(fn, arg, state) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/nodes/Equal.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package nodes 3 | 4 | case class Equal(a: Node, b: Node) extends Node { 5 | override def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S) = { 6 | visitor.equal(a, b, state) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/nodes/Fun.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package nodes 3 | 4 | case class Fun(id: String, body: Node) extends Node { 5 | override def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S) = { 6 | visitor.fun(id, body, state) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/main/scala/package.scala: -------------------------------------------------------------------------------- 1 | package ro.igstan 2 | 3 | import scala.annotation.unused 4 | 5 | package object debugger { 6 | def ignore[A](@unused a: A): Unit = () 7 | 8 | implicit class Ignore[A](a: A) { 9 | def ignore(): Unit = () 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/nodes/Set.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package nodes 3 | 4 | case class Set(id: String, value: Node) extends Node { 5 | override def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S) = { 6 | visitor.set(id, value, state) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/src/test/scala/linguae/test/FunctionalShuntingYardParserSuite.scala: -------------------------------------------------------------------------------- 1 | package linguae 2 | package test 3 | 4 | final class FunctionalShuntingYardParserSuite extends ExprParserSuite { 5 | override def parser: ExprParser = 6 | FunctionalShuntingYardParser(operatorTable) 7 | } 8 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/src/test/scala/linguae/test/ImperativeShuntingYardParserSuite.scala: -------------------------------------------------------------------------------- 1 | package linguae 2 | package test 3 | 4 | final class ImperativeShuntingYardParserSuite extends ExprParserSuite { 5 | override def parser: ExprParser = 6 | ImperativeShuntingYardParser(operatorTable) 7 | } 8 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/nodes/When.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package nodes 3 | 4 | case class When(cond: Node, yes: Node, no: Node) extends Node { 5 | override def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S) = { 6 | visitor.when(cond, yes, no, state) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/src/test/resources/peval/test/data/exp.leesp: -------------------------------------------------------------------------------- 1 | [def factorial [n] 2 | [if [= n 0] 3 | 1 4 | [* n [factorial [- n 1]]]]] 5 | 6 | [def power [x n] 7 | [if [= n 0] 8 | 1 9 | [* x [power x [- n 1]]]]] 10 | 11 | [def main [] 12 | [power x [factorial 3]]] 13 | -------------------------------------------------------------------------------- /lingua-013-pattern-match-compiler/lib.cm: -------------------------------------------------------------------------------- 1 | library (0.1.0) 2 | source (-) 3 | library ($BUCHAREST-ML/sml-foundation/lib.cm) 4 | is 5 | $BUCHAREST-ML/sml-foundation/lib.cm 6 | 7 | src ( 8 | common.sml 9 | naive-matcher.sml 10 | instrumented-matcher.sml 11 | match-compiler.sml 12 | ) 13 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/reg-alloc.sig: -------------------------------------------------------------------------------- 1 | signature REG_ALLOC = 2 | sig 3 | structure Frame : FRAME 4 | structure TempMap : ORD_MAP where type Key.ord_key = Temp.temp 5 | 6 | type allocation = Frame.register TempMap.map 7 | 8 | val alloc : Assem.instr list * Frame.frame -> Assem.instr list * allocation 9 | end 10 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/SwiftML/main.swift: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------- // 2 | // SwiftML // 3 | // -------------------------------------------------------------------------- // 4 | 5 | repl(prompt: "SwiftML> ") 6 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/flow.sml: -------------------------------------------------------------------------------- 1 | structure Flow = 2 | struct 3 | structure Graph = Graph 4 | 5 | datatype flowgraph = 6 | FGRAPH of { 7 | control : Graph.graph, 8 | def : Graph.temp_set Graph.node_map, 9 | use : Graph.temp_set Graph.node_map, 10 | isMove : bool Graph.node_map 11 | } 12 | end 13 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/main/scala/TypeEnv.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | 3 | case class TypeEnv(bindings: Map[String, Type]) { 4 | def set(name: String, ty: Type): TypeEnv = { 5 | TypeEnv(bindings + (name -> ty)) 6 | } 7 | 8 | def get(name: String): Option[Type] = { 9 | bindings.get(name) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/subst.sig: -------------------------------------------------------------------------------- 1 | signature SUBST = 2 | sig 3 | type ty 4 | 5 | val empty : ty 6 | val fromList : (Type.Var.ty * Type.ty) list -> ty 7 | val set : ty -> Type.Var.ty -> Type.ty -> ty 8 | val apply : ty -> Type.ty -> Type.ty 9 | val compose : ty -> ty -> ty 10 | val toString : ty -> string 11 | end 12 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/src/main/resources/leesp/exp.leesp: -------------------------------------------------------------------------------- 1 | [def factorial [n] 2 | [if [= n 0] 3 | 1 4 | [* n [factorial [- n 1]]]]] 5 | 6 | [def power [x n] 7 | [if [= n 0] 8 | 1 9 | [* x [power x [- n 1]]]]] 10 | 11 | [def zero [n] 12 | [- n n]] 13 | 14 | [def main [] 15 | [power x [factorial 3]]] 16 | -------------------------------------------------------------------------------- /lingua-000-tiger/01-introduction/lang.sml: -------------------------------------------------------------------------------- 1 | infixr 1 <| 2 | infixr 9 <|> 3 | 4 | structure Lang = 5 | struct 6 | (* Low precedence function application. Useful to avoid parentheses. *) 7 | fun f <| x = f x 8 | 9 | (* Function composition. The built-in `o` operator is pretty hard to spot. *) 10 | fun f <|> g = fn (x) => f (g x) 11 | end 12 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/showast.sig: -------------------------------------------------------------------------------- 1 | signature SHOW_AST = 2 | sig 3 | val showOper : Ast.oper -> string 4 | val showVar : Ast.var -> string 5 | val showExp : Ast.exp -> string 6 | val showDec : Ast.dec -> string 7 | val showTy : Ast.ty -> string 8 | val showField : Ast.field -> string 9 | val showFundec : Ast.fundec -> string 10 | end 11 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/main/resources/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debugger 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/SwiftML.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/SwiftML/type.swift: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------- // 2 | // SwiftML // 3 | // -------------------------------------------------------------------------- // 4 | 5 | // See: https://forums.swift.org/t/circular-reference-in-enums/64267 6 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/readme.md: -------------------------------------------------------------------------------- 1 | # Shunting Yard Algorithm 2 | 3 |

4 | 5 |

6 | 7 | ## Resources 8 | 9 | - https://aquarchitect.github.io/swift-algorithm-club/Shunting%20Yard/ 10 | - https://en.m.wikipedia.org/wiki/Shunting-yard_algorithm 11 | - https://ir.cwi.nl/pub/9251 12 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/readme.md: -------------------------------------------------------------------------------- 1 | # SwiftML 2 | 3 | A small ML written in Apple's Swift. 4 | 5 | 6 | ``` 7 | SwiftML> let val a = 1 in a end 8 | val it = 1 : int 9 | SwiftML> 2 10 | val it = 2 : int 11 | SwiftML> when true then 1 else 2 end 12 | val it = 1 : int 13 | SwiftML> when false then 1 else 2 end 14 | val it = 2 : int 15 | SwiftML> :q 16 | Bye! 17 | ``` 18 | -------------------------------------------------------------------------------- /lingua-000-tiger/01-introduction/readme.md: -------------------------------------------------------------------------------- 1 | # Lingua 000 2 | 3 | The programming language given as an exercise at the end of Chapter 1 of [Modern 4 | Compiler Implementation in ML][0]. 5 | 6 | ## Usage 7 | 8 | ``` 9 | $ make 10 | $ make run 11 | $ make clean 12 | ``` 13 | 14 | [0]: http://www.amazon.com/Modern-Compiler-Implementation-Andrew-Appel/dp/0521607647/ 15 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/main/scala/eval/Value.scala: -------------------------------------------------------------------------------- 1 | package ro.igstan.debugger 2 | package eval 3 | 4 | import syntax.Term 5 | 6 | sealed trait Value 7 | 8 | object Value { 9 | case class Num(value: Int) extends Value 10 | case class Bool(value: Boolean) extends Value 11 | case class Fun(param: String, body: Term, closure: Env) extends Value 12 | } 13 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/main/scala/eval/Resumption.scala: -------------------------------------------------------------------------------- 1 | package ro.igstan.debugger 2 | package eval 3 | 4 | case class Resumption(env: Env, id: String, prev: Option[Result])(val next: () => Resumption.Step) 5 | 6 | object Resumption { 7 | sealed trait Step 8 | case class Done(result: Result) extends Step 9 | case class Next(resumption: Resumption) extends Step 10 | } 11 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/main/scala/typer/Constraint.scala: -------------------------------------------------------------------------------- 1 | package ro.igstan.debugger 2 | package typer 3 | 4 | sealed trait Constraint 5 | object Constraint { 6 | case class EQ(a: Type, b: Type) extends Constraint 7 | case class GEN(tenv: TypeEnv, tyScheme: TypeScheme, ty: Type) extends Constraint 8 | case class INST(tsvar: TypeScheme.Var, ty: Type) extends Constraint 9 | } 10 | -------------------------------------------------------------------------------- /lingua-000-tiger/01-introduction/Makefile: -------------------------------------------------------------------------------- 1 | # MLTON 2 | # ===== 3 | # 4 | # all: 5 | # @mkdir -p build && mlton -output build/lingua-000 lingua-000.mlb 6 | # 7 | # run: 8 | # @./build/lingua-000 9 | 10 | # SMLNJ 11 | # ===== 12 | # 13 | all: 14 | mkdir -p build && ml-build sources.cm Main.main build/lingua-000 15 | 16 | run: 17 | @sml @SMLload build/lingua-000.x86-darwin 18 | 19 | clean: 20 | rm -rf ./build 21 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/liveness-analysis.sig: -------------------------------------------------------------------------------- 1 | signature LIVENESS_ANALYSIS = 2 | sig 3 | datatype igraph = 4 | IGRAPH of { 5 | graph : Graph.graph, 6 | nodeMap : Temp.temp Graph.node_map, 7 | moves : (Graph.node * Graph.node) list 8 | } 9 | 10 | val interferenceGraph : Flow.flowgraph -> igraph * (Graph.temp_set Graph.node_map) 11 | val show : TextIO.outstream * igraph -> unit 12 | end 13 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/symbol.sig: -------------------------------------------------------------------------------- 1 | (* 2 | * An abstraction for symbol tables. 3 | *) 4 | signature SYMBOL = 5 | sig 6 | eqtype symbol 7 | val symbol : string -> symbol 8 | val name : symbol -> string 9 | 10 | type 'a table 11 | val empty : 'a table 12 | val set : 'a table -> symbol -> 'a -> 'a table 13 | val get : 'a table -> symbol -> 'a option 14 | val has : 'a table -> symbol -> bool 15 | end 16 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/nodes/Let.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package nodes 3 | 4 | case class Let(id: String, value: Node, body: Node) extends Node { 5 | override def accept(visitor: NodeVisitor { type N = Node })(state: visitor.S) = { 6 | visitor.let(id, value, body, state) 7 | } 8 | } 9 | 10 | object Let { 11 | def apply(id: String, value: Node)(body: => Node): Let = Let(id, value, body) 12 | } 13 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/SwiftML/type-error.swift: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------- // 2 | // SwiftML // 3 | // -------------------------------------------------------------------------- // 4 | 5 | enum TypeError { 6 | case Circular(Int, Type) 7 | case Conflict(Type, Type) 8 | case Unbound(identifier: String) 9 | } 10 | -------------------------------------------------------------------------------- /lingua-003-tree-interpreter/src/main/scala/Environment.scala: -------------------------------------------------------------------------------- 1 | package toy 2 | 3 | case class Environment(bindings: Map[String, Store.Location]) { 4 | def get(name: String): Option[Store.Location] = { 5 | bindings.get(name) 6 | } 7 | 8 | def set(name: String, location: Store.Location): Environment = { 9 | Environment(bindings + (name -> location)) 10 | } 11 | } 12 | 13 | object Environment { 14 | def empty = Environment(Map.empty) 15 | } 16 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/color.sig: -------------------------------------------------------------------------------- 1 | signature COLOR = 2 | sig 3 | structure Frame : FRAME 4 | structure TempMap : ORD_MAP where type Key.ord_key = Temp.temp 5 | 6 | type allocation = Frame.register TempMap.map 7 | 8 | val color : 9 | { 10 | interference : LivenessAnalysis.igraph, 11 | initial : allocation, 12 | spillCost : Graph.node -> int, 13 | registers : Frame.register list 14 | } -> allocation * Temp.temp list 15 | end 16 | -------------------------------------------------------------------------------- /lingua-003-tree-interpreter/build.sbt: -------------------------------------------------------------------------------- 1 | name := "interpreter" 2 | 3 | organization := "toy" 4 | 5 | version := "0.1.0" 6 | 7 | scalaVersion := "2.11.4" 8 | 9 | libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.3" % "test" 10 | 11 | scalacOptions ++= Seq( 12 | "-feature", 13 | "-unchecked", 14 | "-deprecation", 15 | "-Yno-adapted-args", 16 | "-Ywarn-value-discard", 17 | "-language:implicitConversions", 18 | "-language:higherKinds" 19 | ) 20 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/type-env.sig: -------------------------------------------------------------------------------- 1 | signature TYPE_ENV = 2 | sig 3 | type ty 4 | 5 | val empty : ty 6 | val fromList : (Term.Var.ty * TypeScheme.ty) list -> ty 7 | val get : ty -> Term.Var.ty -> TypeScheme.ty option 8 | val set : ty -> Term.Var.ty -> TypeScheme.ty -> ty 9 | val freeVars : ty -> Type.Var.ty list 10 | val generalize : ty -> Type.ty -> TypeScheme.ty 11 | val substitute : ty -> Subst.ty -> ty 12 | val toString : ty -> string 13 | end 14 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/term.sml: -------------------------------------------------------------------------------- 1 | structure Term = 2 | struct 3 | structure Var = 4 | struct 5 | type ty = string 6 | 7 | structure Key : ORD_KEY = 8 | struct 9 | type ord_key = ty 10 | val compare = String.compare 11 | end 12 | end 13 | 14 | datatype ty = 15 | VAR of Var.ty 16 | | BOOL of bool 17 | | INT of int 18 | | IF of ty * ty * ty 19 | | FUN of Var.ty * ty 20 | | APP of ty * ty 21 | | LET of Var.ty * ty * ty 22 | end 23 | -------------------------------------------------------------------------------- /lingua-011-bidirectional-typechecking/readme.md: -------------------------------------------------------------------------------- 1 | # Bidirectional Type Checking 2 | 3 | ## Resources 4 | 5 | - Paper: David Christiansen, [Bidirectional Typing Rules: A Tutorial][paper] 6 | - Video: David Christiansen, [Bidirectional Type Checking][video] 7 | 8 | ## Sample Run 9 | 10 | ![Screenshot of a sample run](./screenshot.png "Screenshot of a sample run") 11 | 12 | [paper]: https://davidchristiansen.dk/tutorials/bidirectional.pdf 13 | [video]: https://www.youtube.com/watch?v=utyBNDj7s2w 14 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/env.sig: -------------------------------------------------------------------------------- 1 | signature ENV = 2 | sig 3 | type ty 4 | 5 | datatype enventry = 6 | VarEntry of { 7 | access : Translate.access, 8 | ty : ty 9 | } 10 | | FunEntry of { 11 | level : Translate.level, 12 | label : Temp.label, 13 | formals : ty list, 14 | result : ty 15 | } 16 | 17 | (* Predefined types. *) 18 | val base_tenv : ty Symbol.table 19 | 20 | (* Predefined values. *) 21 | val base_venv : enventry Symbol.table 22 | end 23 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/sources.mlb: -------------------------------------------------------------------------------- 1 | $(SML_LIB)/basis/basis.mlb 2 | $(SML_LIB)/smlnj-lib/Util/smlnj-lib.mlb 3 | 4 | src/basis/tuples.sml 5 | src/basis/list.sig 6 | src/basis/list.sml 7 | src/basis/show.sig 8 | src/basis/show.sml 9 | 10 | src/term.sml 11 | src/type.sml 12 | src/subst.sig 13 | src/subst.sml 14 | src/type-scheme.sml 15 | src/type-env.sig 16 | src/type-env.fun 17 | src/type-env.sml 18 | src/constraint.sml 19 | src/unify.sml 20 | src/infer.sml 21 | src/terms.sml 22 | 23 | src/mlton/main.sml 24 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/temp.sml: -------------------------------------------------------------------------------- 1 | structure Temp : TEMP = 2 | struct 3 | structure F = Format 4 | 5 | type temp = int 6 | 7 | val temps = ref 100 8 | 9 | fun newTemp () = 10 | Ref.getAndIncrement temps 11 | 12 | fun makeString t = "t" ^ Int.toString t 13 | 14 | type label = Symbol.symbol 15 | 16 | val labs = ref 0 17 | 18 | fun newLabel () = 19 | Symbol.symbol (F.format "L%d" [F.INT (Ref.getAndIncrement labs)]) 20 | 21 | fun namedLabel name = 22 | Symbol.symbol name 23 | end 24 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/sources.cm: -------------------------------------------------------------------------------- 1 | group 2 | 3 | is 4 | $/basis.cm 5 | $/smlnj-lib.cm 6 | 7 | src ( 8 | term.sml 9 | type.sml 10 | subst.sig 11 | subst.sml 12 | type-scheme.sml 13 | type-env.sig 14 | type-env.fun 15 | type-env.sml 16 | constraint.sml 17 | unify.sml 18 | infer.sml 19 | terms.sml 20 | ) 21 | 22 | src/basis ( 23 | tuples.sml 24 | list.sig 25 | list.sml 26 | show.sig 27 | show.sml 28 | ) 29 | 30 | src/smlnj/main.sml 31 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/main/scala/Infer.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | 3 | object Infer { 4 | val tenv = TypeEnv(Map( 5 | "+" -> Type.FUN(Type.INT, Type.FUN(Type.INT, Type.INT)), 6 | "-" -> Type.FUN(Type.INT, Type.FUN(Type.INT, Type.INT)) 7 | )) 8 | 9 | def typeOf(term: Term): Type = { 10 | val typedTerm = Annotate.annotate(term, tenv) 11 | val constraints = Constraint.collect(typedTerm) 12 | val subst = Unifier.unify(constraints) 13 | subst.apply(typedTerm.ty) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/main/scala/typer/TypeEnv.scala: -------------------------------------------------------------------------------- 1 | package ro.igstan.debugger 2 | package typer 3 | 4 | case class TypeEnv(bindings: Map[String, TypeScheme]) { 5 | def get(name: String): Option[TypeScheme] = { 6 | bindings.get(name) 7 | } 8 | 9 | def set(name: String, value: TypeScheme): TypeEnv = { 10 | TypeEnv(bindings + (name -> value)) 11 | } 12 | 13 | def generalize(ty: Type): TypeScheme = { 14 | ??? 15 | } 16 | } 17 | 18 | object TypeEnv { 19 | def empty = TypeEnv(Map.empty) 20 | } 21 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/main/scala/Type.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | 3 | sealed trait Type 4 | 5 | object Type { 6 | type Var = Int 7 | 8 | case object INT extends Type 9 | case object BOOL extends Type 10 | case class FUN(paramTy: Type, returnTy: Type) extends Type 11 | case class VAR(tvar: Type.Var) extends Type 12 | 13 | private var counter = 0 14 | 15 | def freshVar(): Type = { 16 | counter += 1 17 | VAR(counter) 18 | } 19 | 20 | def resetFreshness(): Unit = { 21 | counter = 0 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/main/scala/typer/Substitution.scala: -------------------------------------------------------------------------------- 1 | package ro.igstan.debugger 2 | package typer 3 | 4 | case class Substitution(solutions: Map[Type.Var, Type]) { 5 | def apply(ty: Type): Type = { 6 | ??? 7 | } 8 | 9 | def compose(other: Substitution): Substitution = { 10 | ??? 11 | } 12 | } 13 | 14 | object Substitution { 15 | def empty: Substitution = { 16 | Substitution(Map.empty) 17 | } 18 | 19 | def one(tvar: Type.Var, ty: Type): Substitution = { 20 | Substitution(Map(tvar -> ty)) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/SwiftML/elaborator.swift: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------- // 2 | // SwiftML // 3 | // -------------------------------------------------------------------------- // 4 | 5 | func elaborate(term: Term) -> Result, TypeError> { 6 | return annotate(term: term).flatMap { annotated in 7 | Unifier.solve(constraints: constrain(annotated)).map { substitution in 8 | substitution.applyTo(term: annotated) 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/main/scala/Main.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | 3 | import parser.Parser 4 | import signature.Signature 5 | 6 | object Main { 7 | def main(args: Array[String]): Unit = { 8 | val source = """ 9 | | fn isZero => 10 | | if isZero 1 11 | | then 2 12 | | else 3 13 | """.trim.stripMargin 14 | 15 | println(s"\n$source\n") 16 | 17 | val ast = Parser.parse(source) 18 | println(s"Term: $ast") 19 | 20 | val inferredType = Infer.typeOf(ast) 21 | println("Type: " + Signature.forType(inferredType) + "\n") 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/main/scala/Term.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | 3 | /** 4 | * Represents the untyped AST, produced by the parser phase. 5 | */ 6 | sealed trait Term 7 | 8 | case class INT(value: Int) extends Term 9 | case class BOOL(value: Boolean) extends Term 10 | case class FUN(param: String, body: Term) extends Term 11 | case class VAR(name: String) extends Term 12 | case class APP(fn: Term, arg: Term) extends Term 13 | case class IF(testCondition: Term, trueBranch: Term, falseBranch: Term) extends Term 14 | case class LET(binding: String, value: Term, body: Term) extends Term 15 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/main/scala/typer/TypeScheme.scala: -------------------------------------------------------------------------------- 1 | package ro.igstan.debugger 2 | package typer 3 | 4 | sealed trait TypeScheme 5 | 6 | object TypeScheme { 7 | case class Var(value: Int) extends AnyRef 8 | 9 | object Var { 10 | private var counter = -1 11 | 12 | def fresh(): TypeScheme = { 13 | counter += 1 14 | TSVAR(Var(counter)) 15 | } 16 | 17 | def reset(): Unit = { 18 | counter = -1 19 | } 20 | } 21 | 22 | case class FORALL(vars: Set[Type.Var], ty: Type) extends TypeScheme 23 | case class TSVAR(tsVar: Var) extends TypeScheme 24 | } 25 | -------------------------------------------------------------------------------- /lingua-000-tiger/02-lexical-analysis/driver.sml: -------------------------------------------------------------------------------- 1 | structure Parse = 2 | struct 3 | fun parse filename = 4 | let 5 | val file = TextIO.openIn filename 6 | fun get _ = TextIO.input file 7 | val lexer = Mlex.makeLexer get 8 | fun lex () = 9 | let 10 | val t = lexer() 11 | in 12 | print (Token.toString t); 13 | print "\n"; 14 | case t of 15 | Token.EOF(_, _) => () 16 | | _ => lex () 17 | end 18 | in 19 | lex (); 20 | TextIO.closeIn file 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/src/main/scala/linguae/Fixity.scala: -------------------------------------------------------------------------------- 1 | package linguae 2 | 3 | sealed trait Fixity extends Product with Serializable { 4 | def precedence: Int 5 | def appliesAfter(that: Fixity): Boolean 6 | } 7 | 8 | object Fixity { 9 | final case class L(override val precedence: Int) extends Fixity { 10 | override def appliesAfter(that: Fixity): Boolean = 11 | this.precedence <= that.precedence 12 | } 13 | 14 | final case class R(override val precedence: Int) extends Fixity { 15 | override def appliesAfter(that: Fixity): Boolean = 16 | this.precedence < that.precedence 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lingua-003-tree-interpreter/src/main/scala/Result.scala: -------------------------------------------------------------------------------- 1 | package toy 2 | 3 | sealed trait Result[+A] { 4 | import Result._ 5 | 6 | def map[B](fn: A => B): Result[B] = { 7 | this match { 8 | case Success(s) => Success(fn(s)) 9 | case Failure(f) => Failure(f) 10 | } 11 | } 12 | 13 | def flatMap[B](fn: A => Result[B]): Result[B] = { 14 | this match { 15 | case Success(s) => fn(s) 16 | case Failure(f) => Failure(f) 17 | } 18 | } 19 | } 20 | 21 | object Result { 22 | case class Success[A](value: A) extends Result[A] 23 | case class Failure(reason: String) extends Result[Nothing] 24 | } 25 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/main/scala/eval/Env.scala: -------------------------------------------------------------------------------- 1 | package ro.igstan.debugger 2 | package eval 3 | 4 | case class Env(bindings: Map[String, Value]) { 5 | def get(name: String): Option[Value] = bindings.get(name) 6 | def set(name: String, value: Value): Env = Env(bindings + (name -> value)) 7 | 8 | override def toString = { 9 | val pairs = bindings.map({ 10 | case (k, Value.Num(n)) => s"$k: $n" 11 | case (k, Value.Bool(b)) => s"$k: $b" 12 | case (k, _: Value.Fun) => s"$k: ƒ" 13 | }) 14 | 15 | pairs.mkString("[ ", " ; ", " ]") 16 | } 17 | } 18 | 19 | object Env { 20 | def empty = Env(Map.empty) 21 | } 22 | -------------------------------------------------------------------------------- /lingua-013-pattern-match-compiler/src/common.sml: -------------------------------------------------------------------------------- 1 | (* Follows: "ML pattern match compilation (March 5, 1996).pdf" *) 2 | 3 | structure Common = 4 | struct 5 | type con = { name : string, arity : int, span : int } 6 | 7 | datatype pat = 8 | | PVar of string 9 | | PCon of con * pat list 10 | 11 | datatype 'a tree = 12 | | Null 13 | | Leaf of 'a 14 | | Node of 'a tree * 'a * 'a tree 15 | 16 | val Nullc = { name = "Null", arity = 0, span = 3 } 17 | val Leafc = { name = "Leaf", arity = 1, span = 3 } 18 | val Nodec = { name = "Node", arity = 3, span = 3 } 19 | 20 | type 'rhs match = (pat * 'rhs) list 21 | end 22 | -------------------------------------------------------------------------------- /lingua-004-lisp-parser/build.sbt: -------------------------------------------------------------------------------- 1 | name := "leesp" 2 | 3 | organization := "ro.igstan" 4 | 5 | version := "0.1.0" 6 | 7 | scalaVersion := "2.11.5" 8 | 9 | libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.3" % "test" 10 | 11 | scalacOptions ++= Seq( 12 | "-feature", 13 | "-unchecked", 14 | "-deprecation", 15 | "-language:implicitConversions", 16 | "-language:higherKinds", 17 | "-Xlint:_", 18 | "-Yno-adapted-args", 19 | "-Ywarn-dead-code", 20 | "-Ywarn-inaccessible", 21 | "-Ywarn-infer-any", 22 | "-Ywarn-nullary-override", 23 | "-Ywarn-nullary-unit", 24 | "-Ywarn-numeric-widen", 25 | "-Ywarn-unused", 26 | "-Ywarn-value-discard" 27 | ) 28 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/build.sbt: -------------------------------------------------------------------------------- 1 | name := "linguae:hm-inference-scala" 2 | 3 | organization := "ro.igstan" 4 | 5 | version := "0.1.0" 6 | 7 | scalaVersion := "2.12.1" 8 | 9 | scalacOptions ++= Seq( 10 | "-feature", 11 | "-unchecked", 12 | "-deprecation", 13 | "-language:implicitConversions", 14 | "-language:higherKinds", 15 | "-Xlint:_", 16 | "-Yno-adapted-args", 17 | "-Ywarn-dead-code", 18 | "-Ywarn-inaccessible", 19 | "-Ywarn-infer-any", 20 | "-Ywarn-nullary-override", 21 | "-Ywarn-nullary-unit", 22 | "-Ywarn-numeric-widen", 23 | "-Ywarn-unused", 24 | "-Ywarn-value-discard" 25 | ) 26 | 27 | libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1" % "test" 28 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/test/scala/logback.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package test 3 | 4 | import ch.qos.logback.classic.Level 5 | import ch.qos.logback.classic.spi.ILoggingEvent 6 | import ch.qos.logback.core.pattern.color.ANSIConstants._ 7 | import ch.qos.logback.core.pattern.color.ForegroundCompositeConverterBase 8 | 9 | class LogLevelHighlighting extends ForegroundCompositeConverterBase[ILoggingEvent] { 10 | override def getForegroundColorCode(event: ILoggingEvent): String = { 11 | (event.getLevel.toInt: @annotation.switch) match { 12 | case Level.ERROR_INT => RED_FG 13 | case Level.WARN_INT => YELLOW_FG 14 | case _ => DEFAULT_FG 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/graph.sig: -------------------------------------------------------------------------------- 1 | signature GRAPH = 2 | sig 3 | type node 4 | type graph 5 | 6 | structure NodeMap : ORD_MAP where type Key.ord_key = node 7 | structure TempSet : ORD_SET where type Key.ord_key = Temp.temp 8 | 9 | type 'a node_map = 'a NodeMap.map 10 | type temp_set = TempSet.set 11 | 12 | exception GraphEdge 13 | 14 | val nodes : graph -> node list 15 | val succ : node -> node list 16 | val pred : node -> node list 17 | val adj : node -> node list 18 | val eq : node * node -> bool 19 | val newGraph : unit -> graph 20 | val newNode : graph -> node 21 | val mkEdge : { from : node, to : node } -> unit 22 | val rmEdge : { from : node, to : node } -> unit 23 | val nodename : node -> string 24 | end 25 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/subst.sml: -------------------------------------------------------------------------------- 1 | structure Subst :> SUBST = 2 | struct 3 | type ty = (Type.Var.ty * Type.ty) list 4 | 5 | val empty = [] 6 | 7 | fun fromList xs = xs 8 | 9 | fun set subst var value = 10 | (var, value) :: subst 11 | 12 | fun apply subst ty = 13 | let 14 | fun fold ((tvar, newTy), ty) = Type.substitute ty tvar newTy 15 | in 16 | List.foldl fold ty subst 17 | end 18 | 19 | fun compose s1 s2 = 20 | let 21 | val s = List.map (fn (tvar, ty) => (tvar, apply s2 ty)) s1 22 | in 23 | s @ s2 24 | end 25 | 26 | fun toString subst = 27 | let 28 | open Show 29 | val pair = tuple2 (int, Type.toString) 30 | in 31 | list pair subst 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | true 7 | 8 | 9 | 10 | 11 | %highlight(%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %+5level) — %logger{36} — %msg%n 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /lingua-003-tree-interpreter/src/main/scala/Node.scala: -------------------------------------------------------------------------------- 1 | package toy 2 | 3 | sealed trait Node 4 | case class Num(value: Int) extends Node 5 | case class Add(left: Node, right: Node) extends Node 6 | case class Sub(left: Node, right: Node) extends Node 7 | case class Mul(left: Node, right: Node) extends Node 8 | case class Div(left: Node, right: Node) extends Node 9 | case class If(cond: Node, yes: Node, no: Node) extends Node 10 | case class Fun(param: String, body: Node) extends Node 11 | case class App(fn: Node, arg: Node) extends Node 12 | case class Ref(name: String) extends Node 13 | case class Let(name: String, value: Node, body: Node) extends Node 14 | case class Seq(a: Node, b: Node) extends Node 15 | case class Set(name: String, value: Node) extends Node 16 | -------------------------------------------------------------------------------- /lingua-004-lisp-parser/src/main/scala/main.scala: -------------------------------------------------------------------------------- 1 | package leesp 2 | 3 | object Main { 4 | val reader = new Reader(traceExecution = false) 5 | 6 | def main(args: Array[String]): Unit = { 7 | showProgram(args(0)) 8 | showProgram(""" 9 | (define a 1) 10 | (define b 2) 11 | (define add (lambda (a b) (+ a b))) 12 | (add a b) 13 | """) 14 | } 15 | 16 | def showProgram(source: String): Unit = { 17 | try { 18 | println(reader.read(source).mkString("\n")) 19 | } catch { 20 | case UnmatchedLeftParen(row, col) => 21 | println(s"unmatched left parenthesis: row=$row, col=$col") 22 | case UnmatchedRightParen(row, col) => 23 | println(s"unmatched right parenthesis: row=$row, col=$col") 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lingua-011-bidirectional-typechecking/src/main/scala/linguae/Color.scala: -------------------------------------------------------------------------------- 1 | package linguae 2 | 3 | object Color { 4 | private val reset = "\u001b[0m" 5 | 6 | private def xterm256(c: Int): String = 7 | "\u001b[1;38;5;%dm".format(c) 8 | 9 | def keyword(s: String): String = 10 | xterm256(90) + s + reset 11 | 12 | private def xterm256(r: Int, g: Int, b: Int): String = { 13 | val color = 16 + (r * 36) + (g * 6) + b 14 | "\u001b[48;5;%dm".format(color) 15 | } 16 | 17 | def main(args: Array[String]): Unit = { 18 | println(keyword("class")) 19 | 20 | for { 21 | r <- 0.until(6) 22 | g <- 0.until(6) 23 | b <- 0.until(6) 24 | } yield { 25 | print(xterm256(r, g, b) + " " + reset) 26 | if (b == 5) println() 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/tree.sig: -------------------------------------------------------------------------------- 1 | signature TREE = 2 | sig 3 | type size 4 | type label = Temp.label 5 | 6 | datatype stm = 7 | SEQ of stm * stm 8 | | LABEL of label 9 | | JUMP of exp * label list 10 | | CJUMP of relop * exp * exp * label * label 11 | | MOVE of exp * exp 12 | | EXP of exp 13 | 14 | and exp = 15 | BINOP of binop * exp * exp 16 | | MEM of exp 17 | | TEMP of Temp.temp 18 | | ESEQ of stm * exp 19 | | NAME of label 20 | | CONST of int 21 | | CALL of exp * exp list 22 | 23 | and binop = 24 | PLUS | MINUS | MUL | DIV | AND | OR | LSHIFT | RSHIFT | ARSHIFT | XOR 25 | 26 | and relop = 27 | EQ | NE | LT | GT | LE | GE | ULT | ULE | UGT | UGE 28 | 29 | val notRel : relop -> relop 30 | val commute : relop -> relop 31 | val seq : stm list -> stm 32 | end 33 | -------------------------------------------------------------------------------- /lingua-003-tree-interpreter/src/test/scala/package.scala: -------------------------------------------------------------------------------- 1 | package toy 2 | 3 | import org.scalatest.matchers.{ Matcher, MatchResult } 4 | import org.scalatest.words.ResultOfNotWordForAny 5 | 6 | package object test { 7 | type FunSuite = org.scalatest.FunSuite 8 | type Matchers = org.scalatest.Matchers 9 | 10 | def evaluateTo(expected: Value) = { 11 | new Matcher[Result[Evaluation]] { 12 | def apply(actual: Result[Evaluation]) = { 13 | val matches = actual match { 14 | case Result.Success(Evaluation(actual, _)) => actual == expected 15 | case _ => false 16 | } 17 | MatchResult( 18 | matches, 19 | s"The value in $actual was not equal to $expected", 20 | s"The value in $actual was equal to $expected" 21 | ) 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/SwiftML/unifier.swift: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------- // 2 | // SwiftML // 3 | // -------------------------------------------------------------------------- // 4 | 5 | enum Unifier { 6 | static func solve(constraints: Set) -> Result { 7 | guard let constraint = constraints.first else { 8 | return .Success(Substitution.empty) 9 | } 10 | 11 | return constraint.solve().flatMap { headSubstitution in 12 | let tail = headSubstitution.applyTo(constraints: Set(constraints.dropFirst())) 13 | return solve(constraints: tail).map { tailSubstitution in 14 | headSubstitution.compose(with: tailSubstitution) 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lingua-010-jit-hello-world-apple-silicon/readme.md: -------------------------------------------------------------------------------- 1 | # JIT Hello World for Apple Silicon 2 | 3 | ## Resources 4 | 5 | - [Antonio Cuni — How to write a JIT compiler in 30 minutes](https://www.youtube.com/watch?v=DKns_rH8rrg) 6 | - [Porting Just-In-Time Compilers to Apple Silicon][apple-jit] 7 | - [QEMU Patch: Fix execution on Apple Silicon](https://lists.gnu.org/archive/html/qemu-devel/2021-01/msg02555.html) 8 | - [Gist for Linux/x86](https://gist.github.com/markmont/dcd20d632fa753438f6fc1b3bb3711ec) 9 | 10 | ## Notes 11 | 12 | For some reason, the executable doesn't seem to need the `com.apple.security.cs.allow-jit` 13 | entitlement, as mentioned in [Porting Just-In-Time Compilers to Apple Silicon][apple-jit]. 14 | 15 | [apple-jit]: https://developer.apple.com/documentation/apple-silicon/porting-just-in-time-compilers-to-apple-silicon 16 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/NodeVisitor.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | 3 | trait NodeVisitor { 4 | type N // Node 5 | type R // Result 6 | type S // State 7 | 8 | def num(n: Int, state: S): (R, S) 9 | def bool(b: Boolean, state: S): (R, S) 10 | def add(a: N, b: N, state: S): (R, S) 11 | def sub(a: N, b: N, state: S): (R, S) 12 | def mul(a: N, b: N, state: S): (R, S) 13 | def div(a: N, b: N, state: S): (R, S) 14 | def let(id: String, value: N, body: N, state: S): (R, S) 15 | def ref(id: String, state: S): (R, S) 16 | def fun(id: String, body: N, state: S): (R, S) 17 | def app(fn: N, arg: N, state: S): (R, S) 18 | def seq(a: N, b: N, state: S): (R, S) 19 | def set(id: String, value: N, state: S): (R, S) 20 | def equal(a: N, b: N, state: S): (R, S) 21 | def when(cond: N, yes: N, no: N, state: S): (R, S) 22 | } 23 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/SwiftML/value.swift: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------- // 2 | // SwiftML // 3 | // -------------------------------------------------------------------------- // 4 | 5 | indirect enum Value: CustomStringConvertible { 6 | case Num(Int) 7 | case Bool(Bool) 8 | case Fun(String, Term, [String:Value]) 9 | case Primitive((Value) -> Result) 10 | 11 | func success() -> Result { 12 | return .Success(self) 13 | } 14 | 15 | var description: String { 16 | switch self { 17 | case .Num(let n): return String(n, radix: 10) 18 | case .Bool(true): return "true" 19 | case .Bool(false): return "false" 20 | case .Fun, .Primitive: return "fn" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/src/main/scala/linguae/Expr.scala: -------------------------------------------------------------------------------- 1 | package linguae 2 | 3 | enum Expr { 4 | case Const(value: Int) 5 | case BinOp(value: String, a: Expr, b: Expr) 6 | 7 | def pretty(operatorTable: Map[String, Fixity]): String = { 8 | def parenthesize(a: Expr, parentFixity: Fixity) = 9 | a match { 10 | case Const(a) => a.toString 11 | case a @ BinOp(op, _, _) => 12 | val thisFixity = operatorTable(op) 13 | val sa = a.pretty(operatorTable) 14 | if parentFixity.appliesAfter(thisFixity) then sa else s"($sa)" 15 | } 16 | 17 | this match { 18 | case Const(n) => n.toString 19 | case BinOp(op, a, b) => 20 | val oPrec = operatorTable(op) 21 | val sa = parenthesize(a, oPrec) 22 | val sb = parenthesize(b, oPrec) 23 | s"$sa $op $sb" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/SwiftML/dictionary.swift: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------- // 2 | // SwiftML // 3 | // -------------------------------------------------------------------------- // 4 | 5 | extension Dictionary { 6 | init(_ pairs: [Element]) { 7 | self.init(minimumCapacity: pairs.count) 8 | 9 | for (k, v) in pairs { 10 | self[k] = v 11 | } 12 | } 13 | 14 | func mapValues(fn: @escaping (Value) -> T) -> Dictionary { 15 | return Dictionary(self.map { (k, v) in (k, fn(v)) }) 16 | } 17 | 18 | mutating func get(key: Key, orUpdate: @autoclosure () -> Value) -> Value { 19 | if let value = self[key] { 20 | return value 21 | } else { 22 | let value = orUpdate() 23 | self[key] = value 24 | return value 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/main/scala/typer/Type.scala: -------------------------------------------------------------------------------- 1 | package ro.igstan.debugger 2 | package typer 3 | 4 | sealed trait Type 5 | 6 | object Type { 7 | case class Var(value: Int) extends AnyVal { 8 | def occursIn(ty: Type): Boolean = { 9 | ty match { 10 | case TINT => false 11 | case TBOOL => false 12 | case TVAR(other) => this == other 13 | case TFUN(paramTy, returnTy) => occursIn(paramTy) || occursIn(returnTy) 14 | } 15 | } 16 | } 17 | 18 | object Var { 19 | private var counter = -1 20 | 21 | def fresh(): Type = { 22 | counter += 1 23 | TVAR(Var(counter)) 24 | } 25 | 26 | def reset(): Unit = { 27 | counter = -1 28 | } 29 | } 30 | } 31 | 32 | case class TFUN(paramTy: Type, returnTy: Type) extends Type 33 | case class TVAR(tvar: Type.Var) extends Type 34 | case object TBOOL extends Type 35 | case object TINT extends Type 36 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/main/scala/TypedTerm.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | 3 | /** 4 | * Represents the *typed* AST, produced by the type annotation phase from 5 | * an untyped AST. 6 | */ 7 | sealed trait TypedTerm { 8 | def ty: Type 9 | } 10 | 11 | object TypedTerm { 12 | case class Binder(ty: Type, name: String) 13 | 14 | case class INT(ty: Type, value: Int) extends TypedTerm 15 | case class BOOL(ty: Type, value: Boolean) extends TypedTerm 16 | case class FUN(ty: Type, param: TypedTerm.Binder, body: TypedTerm) extends TypedTerm 17 | case class VAR(ty: Type, name: String) extends TypedTerm 18 | case class APP(ty: Type, fn: TypedTerm, arg: TypedTerm) extends TypedTerm 19 | case class IF(ty: Type, testCondition: TypedTerm, trueBranch: TypedTerm, falseBranch: TypedTerm) extends TypedTerm 20 | case class LET(ty: Type, binding: TypedTerm.Binder, value: TypedTerm, body: TypedTerm) extends TypedTerm 21 | } 22 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/src/test/scala/linguae/test/ExprParserSuite.scala: -------------------------------------------------------------------------------- 1 | package linguae 2 | package test 3 | 4 | abstract class ExprParserSuite extends munit.FunSuite { 5 | def parser: ExprParser 6 | 7 | protected val operatorTable = Map( 8 | "^" -> Fixity.R(6), 9 | "*" -> Fixity.L(3), 10 | "/" -> Fixity.L(3), 11 | "+" -> Fixity.L(0), 12 | "-" -> Fixity.L(0), 13 | ) 14 | 15 | private val exprs = List( 16 | "1 + 2", 17 | "(1 + 2) * 3", 18 | "4 + -2 - 1", 19 | "4 * 2 / 1", 20 | "1 + 2 * 3", 21 | "4 + 4 * 2 / (1 - 5)", 22 | "4 + (4 + 2) / (1 - 5)", 23 | ) 24 | 25 | exprs.foreach { expr => 26 | test(s"parses: $expr") { 27 | val result = Token 28 | .parser 29 | .consume(expr) 30 | .map(parser.parse) 31 | .toOption 32 | .get 33 | .pretty(operatorTable) 34 | 35 | assertEquals(result, expr) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/symbol.sml: -------------------------------------------------------------------------------- 1 | structure Symbol : SYMBOL = 2 | struct 3 | exception Symbol 4 | 5 | type symbol = string * int 6 | 7 | val nextsym = ref 0 8 | 9 | val hashtable : (string, int) HashTable.hash_table = 10 | HashTable.mkTable (HashString.hashString, op=) (128, Symbol) 11 | 12 | fun symbol name = 13 | case HashTable.find hashtable name of 14 | SOME i => (name, i) 15 | | NONE => 16 | let 17 | val i = !nextsym 18 | in 19 | nextsym := i + 1; 20 | HashTable.insert hashtable (name, i); 21 | (name, i) 22 | end 23 | 24 | fun name (s, _) = s 25 | 26 | type 'a table = 'a IntBinaryMap.map 27 | 28 | val empty = IntBinaryMap.empty 29 | fun set table (_, key) value = IntBinaryMap.insert (table, key, value) 30 | fun get table (_, key) = IntBinaryMap.find (table, key) 31 | fun has table (_, key) = Option.isSome (IntBinaryMap.find (table, key)) 32 | end 33 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/SwiftML/result.swift: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------- // 2 | // SwiftML // 3 | // -------------------------------------------------------------------------- // 4 | 5 | indirect enum Result { 6 | case Success(S) 7 | case Failure(F) 8 | 9 | public static func fromOptional(_ s: S?, _ f: F) -> Result { 10 | switch s { 11 | case .some(let s): return .Success(s) 12 | case .none: return .Failure(f) 13 | } 14 | } 15 | 16 | func map(_ fn: (S) -> T) -> Result { 17 | switch self { 18 | case .Success(let s): return .Success(fn(s)) 19 | case .Failure(let f): return .Failure(f) 20 | } 21 | } 22 | 23 | func flatMap(_ fn: (S) -> Result) -> Result { 24 | switch self { 25 | case .Success(let s): return fn(s) 26 | case .Failure(let f): return .Failure(f) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/main/scala/syntax/Term.scala: -------------------------------------------------------------------------------- 1 | package ro.igstan.debugger 2 | package syntax 3 | 4 | sealed trait Term { 5 | val meta: String 6 | val id: String 7 | } 8 | 9 | object Term { 10 | case class INT(value: Int)(val meta: String, val id: String) extends Term 11 | case class ADD(a: Term, b: Term)(val meta: String, val id: String) extends Term 12 | case class SUB(a: Term, b: Term)(val meta: String, val id: String) extends Term 13 | case class BOOL(value: Boolean)(val meta: String, val id: String) extends Term 14 | case class VAR(name: String)(val meta: String, val id: String) extends Term 15 | case class IF(test: Term, yes: Term, no: Term)(val meta: String, val id: String) extends Term 16 | case class FN(param: String, body: Term)(val meta: String, val id: String) extends Term 17 | case class APP(fn: Term, arg: Term)(val meta: String, val id: String) extends Term 18 | case class LET(binding: String, value: Term, body: Term)(val meta: String, val id: String) extends Term 19 | } 20 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/SwiftML/stdlib.swift: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------- // 2 | // SwiftML // 3 | // -------------------------------------------------------------------------- // 4 | 5 | private typealias TypedValue = Value<(Position, Type)> 6 | 7 | private func arithmetic(_ a: TypedValue, _ op: @escaping (Int, Int) -> Int) -> Result { 8 | switch a { 9 | case let .Num(a): return Value.Primitive({ b in 10 | switch b { 11 | case let .Num(b): return Value.Num(op(a, b)).success() 12 | case _: return .Failure("number required, got: \(b)") 13 | } 14 | }).success() 15 | case _: return .Failure("number required, got: \(a)") 16 | } 17 | } 18 | 19 | let stdlib = [ 20 | "+": Value.Primitive { arithmetic($0, +) }, 21 | "-": Value.Primitive { arithmetic($0, -) }, 22 | "*": Value.Primitive { arithmetic($0, *) }, 23 | "/": Value.Primitive { arithmetic($0, /) } 24 | ] 25 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/sources.cm: -------------------------------------------------------------------------------- 1 | group 2 | 3 | is 4 | $/basis.cm 5 | $/smlnj-lib.cm 6 | 7 | $SMACKAGE/sml-extras/v0.1.2/sources.sml.cm 8 | 9 | assem.sml 10 | ast.sml 11 | canon.sig 12 | canon.sml 13 | codegen.sig 14 | color.sig 15 | env.sig 16 | env.sml 17 | escape-analysis.sig 18 | escape-analysis.sml 19 | flow.sml 20 | frame.sig 21 | frame.sml 22 | free-var-analysis.sig 23 | free-var-analysis.sml 24 | graph.sig 25 | graph.sml 26 | liveness-analysis.sig 27 | liveness-analysis.sml 28 | main.sml 29 | make-graph.sig 30 | make-graph.sml 31 | mips-codegen.sml 32 | mips-frame.sml 33 | mips-register.sml 34 | parse.sml 35 | reg-alloc.sig 36 | semant.sig 37 | semant.sml 38 | showast.sig 39 | showast.sml 40 | symbol.sig 41 | symbol.sml 42 | syntax.sig 43 | syntax.sml 44 | temp.sig 45 | temp.sml 46 | test.sml 47 | topo-sort.sml 48 | translate.sig 49 | translate.sml 50 | tree-printer.sig 51 | tree-printer.sml 52 | tree.sig 53 | tree.sml 54 | types.sml 55 | -------------------------------------------------------------------------------- /lingua-005-debugger-scalajs/src/main/resources/css/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | -webkit-box-siging: border-box; 3 | -ms-box-siging: border-box; 4 | -o-box-siging: border-box; 5 | box-sizing: border-box; 6 | } 7 | 8 | body { 9 | margin: 120px; 10 | padding: 0; 11 | position: relative; 12 | font-size: 90%; 13 | font-family: menlo, monospace; 14 | cursor: default; 15 | } 16 | 17 | .source { 18 | font-family: menlo, monospace; 19 | font-size: 13px; 20 | padding: 5px; 21 | } 22 | 23 | .source:focus { 24 | outline: none; 25 | } 26 | 27 | .env, .result, pre { 28 | font-size: 14px; 29 | font-family: menlo, monospace; 30 | } 31 | 32 | .keyword, .bool { 33 | font-weight: bold; 34 | } 35 | 36 | .param, .val-def, .var { 37 | color: #804000; 38 | } 39 | 40 | .highlight { 41 | background: #FFE7CA; 42 | } 43 | 44 | .reference { 45 | background: #FFC9D7; 46 | border-radius: 3px; 47 | padding: 2px 0; 48 | } 49 | 50 | .overlay { 51 | position: absolute; 52 | pointer-events: none; 53 | top: 0; 54 | left: 0; 55 | } 56 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/src/main/scala/linguae/Token.scala: -------------------------------------------------------------------------------- 1 | package linguae 2 | 3 | enum Token { 4 | case Const(value: Int) 5 | case BinOp(value: String) 6 | case ParenL 7 | case ParenR 8 | } 9 | 10 | object Token { 11 | def parser: Parser[List[Token]] = { 12 | import Parser.* 13 | 14 | def token[A](parser: Parser[A]): Parser[A] = spaces *> parser <* spaces 15 | def spaces: Parser[Unit] = satisfy(_.isWhitespace).optionalMany.void 16 | def lparen: Parser[Token] = char('(').as(ParenL) 17 | def rparen: Parser[Token] = char(')').as(ParenR) 18 | 19 | def number: Parser[Token] = 20 | for { 21 | n <- char('-').optional.map(_.isDefined) 22 | d <- satisfy(_.isDigit).many.map(_.mkString.toInt) 23 | } yield { 24 | Const(if n then -d else d) 25 | } 26 | 27 | def operator: Parser[Token] = 28 | Set('+', '-', '*', '/', '^') 29 | .map(char) 30 | .reduce(_ | _) 31 | .map(op => BinOp(op.toString)) 32 | 33 | token(lparen | rparen | number | operator).optionalMany 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/basis/show.sig: -------------------------------------------------------------------------------- 1 | signature SHOW = 2 | sig 3 | type 'a show 4 | 5 | val println : string -> unit 6 | val int : int show 7 | val bool : bool show 8 | val char : char show 9 | val real : real show 10 | val word : word show 11 | val unit : unit show 12 | val string : string show 13 | val list : 'a show -> 'a list show 14 | val array : 'a show -> 'a array show 15 | val vector : 'a show -> 'a vector show 16 | val option : 'a show -> 'a option show 17 | val tuple2 : 'a show * 'b show -> ('a * 'b) show 18 | val tuple3 : 'a show * 'b show * 'c show -> ('a * 'b * 'c) show 19 | val tuple4 : 'a show * 'b show * 'c show * 'd show -> ('a * 'b * 'c * 'd) show 20 | val tuple5 : 'a show * 'b show * 'c show * 'd show * 'e show -> ('a * 'b * 'c * 'd * 'e) show 21 | val tuple6 : 'a show * 'b show * 'c show * 'd show * 'e show * 'f show -> ('a * 'b * 'c * 'd * 'e * 'f) show 22 | val tuple7 : 'a show * 'b show * 'c show * 'd show * 'e show * 'f show * 'g show -> ('a * 'b * 'c * 'd * 'e * 'f * 'g) show 23 | end 24 | -------------------------------------------------------------------------------- /lingua-012-chatgpt-c++-compiler/Makefile: -------------------------------------------------------------------------------- 1 | # Define compiler, linker, and assembler 2 | CXX = g++ 3 | AS = as 4 | CC = gcc 5 | 6 | # Define flags for C++ and C compilation 7 | CXXFLAGS = -std=c++17 -O2 -Wall 8 | CFLAGS = -O2 -Wall 9 | 10 | # Define the C++ compiler source and target 11 | CPP_COMPILER_SRC = compiler.cpp 12 | CPP_COMPILER_BIN = .build/compiler 13 | 14 | # Define the assembly output file 15 | ASM_OUTPUT = .build/main.s 16 | 17 | # Define the C source file and object file 18 | C_SRC = print_int.c 19 | C_OBJ = .build/print_int.o 20 | 21 | # Define the final binary 22 | TARGET = program 23 | 24 | # Create the .build directory 25 | $(shell mkdir -p .build) 26 | 27 | all: $(TARGET) 28 | 29 | $(TARGET): $(ASM_OUTPUT) $(C_OBJ) 30 | $(CC) -o $@ .build/main.o $(C_OBJ) 31 | 32 | $(C_OBJ): $(C_SRC) 33 | $(CC) $(CFLAGS) -c $< -o $@ 34 | 35 | $(ASM_OUTPUT): $(CPP_COMPILER_BIN) 36 | ./$(CPP_COMPILER_BIN) > $@ 37 | $(AS) -o .build/main.o $(ASM_OUTPUT) 38 | 39 | $(CPP_COMPILER_BIN): $(CPP_COMPILER_SRC) 40 | $(CXX) $(CXXFLAGS) $< -o $@ 41 | 42 | clean: 43 | rm -rf .build $(TARGET) 44 | 45 | .PHONY: all clean 46 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/syntax.sml: -------------------------------------------------------------------------------- 1 | structure Syntax : SYNTAX = 2 | struct 3 | local 4 | fun join xs sep = 5 | let 6 | val folder = fn (x, acc) => acc ^ sep ^ x 7 | in 8 | if List.null xs then "" 9 | else (List.hd xs) ^ (List.foldl (folder) "" (List.tl xs)) 10 | end 11 | in 12 | fun showOper oper = 13 | let open Ast in 14 | case oper of 15 | PlusOp => "+" 16 | | MinusOp => "-" 17 | | TimesOp => "*" 18 | | DivideOp => "/" 19 | | EqOp => "=" 20 | | NeqOp => "<>" 21 | | LtOp => "<" 22 | | LeOp => "<=" 23 | | GtOp => ">" 24 | | GeOp => ">=" 25 | end 26 | 27 | fun showType t = 28 | let open Types in 29 | case t of 30 | NIL => "nil" 31 | | INT => "int" 32 | | UNIT => "unit" 33 | | STRING => "string" 34 | | NAME(name, _) => Symbol.name name 35 | | ARRAY(ty, _) => "array of " ^ (showType ty) 36 | | RECORD(fields, _) => "{ "^ (join (List.map (fn (sym, ty) => (Symbol.name sym) ^" : "^ (showType ty)) fields) ", ") ^" }" 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/tree.sml: -------------------------------------------------------------------------------- 1 | structure Tree :> TREE = 2 | struct 3 | type size = int 4 | type label = Temp.label 5 | 6 | datatype stm = 7 | SEQ of stm * stm 8 | | LABEL of label 9 | | JUMP of exp * label list 10 | | CJUMP of relop * exp * exp * label * label 11 | | MOVE of exp * exp 12 | | EXP of exp 13 | 14 | and exp = 15 | BINOP of binop * exp * exp 16 | | MEM of exp 17 | | TEMP of Temp.temp 18 | | ESEQ of stm * exp 19 | | NAME of label 20 | | CONST of int 21 | | CALL of exp * exp list 22 | 23 | and binop = 24 | PLUS | MINUS | MUL | DIV | AND | OR | LSHIFT | RSHIFT | ARSHIFT | XOR 25 | 26 | and relop = 27 | EQ | NE | LT | GT | LE | GE | ULT | ULE | UGT | UGE 28 | 29 | fun notRel relop = raise Fail "not implemented" 30 | fun commute relop = raise Fail "not implemented" 31 | 32 | fun seq stms = 33 | case stms of 34 | [] => raise Fail "empty statement list" 35 | | stm :: [] => stm 36 | | stm :: rest => 37 | let 38 | fun loop stms result = 39 | case stms of 40 | [] => result 41 | | stm :: rest => loop rest (SEQ (stm, result)) 42 | in 43 | loop (List.rev rest) stm 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/src/main/scala/linguae/Main.scala: -------------------------------------------------------------------------------- 1 | package linguae 2 | 3 | object Main { 4 | private val operatorTable = Map( 5 | "^" -> Fixity.R(6), 6 | "*" -> Fixity.L(3), 7 | "/" -> Fixity.L(3), 8 | "+" -> Fixity.L(0), 9 | "-" -> Fixity.L(0), 10 | ) 11 | 12 | private val exprs = List( 13 | " 4 + -2 - 1", 14 | " 4 * 2 / 1", 15 | " 1 + 2 * 3", 16 | "4 + 4 * 2 / (1 - 5)", 17 | ) 18 | 19 | def main(args: Array[String]): Unit = { 20 | println() 21 | println("FunctionalShuntingYardParser") 22 | println("----------------------------") 23 | samples(FunctionalShuntingYardParser(operatorTable)) 24 | println() 25 | println("ImperativeShuntingYardParser") 26 | println("----------------------------") 27 | samples(ImperativeShuntingYardParser(operatorTable)) 28 | println() 29 | } 30 | 31 | private def samples(parser: ExprParser): Unit = 32 | exprs.foreach { expr => 33 | println { 34 | expr + " → " + Token 35 | .parser 36 | .consume(expr) 37 | .map(parser.parse) 38 | .toOption 39 | .get 40 | .pretty(operatorTable) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/main.sml: -------------------------------------------------------------------------------- 1 | structure Main = 2 | struct 3 | fun emitproc out (Frame.STRING (lab, s)) = TextIO.output (out, Frame.string (lab, s)) 4 | | emitproc out (Frame.PROC { body, frame }) = 5 | let 6 | val _ = print ("emit " ^ Frame.name frame ^ "\n") 7 | val _ = TreePrinter.print (out, body) 8 | val stms = Canon.linearize body 9 | val _ = app (fn s => TreePrinter.print (out, s)) stms 10 | val stms' = Canon.traceSchedule (Canon.basicBlocks stms) 11 | val instrs = List.concat (map (MipsCodegen.codegen frame) stms') 12 | val format0 = Assem.format Frame.tempName 13 | in 14 | List.app (fn i => TextIO.output (out, format0 i)) instrs 15 | end 16 | 17 | fun withOpenFile fname f = 18 | let 19 | val out = TextIO.openOut fname 20 | in 21 | (f out before TextIO.closeOut out) handle 22 | e => (TextIO.closeOut out ; raise e) 23 | end 24 | 25 | fun compile filename = 26 | let 27 | val absyn = Parse.parse filename 28 | val frags = (EscapeAnalysis.analyse absyn ; Semant.translateProgram absyn) 29 | in 30 | withOpenFile (filename ^ ".s") (fn out => app (emitproc out) frags) 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lingua-012-chatgpt-c++-compiler/readme.md: -------------------------------------------------------------------------------- 1 | # ChatGPT-made Compiler 2 | 3 | A little experiment in understanding the nature of ChatGPT 4 as a tool. 4 | 5 | Most of the code in this project is generated by ChatGPT. I helped it here and 6 | there in order to save on requests (which were capped with ChatGPT 4) or 7 | because the changes were so finicky that it couldn't have gotten it right. 8 | 9 | The whole thing took about 5-6 hours, if I remember correctly. I did it in 10 | April 2023, but my laptop broke at some point and the source I wrote got lost. 11 | What's in this repo is a reconstruction of that code, based on the chat. 12 | 13 | There are two chat sessions in [chats](chats). I had to start a new session in 14 | order to debug an assembly bug. The original seesion got stuck when trying to 15 | guide it to fix the bug and couldn't move forward, but the second chat with a 16 | fresh context managed to spot the problem very quickly. 17 | 18 | Another thing. I don't know much C++, nor assembly, but even considering that 19 | I tried to do this experiment "blindly" without thinking too much about what 20 | ChatGPT was doing. The purpose hasn't necessarily been to write a compiler, but 21 | to understand what ChatGPT was capable of. 22 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/types.sml: -------------------------------------------------------------------------------- 1 | structure Types = 2 | struct 3 | (* 4 | * Each array or record declaration introduces a new type, regardless of 5 | * the structure. The `unique` type is used to encode that by exploiting 6 | * the fact that, in SML, no two `ref` instances are equal. 7 | *) 8 | type unique = unit ref 9 | 10 | (* 11 | * Supported Data Types 12 | *) 13 | datatype ty = 14 | NIL 15 | | INT 16 | | UNIT 17 | | STRING 18 | | NAME of Symbol.symbol * ty option ref 19 | | ARRAY of ty * unique 20 | | RECORD of (Symbol.symbol * ty) list * unique 21 | 22 | fun areEqual types = 23 | case types of 24 | (NIL, NIL) => true 25 | | (NIL, RECORD(_, _)) => true 26 | | (RECORD(_, _), NIL) => true 27 | | (INT, INT) => true 28 | | (UNIT, UNIT) => true 29 | | (STRING, STRING) => true 30 | | (NAME(_, ty1), ty2) => areEqual (Option.valOf (!ty1), ty2) 31 | | (ty1, NAME(_, ty2)) => areEqual (ty1, Option.valOf (!ty2)) 32 | | (ARRAY(_, uniq1), ARRAY(_, uniq2)) => uniq1 = uniq2 33 | | (RECORD(_, uniq1), RECORD(_, uniq2)) => uniq1 = uniq2 34 | | _ => false 35 | 36 | fun actual t = 37 | case t of 38 | NAME(_, ty) => Option.valOf (!ty) 39 | | t => t 40 | end 41 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/mips-register.sml: -------------------------------------------------------------------------------- 1 | structure MipsRegister = 2 | struct 3 | val ZERO = Temp.newTemp () 4 | 5 | (* return value registers *) 6 | val V0 = Temp.newTemp () 7 | val V1 = Temp.newTemp () 8 | 9 | (* argument registers; callee-saved *) 10 | val A0 = Temp.newTemp () 11 | val A1 = Temp.newTemp () 12 | val A2 = Temp.newTemp () 13 | val A3 = Temp.newTemp () 14 | 15 | (* caller-saved registers *) 16 | val T0 = Temp.newTemp () 17 | val T1 = Temp.newTemp () 18 | val T2 = Temp.newTemp () 19 | val T3 = Temp.newTemp () 20 | val T4 = Temp.newTemp () 21 | val T5 = Temp.newTemp () 22 | val T6 = Temp.newTemp () 23 | val T7 = Temp.newTemp () 24 | val T8 = Temp.newTemp () 25 | val T9 = Temp.newTemp () 26 | 27 | (* callee-saved registers *) 28 | val S0 = Temp.newTemp () 29 | val S1 = Temp.newTemp () 30 | val S2 = Temp.newTemp () 31 | val S3 = Temp.newTemp () 32 | val S4 = Temp.newTemp () 33 | val S5 = Temp.newTemp () 34 | val S6 = Temp.newTemp () 35 | val S7 = Temp.newTemp () 36 | 37 | (* stack pointer *) 38 | val SP = Temp.newTemp () 39 | 40 | (* frame pointer; callee-saved *) 41 | val FP = Temp.newTemp () 42 | 43 | (* return address; callee-saved *) 44 | val RA = Temp.newTemp () 45 | end 46 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/main/scala/Constraint.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | 3 | case class Constraint(a: Type, b: Type) 4 | 5 | object Constraint { 6 | import TypedTerm._ 7 | 8 | def collect(typedTerm: TypedTerm): Set[Constraint] = { 9 | typedTerm match { 10 | case INT(ty, value) => Set(Constraint(ty, Type.INT)) 11 | case BOOL(ty, value) => Set(Constraint(ty, Type.BOOL)) 12 | case FUN(ty, param, body) => 13 | collect(body) ++ Set( 14 | Constraint(ty, Type.FUN(param.ty, body.ty)) 15 | ) 16 | case VAR(ty, name) => Set.empty 17 | case APP(ty, fn, arg) => 18 | collect(fn) ++ collect(arg) ++ Set( 19 | Constraint(fn.ty, Type.FUN(arg.ty, ty)) 20 | ) 21 | case IF(ty, testCondition, trueBranch, falseBranch) => 22 | collect(testCondition) ++ collect(trueBranch) ++ collect(falseBranch) ++ Set( 23 | Constraint(testCondition.ty, Type.BOOL), 24 | Constraint(trueBranch.ty, ty), 25 | Constraint(falseBranch.ty, ty) 26 | ) 27 | case LET(ty, binding, value, body) => 28 | collect(value) ++ collect(body) ++ Set( 29 | Constraint(ty, body.ty), 30 | Constraint(binding.ty, value.ty) 31 | ) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/src/test/scala/peval/test/BetterSpecializerSuite.scala: -------------------------------------------------------------------------------- 1 | package peval 2 | package test 3 | 4 | final class BetterSpecializerSuite extends munit.FunSuite { 5 | test("specializes: [power x 3]") { 6 | val source = """ 7 | [def power [x n] 8 | [if [= n 0] 9 | 1 10 | [* x [power x [- n 1]]]]] 11 | 12 | [def main [] 13 | [power x 3]] 14 | """ 15 | 16 | val expected = "[def main [fun [] [* x [* x x]]]]" 17 | 18 | val program = Parser(Reader.read(source)) 19 | val residue = BetterSpecializer.specialize(program) 20 | 21 | assertEquals(residue.program.toString, expected) 22 | } 23 | 24 | test("specializes: [power 3 n] (no stack overflow)") { 25 | val source = """ 26 | [def power [x n] 27 | [if [= n 0] 28 | 1 29 | [* x [power x [- n 1]]]]] 30 | 31 | [def main [] 32 | [power 3 n]] 33 | """ 34 | 35 | val expected = List( 36 | "[def fn-863002692 [fun [n] [if [= n 0] 1 [* 3 [fn-863002692 [- n 1]]]]]]", 37 | "[def main [fun [] [fn-863002692 n]]]", 38 | ) 39 | 40 | val program = Parser(Reader.read(source)) 41 | val residue = BetterSpecializer.specialize(program) 42 | 43 | assertEquals(residue.program.toString, expected.mkString("\n")) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/main/scala/signature/Signature.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | package signature 3 | 4 | import scala.collection.mutable 5 | 6 | object Signature { 7 | def forType(ty: Type): String = { 8 | val varNames = Iterator.from(0).map(nameFromNumber) 9 | val knownVars = mutable.Map.empty[Type.Var, String] 10 | 11 | def traverse(ty: Type): String = { 12 | ty match { 13 | case Type.INT => "int" 14 | case Type.BOOL => "bool" 15 | case Type.VAR(v) => knownVars.getOrElseUpdate(v, varNames.next()) 16 | case Type.FUN(param, ret) => 17 | val paramSignature = traverse(param) 18 | val returnSignature = traverse(ret) 19 | param match { 20 | case _: Type.FUN => s"($paramSignature) -> $returnSignature" 21 | case _ => s"$paramSignature -> $returnSignature" 22 | } 23 | } 24 | } 25 | 26 | traverse(ty) 27 | } 28 | 29 | private def nameFromNumber(counter: Int): String = { 30 | @annotation.tailrec 31 | def recur(counter: Int, suffix: String): String = { 32 | val result = (97 + counter % 26).toChar +: suffix 33 | 34 | if (counter >= 0 && counter <= 25) { 35 | result 36 | } else { 37 | recur(counter / 26 - 1, result) 38 | } 39 | } 40 | 41 | "'" + recur(counter, "") 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/src/main/scala/peval/Main.scala: -------------------------------------------------------------------------------- 1 | package peval 2 | 3 | object Main { 4 | def main(args: Array[String]): Unit = { 5 | println() 6 | println("NAIVE SPECIALIZER") 7 | println("=================") 8 | naive() 9 | println() 10 | println("BETTER SPECIALIZER") 11 | println("==================") 12 | better() 13 | println() 14 | } 15 | 16 | def naive(): Unit = { 17 | val source = getClass.getResourceAsStream("/leesp/exp.leesp") 18 | val program = Parser(Reader.read(source)) 19 | val residue = NaiveSpecializer.specialize(program) 20 | 21 | println() 22 | println("PROGRAM:") 23 | println(program) 24 | println() 25 | println("RESIDUE:") 26 | println(residue) 27 | println() 28 | } 29 | 30 | private def better(): Unit = { 31 | val source = """ 32 | [def power [x n] 33 | [if [= n 0] 34 | 1 35 | [* x [power x [- n 1]]]]] 36 | 37 | [def main [] 38 | [power x 3]] 39 | """ 40 | 41 | val program = Parser(Reader.read(source)) 42 | val residue = BetterSpecializer.specialize(program) 43 | 44 | println() 45 | println("PROGRAM:") 46 | println(program) 47 | println() 48 | println("RESIDUE:") 49 | println(residue.program) 50 | println() 51 | println("LOGS:") 52 | println(residue.logs.reverse.mkString("\n\n")) 53 | println() 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/SwiftML/substitution.swift: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------- // 2 | // SwiftML // 3 | // -------------------------------------------------------------------------- // 4 | 5 | struct Substitution { 6 | let solutions: [Int : Type] 7 | 8 | static let empty = Substitution(solutions: [:]) 9 | 10 | func applyTo(constraints: Set) -> Set { 11 | return Set(constraints.map(applyTo(constraint:))) 12 | } 13 | 14 | func applyTo(constraint: Constraint) -> Constraint { 15 | switch constraint { 16 | case let .Equal(a, b): 17 | return .Equal(applyTo(type: a), applyTo(type: b)) 18 | } 19 | } 20 | 21 | func applyTo(type: Type) -> Type { 22 | return solutions.reduce(type) { (result, solution) in 23 | let (tvar, solutionType) = solution 24 | return result.substitute(tvar: tvar, with: solutionType) 25 | } 26 | } 27 | 28 | func applyTo(term: Term<(A, Type)>) -> Term<(A, Type)> { 29 | return term.mapAttr { (a, type) in (a, applyTo(type: type)) } 30 | } 31 | 32 | func compose(with other: Substitution) -> Substitution { 33 | var substituted = solutions.mapValues { other.applyTo(type: $0) } 34 | 35 | for (tvar, type) in other.solutions { 36 | substituted[tvar] = type 37 | } 38 | 39 | return Substitution(solutions: substituted) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/test/scala/JsCompilerTest.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package test 3 | 4 | import nodes._, visitors._ 5 | 6 | class JsCompilerTest extends FunSuite with Matchers { 7 | val log = logger("InterpreterTest") 8 | 9 | test("compiles function reference application") { 10 | val tree = App(Ref("someFunction"), Num(1)) 11 | val js = tree.accept(JsCompiler)(Trace.empty)._1 12 | js should be("someFunction(1)") 13 | } 14 | 15 | test("compiles function literal application") { 16 | val tree = App(Fun("a", Ref("a")), Num(1)) 17 | val js = tree.accept(JsCompiler)(Trace.empty)._1 18 | js should be("(function(a){return a})(1)") 19 | } 20 | 21 | test("compiles return statement to correct position") { 22 | val tree = Seq(Num(1), Seq(Num(2), Num(3))) 23 | val js = tree.accept(JsCompiler)(Trace(returning = true))._1 24 | js should be("1;2;return 3") 25 | } 26 | 27 | test("compiles let bindings to JS vars") { 28 | val tree = Let("a", Num(1)) { Ref("a") } 29 | val js = tree.accept(JsCompiler)(Trace(returning = true))._1 30 | js should be("var a=1;return a") 31 | } 32 | 33 | ignore("compiles shadowing let bindings to IIFEs") { 34 | val tree = Let("a", Num(1)) { 35 | Let("a", Num(2)) { 36 | Ref("a") 37 | } 38 | } 39 | val js = tree.accept(JsCompiler)(Trace(returning = true))._1 40 | js should be("var a=1;return (function(a){return a})(2)") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/topo-sort.sml: -------------------------------------------------------------------------------- 1 | (** 2 | * Sorts a graph topologically, without ensuring that the graph is acyclic. 3 | *) 4 | structure TopoSort = 5 | struct 6 | open Fn infix 1 |> 7 | 8 | structure G = Graph 9 | structure M = Graph.NodeMap 10 | 11 | fun sort (graph : G.graph) : G.node list = 12 | let 13 | fun fold (node, (result, marked)) = 14 | case M.find (marked, node) of 15 | SOME _ => (result, marked) 16 | | NONE => dfs node marked result 17 | 18 | and dfs node marked result = 19 | let 20 | val nodes = G.succ node 21 | val marked = M.insert (marked, node, true) 22 | val (result, marked) = List.foldl fold (result, marked) nodes 23 | in 24 | (node :: result, marked) 25 | end 26 | 27 | val seed = ([], M.empty) 28 | val nodes = G.nodes graph 29 | in 30 | List.foldl fold seed nodes |> #1 31 | end 32 | 33 | and main () = 34 | let 35 | val graph = G.newGraph () 36 | val [a,b,c,d,e,f,g] = List.tabulate (7, fn _ => Graph.newNode graph) 37 | val _ = List.app (fn (a, b) => G.mkEdge { from = a, to = b }) [ 38 | (a, b), 39 | (a, c), 40 | (a, f), 41 | (d, g), 42 | (d, f), 43 | (d, e), 44 | (f, c), 45 | (g, e), 46 | (g, a), 47 | (d, c), 48 | (b, e) 49 | ] 50 | in 51 | Show.list G.nodename (sort graph) 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/main/scala/Substitution.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | 3 | case class Substitution(solutions: Map[Type.Var, Type]) { 4 | def apply(constraints: Set[Constraint]): Set[Constraint] = { 5 | constraints.map(c => apply(c)) 6 | } 7 | 8 | def apply(constraint: Constraint): Constraint = { 9 | Constraint( 10 | apply(constraint.a), 11 | apply(constraint.b) 12 | ) 13 | } 14 | 15 | def apply(ty: Type): Type = { 16 | solutions.foldLeft(ty) { (result, solution) => 17 | val (tvar, solutionType) = solution 18 | substitute(result, tvar, solutionType) 19 | } 20 | } 21 | 22 | def substitute(ty: Type, tvar: Type.Var, replacement: Type): Type = { 23 | ty match { 24 | case Type.INT => ty 25 | case Type.BOOL => ty 26 | case Type.FUN(paramTy, returnTy) => 27 | Type.FUN( 28 | substitute(paramTy, tvar, replacement), 29 | substitute(returnTy, tvar, replacement) 30 | ) 31 | case Type.VAR(tvar2) => 32 | if (tvar == tvar2) replacement else ty 33 | } 34 | } 35 | 36 | def compose(other: Substitution): Substitution = { 37 | val substitutedThis = solutions.mapValues(s => other.apply(s)) 38 | Substitution(substitutedThis ++ other.solutions) 39 | } 40 | } 41 | 42 | object Substitution { 43 | def empty = Substitution(Map.empty) 44 | 45 | def fromPair(tvar: Type.Var, ty: Type): Substitution = { 46 | Substitution(Map(tvar -> ty)) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/translate.sig: -------------------------------------------------------------------------------- 1 | signature TRANSLATE = 2 | sig 3 | structure Frame : FRAME 4 | 5 | type level 6 | type access 7 | 8 | type frag = Frame.frag 9 | type offset = int 10 | 11 | datatype exp = 12 | Ex of Tree.exp 13 | | Nx of Tree.stm 14 | | Cx of Temp.label * Temp.label -> Tree.stm 15 | 16 | val topLevel : level 17 | val newLevel : { parent : level, name : Temp.label, formals : bool list } -> level 18 | 19 | val formals : level -> access list 20 | val allocLocal : level -> bool -> access 21 | 22 | val unEx : exp -> Tree.exp 23 | val unNx : exp -> Tree.stm 24 | val unCx : exp -> Temp.label * Temp.label -> Tree.stm 25 | 26 | val nilExp : exp 27 | val simpleVar : access * level -> exp 28 | val fieldVar : exp * offset -> exp 29 | val subscriptVar : exp * exp -> exp 30 | val callExp : Temp.label * level * level * exp list -> exp 31 | val opExp : Ast.oper * exp * exp -> exp 32 | val recordExp : exp list -> exp 33 | val seqExp : exp list -> exp 34 | val assignExp : exp * exp -> exp 35 | val ifExp : (exp * exp * exp option) -> exp 36 | val whileExp : (exp * exp * Temp.label) -> exp 37 | val forExp : (exp * exp * exp * Temp.label) -> exp 38 | val letExp : (exp list * exp) -> exp 39 | val arrayExp : (exp * exp) -> exp 40 | val breakExp : Temp.label -> exp 41 | val intExp : int -> exp 42 | val stringExp : string -> exp 43 | 44 | val procEntryExit : { level : level, body : exp } -> unit 45 | val getResult : unit -> frag list 46 | end 47 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/src/test/scala/peval/test/NaiveSpecializerSuite.scala: -------------------------------------------------------------------------------- 1 | package peval 2 | package test 3 | 4 | final class NaiveSpecializerSuite extends munit.FunSuite { 5 | 6 | test("specializes file") { 7 | val program = Parser(Reader.read(getClass.getResourceAsStream("./data/exp.leesp"))) 8 | val residual = NaiveSpecializer.specialize(program) 9 | val expected = Parser(Reader.read("[* x [* x [* x [* x [* x x]]]]]").head) 10 | 11 | assertEquals(residual, expected) 12 | } 13 | 14 | test("specializes: [power x 3]") { 15 | val source = """ 16 | [def power [x n] 17 | [if [= n 0] 18 | 1 19 | [* x [power x [- n 1]]]]] 20 | 21 | [def main [] 22 | [power x 3]] 23 | """ 24 | 25 | val program = Parser(Reader.read(source)) 26 | val residual = NaiveSpecializer.specialize(program) 27 | val expected = Parser(Reader.read("[* x [* x x]]").head) 28 | 29 | assertEquals(residual, expected) 30 | } 31 | 32 | test("overflows the stack: [power 3 n]") { 33 | val source = """ 34 | [def power [x n] 35 | [if [= n 0] 36 | 1 37 | [* x [power x [- n 1]]]]] 38 | 39 | [def main [] 40 | [power 3 n]] 41 | """ 42 | 43 | val program = Parser(Reader.read(source)) 44 | 45 | try { 46 | NaiveSpecializer.specialize(program) 47 | fail("should have overflown the stack") 48 | } catch { 49 | case _: StackOverflowError => () 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lingua-003-tree-interpreter/readme.md: -------------------------------------------------------------------------------- 1 | # A Toy Interpreter 2 | 3 | ``` 4 | $ sbt 5 | > test 6 | [info] InterpreterTest: 7 | [info] - evaluates numbers 8 | [info] - evaluates addition expressions 9 | [info] - evaluates subtraction expressions 10 | [info] - evaluates multiplication expressions 11 | [info] - evaluates division expressions 12 | [info] - evaluates if expressions: false branch 13 | [info] - evaluates if expressions: true branch 14 | [info] - evaluates function expressions 15 | [info] - rejects non-numbers as left operands 16 | [info] - rejects non-numbers as right operands 17 | [info] - rejects non-numbers in condition position in if expressions 18 | [info] - evaluates function application 19 | [info] - rejects non-functions in function application position 20 | [info] - evaluates parameter references 21 | [info] - complains about unbound identifiers 22 | [info] - evaluates let expressions 23 | [info] - supports closures 24 | [info] - functions introduce static, or lexical scope, not dynamic scope 25 | [info] - evaluates two expressions in sequence 26 | [info] - evaluates identifier update expressions 27 | [info] - ensure scope does not leak 28 | [info] - rejects update of an unbound identifier 29 | [info] - evaluates recursive let expressions 30 | [info] Run completed in 175 milliseconds. 31 | [info] Total number of tests run: 23 32 | [info] Suites: completed 1, aborted 0 33 | [info] Tests: succeeded 23, failed 0, canceled 0, ignored 0, pending 0 34 | [info] All tests passed. 35 | [success] Total time: 1 s, completed Dec 20, 2014 3:26:49 PM 36 | ``` 37 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/main/scala/Annotate.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | 3 | object Annotate { 4 | def annotate(term: Term, tenv: TypeEnv): TypedTerm = { 5 | term match { 6 | case INT(value) => TypedTerm.INT(Type.freshVar(), value) 7 | case BOOL(value) => TypedTerm.BOOL(Type.freshVar(), value) 8 | case FUN(param, body) => 9 | val paramTy = Type.freshVar() 10 | val paramBinder = TypedTerm.Binder(paramTy, param) 11 | val extendedTenv = tenv.set(param, paramTy) 12 | TypedTerm.FUN(Type.freshVar(), paramBinder, annotate(body, extendedTenv)) 13 | case VAR(name) => 14 | tenv.get(name) match { 15 | case None => throw new RuntimeException(s"unbound identifier: $name") 16 | case Some(ty) => TypedTerm.VAR(ty, name) 17 | } 18 | case APP(fn, arg) => 19 | TypedTerm.APP(Type.freshVar(), annotate(fn, tenv), annotate(arg, tenv)) 20 | case IF(testCondition, trueBranch, falseBranch) => 21 | TypedTerm.IF( 22 | Type.freshVar(), 23 | annotate(testCondition, tenv), 24 | annotate(trueBranch, tenv), 25 | annotate(falseBranch, tenv) 26 | ) 27 | case LET(binding, value, body) => 28 | val bindingTy = Type.freshVar() 29 | val extendedEnv = tenv.set(binding, bindingTy) 30 | TypedTerm.LET( 31 | Type.freshVar(), 32 | TypedTerm.Binder(bindingTy, binding), 33 | annotate(value, extendedEnv), 34 | annotate(body, extendedEnv) 35 | ) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lingua-003-tree-interpreter/src/main/scala/Store.scala: -------------------------------------------------------------------------------- 1 | package toy 2 | 3 | case class Store(bindings: Map[Int, Store.Cell], locationCount: Int) { 4 | def get(location: Store.Location): Option[Value] = { 5 | bindings.get(location).map(_.value.getOrElse { 6 | throw new IllegalStateException("Store.Cell not bound; this is a bug.") 7 | }) 8 | } 9 | 10 | def set(location: Store.Location, value: Value): Store = { 11 | Store(bindings + (location -> new Store.Cell(Some(value))), locationCount) 12 | } 13 | 14 | def add(value: Value): (Store.Location, Store) = { 15 | val location = locationCount + 1 16 | val newBindings = bindings + (location -> new Store.Cell(Some(value))) 17 | location -> Store(newBindings, location) 18 | } 19 | 20 | def addUnbound: (Store.Location, Store.Cell, Store) = { 21 | val location = locationCount + 1 22 | val cell = new Store.Cell(None) 23 | val newBindings = bindings + (location -> cell) 24 | (location, cell, Store(newBindings, location)) 25 | } 26 | 27 | def gc(old: Store): Store = { 28 | val oldKeys = old.bindings.keys.toSet 29 | val collected = bindings.filterKeys(oldKeys.contains(_)) 30 | Store(collected, locationCount) 31 | } 32 | } 33 | 34 | object Store { 35 | type Location = Int 36 | 37 | class Cell(var value: Option[Value]) { 38 | def bind(value: Value): Unit = { 39 | this.value = Some(value) 40 | } 41 | 42 | override def toString = { 43 | value.map(_.toString).getOrElse("?") 44 | } 45 | } 46 | 47 | def empty = Store(Map.empty, 0) 48 | } 49 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/readme.md: -------------------------------------------------------------------------------- 1 | # Damas-Hindley-Milner in Standard ML 2 | 3 | ### Using SML/NJ: 4 | 5 | ``` 6 | $ sml -Cprint.depth=20 7 | - CM.make "sources.cm"; 8 | - open Terms; 9 | opening Terms 10 | val predef : TypeEnv.ty 11 | val identity : ty 12 | val constant : ty 13 | val compose : ty 14 | val counter : ty 15 | val add10 : ty 16 | val isZero : ty 17 | val letTerm : ty 18 | val letPolymorphism : ty 19 | val closureLetPolymorphism : Term.ty 20 | - 21 | - Infer.typeSignature identity predef; 22 | val it = "forall a. a -> a" : string 23 | - 24 | - Infer.typeSignature constant predef; 25 | val it = "forall ab. a -> b -> a" : string 26 | - 27 | - Infer.typeSignature compose predef; 28 | val it = "forall abc. (c -> b) -> (a -> c) -> a -> b" : string 29 | - 30 | - Infer.typeSignature letPolymorphism predef; 31 | val it = "int" : string 32 | ``` 33 | 34 | ### Using MLton: 35 | 36 | ```bash 37 | $ mlton -output infer sources.mlb 38 | $ ./infer 39 | forall abc. (c -> b) -> (a -> c) -> a -> b 40 | ``` 41 | 42 | ### Corner Case 43 | 44 | ```sml 45 | (* Haskell 46 | 47 | let x1 = \y -> \z -> (z y) y 48 | in let x2 = \z -> x1 (x1 z) 49 | in let x3 = \z -> x2 (x2 z) 50 | in let x4 = \z -> x3 (x3 z) in x4 (\z -> z) 51 | *) 52 | 53 | let 54 | val x1 = fn y => fn z => (z y) y 55 | in 56 | let 57 | val x2 = fn z => x1 (x1 z) 58 | in 59 | let 60 | val x3 = fn z => x2 (x2 z) 61 | in 62 | let 63 | val x4 = fn z => x3 (x3 z) 64 | in 65 | x4 (fn z => z) 66 | end 67 | end 68 | end 69 | end 70 | ``` 71 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/test/scala/UnifierTest.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | package test 3 | 4 | class UnifierTest extends Test { 5 | test("unifies two ints") { 6 | val subst = Unifier.unify(Set( 7 | Constraint(Type.INT, Type.INT) 8 | )) 9 | subst should be(Substitution.empty) 10 | } 11 | 12 | test("unifies two bools") { 13 | val subst = Unifier.unify(Set( 14 | Constraint(Type.BOOL, Type.BOOL) 15 | )) 16 | subst should be(Substitution.empty) 17 | } 18 | 19 | test("unifies two functions") { 20 | val subst = Unifier.unify(Set( 21 | Constraint( 22 | Type.FUN(Type.BOOL, Type.BOOL), 23 | Type.FUN(Type.BOOL, Type.BOOL) 24 | ) 25 | )) 26 | subst should be(Substitution.empty) 27 | } 28 | 29 | test("unifies two variables") { 30 | val subst = Unifier.unify(Set( 31 | Constraint(Type.VAR(1), Type.VAR(2)) 32 | )) 33 | subst should be(Substitution(Map( 34 | 1 -> Type.VAR(2) 35 | ))) 36 | } 37 | 38 | test("unifies variable with non-variable type") { 39 | val subst = Unifier.unify(Set( 40 | Constraint(Type.VAR(1), Type.INT) 41 | )) 42 | subst should be(Substitution(Map( 43 | 1 -> Type.INT 44 | ))) 45 | } 46 | 47 | test("unifies variables in functions") { 48 | val subst = Unifier.unify(Set( 49 | Constraint( 50 | Type.FUN(Type.VAR(1), Type.BOOL), 51 | Type.FUN(Type.INT, Type.VAR(2)) 52 | ) 53 | )) 54 | subst should be(Substitution(Map( 55 | 1 -> Type.INT, 56 | 2 -> Type.BOOL 57 | ))) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/SwiftML/repl.swift: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------- // 2 | // SwiftML // 3 | // -------------------------------------------------------------------------- // 4 | 5 | func repl(prompt: String) { 6 | print(prompt, terminator: "") 7 | 8 | switch readLine() { 9 | case .none, .some(":q"), .some(":quit"): 10 | print("Bye!") 11 | return 12 | case .some(let source) where source.isEmpty: repl(prompt: prompt) 13 | case .some(let source): 14 | switch scanAll(Substring(source)) { 15 | case .Failure(let f): print(f) 16 | case .Success(let tokens): 17 | switch parse(tokens) { 18 | case .Failure(let failure): print("parse error: \(failure)") 19 | case .Success((let term, _)): 20 | switch elaborate(term: term) { 21 | case let .Failure(.Circular(a, b)): print("circular use: \(a) and \(b)") 22 | case let .Failure(.Unbound(id)): print("unbound identifier: \(id)") 23 | case let .Failure(.Conflict(a, b)): print("cannot unify \(a) with \(b)") 24 | case let .Success(typedTerm): 25 | switch typedTerm.eval(env: [:]) { 26 | case let .Failure(failure): print("eval error: \(failure)") 27 | case let .Success(value): print("val it = \(value) : \(typedTerm.attr.1)") 28 | } 29 | } 30 | } 31 | } 32 | 33 | repl(prompt: prompt) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/basis/show.sml: -------------------------------------------------------------------------------- 1 | structure Show : SHOW = 2 | struct 3 | type 'a show = 'a -> string 4 | 5 | fun arrayToList arr = Array.foldr op:: [] arr 6 | fun vectorToList vec = Vector.foldr op:: [] vec 7 | fun comma values = concat (List.interleave ", " values) 8 | fun between a b c = a ^ (comma c) ^ b 9 | fun tuple values = between "(" ")" values 10 | 11 | fun println s = print (s ^ "\n") 12 | 13 | val int = Int.toString 14 | val bool = Bool.toString 15 | val char = Char.toString 16 | val real = Real.toString 17 | val word = Word.toString 18 | val unit = fn _ => "()" 19 | val string = fn s => "\"" ^ s ^ "\"" 20 | 21 | fun list show xs = 22 | between "[" "]" (map show xs) 23 | 24 | fun array show xs = 25 | between "[|" "|]" (map show (arrayToList xs)) 26 | 27 | fun vector show xs = 28 | between "#[" "]" (map show (vectorToList xs)) 29 | 30 | fun option show a = 31 | case a of 32 | NONE => "NONE" 33 | | SOME x => "SOME " ^ show x 34 | 35 | fun tuple2 (sa, sb) (a, b) = 36 | tuple [sa a, sb b] 37 | 38 | fun tuple3 (sa, sb, sc) (a, b, c) = 39 | tuple [sa a, sb b, sc c] 40 | 41 | fun tuple4 (sa, sb, sc, sd) (a, b, c, d) = 42 | tuple [sa a, sb b, sc c, sd d] 43 | 44 | fun tuple5 (sa, sb, sc, sd, se) (a, b, c, d, e) = 45 | tuple [sa a, sb b, sc c, sd d, se e] 46 | 47 | fun tuple6 (sa, sb, sc, sd, se, sf) (a, b, c, d, e, f) = 48 | tuple [sa a, sb b, sc c, sd d, se e, sf f] 49 | 50 | fun tuple7 (sa, sb, sc, sd, se, sf, sg) (a, b, c, d, e, f, g) = 51 | tuple [sa a, sb b, sc c, sd d, se e, sf f, sg g] 52 | end 53 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/build.sbt: -------------------------------------------------------------------------------- 1 | organization := "linguae" 2 | name := "linguae:shunting-yard" 3 | version := "0.1.0" 4 | scalaVersion := "3.1.1" 5 | 6 | // http://tpolecat.github.io/2017/04/25/scalac-flags.html 7 | scalacOptions ++= Seq( 8 | "-deprecation", // Emit warning and location for usages of deprecated APIs. 9 | "-encoding", "utf-8", // Specify character encoding used by source files. 10 | "-feature", // Emit warning and location for usages of features that should be imported explicitly. 11 | "-language:existentials", // Existential types (besides wildcard types) can be written and inferred 12 | "-language:experimental.macros", // Allow macro definition (besides implementation and application) 13 | "-language:higherKinds", // Allow higher-kinded types 14 | "-language:implicitConversions", // Allow definition of implicit functions called views 15 | "-unchecked", // Enable additional warnings where generated code depends on assumptions. 16 | "-Xfatal-warnings", // Fail the compilation if there are any warnings. 17 | ) 18 | 19 | Compile / console / scalacOptions --= Seq( 20 | "-Ywarn-unused:imports", 21 | "-Xfatal-warnings", 22 | ) 23 | 24 | libraryDependencies ++= Seq( 25 | "org.typelevel" %% "cats-core" % "2.7.0", 26 | ) 27 | 28 | libraryDependencies ++= Seq( 29 | "org.scalameta" %% "munit" % "1.0.0-M3" % Test 30 | ) 31 | 32 | consoleQuick / initialCommands := """ 33 | import cats._ 34 | import cats.data._ 35 | import cats.implicits._ 36 | """ 37 | 38 | val root = Project("shunting-yard", file(".")) 39 | -------------------------------------------------------------------------------- /lingua-011-bidirectional-typechecking/build.sbt: -------------------------------------------------------------------------------- 1 | organization := "linguae" 2 | name := "linguae:bitype" 3 | version := "0.1.0" 4 | scalaVersion := "3.4.1" 5 | 6 | // http://tpolecat.github.io/2017/04/25/scalac-flags.html 7 | scalacOptions ++= Seq( 8 | "-deprecation", // Emit warning and location for usages of deprecated APIs. 9 | "-encoding", "utf-8", // Specify character encoding used by source files. 10 | "-feature", // Emit warning and location for usages of features that should be imported explicitly. 11 | "-language:existentials", // Existential types (besides wildcard types) can be written and inferred 12 | "-language:experimental.macros", // Allow macro definition (besides implementation and application) 13 | "-language:higherKinds", // Allow higher-kinded types 14 | "-language:implicitConversions", // Allow definition of implicit functions called views 15 | "-unchecked", // Enable additional warnings where generated code depends on assumptions. 16 | "-Xfatal-warnings", // Fail the compilation if there are any warnings. 17 | ) 18 | 19 | Compile / console / scalacOptions --= Seq( 20 | "-Ywarn-unused:imports", 21 | "-Xfatal-warnings", 22 | ) 23 | 24 | libraryDependencies ++= Seq( 25 | "org.typelevel" %% "cats-core" % "2.10.0", 26 | ) 27 | 28 | libraryDependencies ++= Seq( 29 | "org.scalameta" %% "munit" % "1.0.0-M11" % Test 30 | ) 31 | 32 | consoleQuick / initialCommands := """ 33 | import cats._ 34 | import cats.data._ 35 | import cats.implicits._ 36 | """ 37 | 38 | val root = Project("bitype", file(".")) 39 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/canon.sig: -------------------------------------------------------------------------------- 1 | signature CANON = 2 | sig 3 | (* 4 | * From an arbitrary Tree statement, produce a list of cleaned trees 5 | * satisfying the following properties: 6 | * 7 | * 1. No `SEQ`s or `ESEQ`s 8 | * 2. The parent of every `CALL` is an `EXP` or a `MOVE (TEMP t, ...)` 9 | *) 10 | val linearize : Tree.stm -> Tree.stm list 11 | 12 | (* 13 | * From a list of cleaned trees, produce a list of basic blocks satisfying 14 | * the following properties: 15 | * 16 | * 1. No `SEQ`s or `ESEQ`s 17 | * 2. The parent of every `CALL` is an `EXP` or a `MOVE (TEMP t, ...)` 18 | * 3. Every block begins with a `LABEL` 19 | * 4. A `LABEL` appears only at the beginning of a block 20 | * 5. Any `JUMP` or `CJUMP` is the last stm in a block 21 | * 6. Every block ends with a `JUMP` or `CJUMP` 22 | * 23 | * Also produce the label to which control will be passed upon exit. 24 | *) 25 | val basicBlocks : Tree.stm list -> (Tree.stm list list * Tree.label) 26 | 27 | (* 28 | * From a list of basic blocks satisfying properties 1-6, along with an 29 | * exit label, produce a list of stms such that: 30 | * 31 | * 1. No `SEQ`s or `ESEQ`s 32 | * 2. The parent of every `CALL` is an `EXP` or a `MOVE (TEMP t, ...)` 33 | * 3. Every `CJUMP (_, t, f)` is immediately followed by `LABEL f` 34 | * 35 | * The blocks are reordered to satisfy property 7; also in this reordering 36 | * as many `JUMP (T.NAME lab)` statements as possible are eliminated by 37 | * falling through into `T.LABEL lab`. 38 | *) 39 | val traceSchedule : Tree.stm list list * Tree.label -> Tree.stm list 40 | end 41 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/type.sml: -------------------------------------------------------------------------------- 1 | structure Type = 2 | struct 3 | structure Var = 4 | struct 5 | type ty = int 6 | 7 | structure Key : ORD_KEY = 8 | struct 9 | type ord_key = ty 10 | val compare = Int.compare 11 | end 12 | end 13 | 14 | datatype ty = 15 | INT 16 | | BOOL 17 | | VAR of Var.ty 18 | | FUN of ty * ty 19 | 20 | fun substitute ty tvar replacement = 21 | case ty of 22 | INT => ty 23 | | BOOL => ty 24 | | VAR candidate => if tvar = candidate then replacement else ty 25 | | FUN (paramTy, returnTy) => 26 | FUN ( 27 | substitute paramTy tvar replacement, 28 | substitute returnTy tvar replacement 29 | ) 30 | 31 | (** 32 | * Obtain free type variables from within the given type. 33 | *) 34 | fun freeVars ty = 35 | case ty of 36 | INT => [] 37 | | BOOL => [] 38 | | VAR (var) => [var] 39 | | FUN (p, r) => (freeVars p) @ (freeVars r) 40 | 41 | fun containsVar ty v = 42 | case ty of 43 | INT => false 44 | | BOOL => false 45 | | VAR v' => v = v' 46 | | FUN (param, return) => containsVar param v orelse containsVar return v 47 | 48 | local 49 | val counter = ref 0 50 | fun increment r = !r before r := !r + 1 51 | in 52 | fun freshVar () = VAR (increment counter) 53 | fun resetFreshness () = counter := 0 54 | end 55 | 56 | fun toString INT = "int" 57 | | toString BOOL = "bool" 58 | | toString (VAR v) = "a" ^ Int.toString v 59 | | toString (FUN (p as FUN _, r)) = "(" ^ toString p ^ ") -> " ^ toString r 60 | | toString (FUN (p, r)) = toString p ^ " -> " ^ toString r 61 | end 62 | -------------------------------------------------------------------------------- /lingua-000-tiger/02-lexical-analysis/Lexer.sml: -------------------------------------------------------------------------------- 1 | signature LEXER = 2 | sig 3 | exception Error of int * string 4 | 5 | val stringBuffer : string ref 6 | val commentNesting : int ref 7 | val anyErrors : bool ref 8 | val fileName : string ref 9 | val lineNum : int ref 10 | val linePos : int list ref 11 | val sourceStream : TextIO.instream ref 12 | val error : int -> string -> unit 13 | val impossible : string -> unit 14 | val reset : unit -> unit 15 | end 16 | 17 | structure Lexer : LEXER = 18 | struct 19 | exception Error of int * string 20 | 21 | val stringBuffer = ref "" 22 | val commentNesting = ref 0 23 | val anyErrors = ref false 24 | val fileName = ref "" 25 | val lineNum = ref 1 26 | val linePos = ref [1] 27 | val sourceStream = ref TextIO.stdIn 28 | 29 | fun reset () = ( 30 | stringBuffer := ""; 31 | commentNesting := 0; 32 | anyErrors := false; 33 | fileName := ""; 34 | lineNum := 1; 35 | linePos := [1]; 36 | sourceStream := TextIO.stdIn 37 | ) 38 | 39 | fun error pos (msg: string) = 40 | let 41 | fun look (a :: rest, n) = 42 | if a < pos then 43 | app print [":", Int.toString n, ".", Int.toString (pos - a)] 44 | else 45 | look (rest, n - 1) 46 | | look _ = print "0.0" 47 | in 48 | anyErrors := true; 49 | print (!fileName); 50 | look(!linePos, !lineNum); 51 | print ":"; 52 | print msg; 53 | print "\n" 54 | end 55 | 56 | fun impossible msg = ( 57 | app print ["Error: Compiler bug: ",msg,"\n"]; 58 | TextIO.flushOut TextIO.stdOut 59 | ) 60 | end 61 | -------------------------------------------------------------------------------- /lingua-000-tiger/02-lexical-analysis/merge.tig: -------------------------------------------------------------------------------- 1 | let 2 | 3 | type any = {any : int} 4 | var buffer := getchar() 5 | 6 | function readint(any: any) : int = 7 | let var i := 0 8 | function isdigit(s : string) : int = 9 | ord(buffer)>=ord("0") & ord(buffer)<=ord("9") 10 | function skipto() = 11 | while buffer=" " | buffer="\n" 12 | do buffer := getchar() 13 | in skipto(); 14 | any.any := isdigit(buffer); 15 | while isdigit(buffer) 16 | do (i := i*10+ord(buffer)-ord("0"); buffer := getchar()); 17 | i 18 | end 19 | 20 | type list = {first: int, rest: list} 21 | 22 | function readlist() : list = 23 | let var any := any{any=0} 24 | var i := readint(any) 25 | in if any.any 26 | then list{first=i,rest=readlist()} 27 | else nil 28 | end 29 | 30 | function merge(a: list, b: list) : list = 31 | if a=nil then b 32 | else if b=nil then a 33 | else if a.first < b.first 34 | then list{first=a.first,rest=merge(a.rest,b)} 35 | else list{first=b.first,rest=merge(a,b.rest)} 36 | 37 | function printint(i: int) = 38 | let function f(i:int) = if i>0 39 | then (f(i/10); print(chr(i-i/10*10+ord("0")))) 40 | in if i<0 then (print("-"); f(-i)) 41 | else if i>0 then f(i) 42 | else print("0") 43 | end 44 | 45 | function printlist(l: list) = 46 | if l=nil then print("\n") 47 | else (printint(l.first); print(" "); printlist(l.rest)) 48 | 49 | var list1 := readlist() 50 | var list2 := (buffer:=getchar(); readlist()) 51 | 52 | 53 | /* BODY OF MAIN PROGRAM */ 54 | in printlist(merge(list1,list2)) 55 | end 56 | 57 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/env.sml: -------------------------------------------------------------------------------- 1 | structure Env : ENV = 2 | struct 3 | type ty = Types.ty 4 | 5 | datatype enventry = 6 | VarEntry of { 7 | access : Translate.access, 8 | ty : ty 9 | } 10 | | FunEntry of { 11 | level : Translate.level, 12 | label : Temp.label, 13 | formals : ty list, 14 | result : ty 15 | } 16 | 17 | val quux = Types.RECORD([ 18 | (Symbol.symbol "foo", Types.INT), 19 | (Symbol.symbol "bar", Types.STRING) 20 | ], ref ()) 21 | 22 | val base_tenv = 23 | let 24 | val tenv0 = Symbol.empty 25 | val tenv1 = Symbol.set tenv0 (Symbol.symbol "nil") Types.NIL 26 | val tenv2 = Symbol.set tenv1 (Symbol.symbol "unit") Types.UNIT 27 | val tenv3 = Symbol.set tenv2 (Symbol.symbol "int") Types.INT 28 | val tenv4 = Symbol.set tenv3 (Symbol.symbol "string") Types.STRING 29 | val tenv5 = Symbol.set tenv4 (Symbol.symbol "quux") quux 30 | in 31 | tenv5 32 | end 33 | 34 | val base_venv = 35 | let 36 | val venv0 = Symbol.empty 37 | val venv1 = Symbol.set venv0 (Symbol.symbol "print") (FunEntry { 38 | level = Translate.topLevel, 39 | label = Temp.newLabel (), 40 | formals = [Types.STRING], 41 | result = Types.UNIT 42 | }) 43 | val venv2 = Symbol.set venv1 (Symbol.symbol "q") (VarEntry { 44 | ty = quux, 45 | access = Translate.allocLocal Translate.topLevel true 46 | }) 47 | val venv3 = Symbol.set venv2 (Symbol.symbol "arr") (VarEntry { 48 | ty = Types.ARRAY(Types.STRING, ref ()), 49 | access = Translate.allocLocal Translate.topLevel true 50 | }) 51 | in 52 | venv3 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /lingua-010-jit-hello-world-apple-silicon/jitted.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // 10 | // Grab disassembly using: 11 | // 12 | // ```bash 13 | // gcc -xc -c -o- - < string 52 | end 53 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/type-env.fun: -------------------------------------------------------------------------------- 1 | signature TYPE_ENV_FN_DEPS = 2 | sig 3 | structure TermMap : ORD_MAP where type Key.ord_key = Term.Var.ty 4 | structure TypeSet : ORD_SET where type Key.ord_key = Type.Var.ty 5 | end 6 | 7 | functor TypeEnvFn (Deps : TYPE_ENV_FN_DEPS) :> TYPE_ENV = 8 | struct 9 | structure Map = Deps.TermMap 10 | structure Set = Deps.TypeSet 11 | 12 | type ty = TypeScheme.ty Map.map 13 | 14 | val empty = Map.empty 15 | 16 | fun get tenv var = Map.find (tenv, var) 17 | 18 | fun set tenv var ty = Map.insert (tenv, var, ty) 19 | 20 | fun fromList bindings = 21 | let 22 | fun insert ((binding, value), env) = set env binding value 23 | in 24 | List.foldl insert empty bindings 25 | end 26 | 27 | fun freeVars tenv = 28 | List.concat (Map.listItems (Map.map TypeScheme.freeVars tenv)) 29 | 30 | fun generalize tenv ty = 31 | let 32 | val tyVars = Set.fromList (Type.freeVars ty) 33 | val envVars = Set.fromList (freeVars tenv) 34 | val schemeVars = Set.listItems (Set.difference (tyVars, envVars)) 35 | in 36 | TypeScheme.FORALL (schemeVars, ty) 37 | end 38 | 39 | fun substitute tenv subst = 40 | let 41 | fun substTypeScheme typeScheme = 42 | case typeScheme of 43 | TypeScheme.SVAR _ => typeScheme 44 | (* XXX: It might not be ok to substitute bound type variables... *) 45 | | TypeScheme.FORALL (vars, ty) => TypeScheme.FORALL (vars, Subst.apply subst ty) 46 | in 47 | Map.map substTypeScheme tenv 48 | end 49 | 50 | fun toString tenv = 51 | let 52 | open Show 53 | val pair = tuple2 (fn a => a, TypeScheme.toString) 54 | in 55 | list pair (Map.listItemsi tenv) 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/assem.sml: -------------------------------------------------------------------------------- 1 | structure Assem = 2 | struct 3 | infix 1 |> 4 | 5 | open Fn 6 | 7 | type reg = string 8 | type temp = Temp.temp 9 | type label = Temp.label 10 | 11 | datatype instr = 12 | OPER of { 13 | assem : string, 14 | src : temp list, 15 | dst : temp list, 16 | jump : label list option 17 | } 18 | | LABEL of { 19 | assem : string, 20 | lab : Temp.label 21 | } 22 | | MOVE of { 23 | assem : string, 24 | dst : temp, 25 | src : temp 26 | } 27 | 28 | fun format saytemp = 29 | let 30 | val saylab = Symbol.name 31 | (** 32 | * Replaces `s, `d and `j placeholders with values calculated by in the 33 | * child expressions. 34 | *) 35 | fun speak (assem, dst, src, jump) = 36 | let 37 | fun replace instruction = 38 | case instruction of 39 | #"`" :: #"s" :: i :: rest => explode (saytemp (List.nth (src, ord i - ord #"0"))) @ replace rest 40 | | #"`" :: #"d" :: i :: rest => explode (saytemp (List.nth (dst, ord i - ord #"0"))) @ replace rest 41 | | #"`" :: #"j" :: i :: rest => explode (saylab (List.nth (jump, ord i - ord #"0"))) @ replace rest 42 | | #"`" :: #"`" :: rest => #"`" :: replace rest 43 | | #"`" :: _ :: rest => raise Fail "bad assem format" 44 | | c :: rest => c :: replace rest 45 | | [] => [] 46 | in 47 | assem |> explode |> replace |> implode 48 | end 49 | in 50 | fn OPER { assem, dst, src, jump } => speak (assem, dst, src, Option.getOpt (jump, [])) 51 | | LABEL { assem, ... } => assem 52 | | MOVE { assem, dst, src } => speak (assem, [dst], [src], []) 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/main/scala/Unifier.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | 3 | object Unifier { 4 | def unify(constraints: Set[Constraint]): Substitution = { 5 | if (constraints.isEmpty) { 6 | Substitution.empty 7 | } else { 8 | val subst: Substitution = unifyOne(constraints.head) 9 | val substitutedTail = subst.apply(constraints.tail) 10 | val substTail: Substitution = unify(substitutedTail) 11 | subst.compose(substTail) 12 | } 13 | } 14 | 15 | def unifyOne(constraint: Constraint): Substitution = { 16 | (constraint.a, constraint.b) match { 17 | case (Type.INT, Type.INT) => Substitution.empty 18 | case (Type.BOOL, Type.BOOL) => Substitution.empty 19 | case (Type.FUN(param1, return1), Type.FUN(param2, return2)) => 20 | unify(Set( 21 | Constraint(param1, param2), 22 | Constraint(return1, return2) 23 | )) 24 | case (Type.VAR(tvar), ty) => unifyVar(tvar, ty) 25 | case (ty, Type.VAR(tvar)) => unifyVar(tvar, ty) 26 | case (a, b) => throw new RuntimeException(s"cannot unify $a with $b") 27 | } 28 | } 29 | 30 | def unifyVar(tvar: Type.Var, ty: Type): Substitution = { 31 | ty match { 32 | case Type.VAR(tvar2) if tvar == tvar2 => Substitution.empty 33 | case Type.VAR(_) => Substitution.fromPair(tvar, ty) 34 | case ty if occurs(tvar, ty) => 35 | throw new RuntimeException(s"circular use: $tvar occurs in $ty") 36 | case ty => Substitution.fromPair(tvar, ty) 37 | } 38 | } 39 | 40 | def occurs(tvar: Type.Var, ty: Type): Boolean = { 41 | ty match { 42 | case Type.FUN(p, r) => occurs(tvar, p) || occurs(tvar, r) 43 | case Type.VAR(tvar2) => tvar == tvar2 44 | case _ => false 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/project/build.scala: -------------------------------------------------------------------------------- 1 | import sbt._, Keys._ 2 | 3 | import net.virtualvoid.sbt.graph.Plugin.graphSettings 4 | 5 | object Build extends Build { 6 | val root = Project( 7 | id = "lingua-001", 8 | base = file("."), 9 | settings = graphSettings ++ Seq( 10 | name := "lingua-001", 11 | organization := "ro.igstan", 12 | version := "0.1.0", 13 | scalaVersion := "2.11.1", 14 | crossPaths := false, 15 | // http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/javac.html#xlintwarnings 16 | javacOptions ++= Seq("-Xlint:unchecked", "-Xlint:deprecation"), 17 | scalacOptions ++= Seq( 18 | "-feature", 19 | "-unchecked", 20 | "-deprecation", 21 | "-Yno-adapted-args", 22 | "-language:implicitConversions", 23 | "-language:higherKinds" 24 | ), 25 | libraryDependencies ++= Seq( 26 | "org.slf4j" % "slf4j-api" % "1.7.7", 27 | "org.slf4j" % "jcl-over-slf4j" % "1.7.7", 28 | "org.slf4j" % "jul-to-slf4j" % "1.7.7", 29 | "org.slf4j" % "log4j-over-slf4j" % "1.7.7", 30 | "ch.qos.logback" % "logback-classic" % "1.1.2", 31 | "ch.qos.logback" % "logback-core" % "1.1.2", 32 | "org.scalatest" %% "scalatest" % "2.1.7" % "test" 33 | ), 34 | testOptions ++= Seq( 35 | // Avoid "substitute logger" warning from SLF4J when running tests in 36 | // parallel. See also: stackoverflow.com/questions/7898273#12095245. 37 | Tests.Setup { cl => 38 | cl.loadClass("org.slf4j.LoggerFactory") 39 | .getMethod("getLogger", cl.loadClass("java.lang.String")) 40 | .invoke(null, "ROOT") 41 | } 42 | ) 43 | ) 44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /lingua-013-pattern-match-compiler/src/naive-matcher.sml: -------------------------------------------------------------------------------- 1 | (*) Described in §3 of the paper. 2 | structure NaiveMatcher = 3 | struct 4 | open Common 5 | 6 | fun main origobj allmrules = 7 | let 8 | fun fail [] = NONE 9 | | fail ((pat1, rhs1) :: rulerest) = match pat1 origobj [] rhs1 rulerest 10 | 11 | and succeed work rhs rules = 12 | case work of 13 | | [] => SOME rhs 14 | | ([], []) :: workr => succeed workr rhs rules 15 | | (pat1 :: patr, obj1 :: objr) :: workr => match pat1 obj1 ((patr, objr) :: workr) rhs rules 16 | | _ => raise Fail "impossible: work" 17 | 18 | and match pattern object work rhs rules = 19 | case pattern of 20 | | PVar _ => succeed work rhs rules 21 | | PCon (pcon, pargs) => 22 | case object of 23 | | PVar _ => raise Fail "impossible: PVar" 24 | | PCon (ocon, oargs) => 25 | if ocon = pcon 26 | then succeed ((pargs, oargs) :: work) rhs rules 27 | else fail rules 28 | in 29 | fail allmrules 30 | end 31 | 32 | fun test () = 33 | let 34 | val null = PCon ({ name = "null", arity = 0, span = 2 }, []) 35 | fun cons a b = PCon ({ name = "cons", arity = 2, span = 2 }, [a, b]) 36 | in 37 | (*) So... this is a bit unusual because the strutinee is a pattern 38 | (*) too, whereas it should be a value. 39 | main (cons null (PVar "rest")) [ 40 | (null, 1), 41 | (cons null (PVar "rest"), 2), 42 | (cons (PVar "head") (PVar "rest"), 3) 43 | ] 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/src/test/scala/peval/test/ReaderSuite.scala: -------------------------------------------------------------------------------- 1 | package peval 2 | package test 3 | 4 | final class ReaderSuite extends munit.FunSuite { 5 | test("[") { 6 | intercept[UnbalancedParenL](Reader.read("[")) 7 | } 8 | 9 | test("]") { 10 | intercept[UnbalancedParenR](Reader.read("]")) 11 | } 12 | 13 | test("atom") { 14 | val result = Reader.read("atom") 15 | assertEquals(result, List(ATOM("atom"))) 16 | } 17 | 18 | test("atom 1234") { 19 | val result = Reader.read("atom 1234") 20 | assertEquals(result, List(ATOM("atom"), ATOM("1234"))) 21 | } 22 | 23 | test("[atom]") { 24 | val result = Reader.read("[atom]") 25 | assertEquals(result, List(LIST(ATOM("atom")))) 26 | } 27 | 28 | test("[[atom] atom]") { 29 | val result = Reader.read("[[atom] atom]") 30 | assertEquals(result, List(LIST(LIST(ATOM("atom")), ATOM("atom")))) 31 | } 32 | 33 | test("[atom [atom]]") { 34 | val result = Reader.read("[atom [atom]]") 35 | assertEquals(result, List(LIST(ATOM("atom"), LIST(ATOM("atom"))))) 36 | } 37 | 38 | test("[atom [atom]] multiline") { 39 | val result = Reader.read(""" 40 | [atom 41 | [atom]] 42 | """) 43 | 44 | assertEquals(result, List(LIST(ATOM("atom"), LIST(ATOM("atom"))))) 45 | } 46 | 47 | test("allows comments") { 48 | val result = Reader.read(""" 49 | ; comments are supported 50 | [atom 51 | ; here too 52 | [atom] 53 | ; as well as here 54 | ] 55 | """) 56 | 57 | assertEquals(result, List(LIST(ATOM("atom"), LIST(ATOM("atom"))))) 58 | } 59 | 60 | test("reads from stream") { 61 | val result = Reader.read(getClass.getResourceAsStream("./data/test.leesp")) 62 | assertEquals(result, List(LIST(ATOM("atom"), LIST(ATOM("atom"))))) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/test/scala/SubstitutionTest.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | package test 3 | 4 | class SubstitutionTest extends Test { 5 | test("substitutes standalone type variable") { 6 | val subst = Substitution.fromPair(1, Type.INT) 7 | subst.apply(Type.VAR(1)) should be(Type.INT) 8 | } 9 | 10 | test("substitutes type variable in functions") { 11 | val subst = Substitution(Map( 12 | 1 -> Type.INT, 13 | 2 -> Type.BOOL 14 | )) 15 | subst.apply(Type.FUN(Type.VAR(1), Type.VAR(2))) should be(Type.FUN(Type.INT, Type.BOOL)) 16 | } 17 | 18 | test("substitutes constraint") { 19 | val subst = Substitution(Map( 20 | 1 -> Type.INT, 21 | 2 -> Type.BOOL 22 | )) 23 | subst.apply(Constraint(Type.VAR(1), Type.VAR(2))) should be(Constraint(Type.INT, Type.BOOL)) 24 | } 25 | 26 | test("substitutes constraint set") { 27 | val subst = Substitution(Map( 28 | 1 -> Type.INT, 29 | 2 -> Type.BOOL, 30 | 3 -> Type.FUN(Type.INT, Type.BOOL) 31 | )) 32 | val constraints = Set( 33 | Constraint(Type.VAR(1), Type.VAR(2)), 34 | Constraint(Type.VAR(2), Type.VAR(3)) 35 | ) 36 | subst.apply(constraints) should be(Set( 37 | Constraint(Type.INT, Type.BOOL), 38 | Constraint(Type.BOOL, Type.FUN(Type.INT, Type.BOOL)) 39 | )) 40 | } 41 | 42 | test("composes") { 43 | val substA = Substitution(Map( 44 | 3 -> Type.VAR(1), 45 | 2 -> Type.INT, 46 | 4 -> Type.FUN(Type.VAR(1), Type.VAR(2)) 47 | )) 48 | val substB = Substitution(Map( 49 | 1 -> Type.INT, 50 | 2 -> Type.BOOL 51 | )) 52 | 53 | substA.compose(substB) should be(Substitution(Map( 54 | 1 -> Type.INT, 55 | 2 -> Type.BOOL, // variable in substB overrides that in substA 56 | 3 -> Type.INT, 57 | 4 -> Type.FUN(Type.INT, Type.BOOL) 58 | ))) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lingua-013-pattern-match-compiler/readme.md: -------------------------------------------------------------------------------- 1 | # Pattern Match Compiler 2 | 3 | A reconstruction of the pattern match compiler presented in [ML pattern match 4 | compilation and partial evaluation][paper]. 5 | 6 | ## Version 1: Naive Matcher 7 | 8 | ``` 9 | - CM.make "lib.cm"; NaiveMatcher.test (); 10 | val it = true : bool 11 | val it = SOME 2 : int option 12 | ``` 13 | 14 | ## Version 2: Instrumented Matcher 15 | 16 | ``` 17 | - CM.make "lib.cm"; InstrumentedMatcher.test (); 18 | val it = true : bool 19 | val it = SOME 2 : int option 20 | ``` 21 | 22 | ## Version 3: Match Compiler 23 | 24 | ``` 25 | - CM.make "lib.cm"; MatchCompiler.test (); 26 | val it = true : bool 27 | 28 | WHEN: Obj.1 = True 29 | THEN: 30 | WHEN: Obj.2 = Green 31 | THEN: SUCCESS: 1 32 | ELSE: FAILURE 33 | ELSE: 34 | WHEN: Obj.2 = Green 35 | THEN: SUCCESS: 2 36 | ELSE: 37 | WHEN: Obj.2 = Red 38 | THEN: SUCCESS: 3 39 | ELSE: SUCCESS: 4 40 | 41 | WHEN: Obj.1 = True 42 | THEN: 43 | WHEN: Obj.2 = Green 44 | THEN: SUCCESS: 1 45 | ELSE: 46 | WHEN: Obj.2 = Blue 47 | THEN: SUCCESS: 4 48 | ELSE: FAILURE 49 | ELSE: 50 | WHEN: Obj.2 = Green 51 | THEN: SUCCESS: 2 52 | ELSE: 53 | WHEN: Obj.2 = Red 54 | THEN: SUCCESS: 3 55 | ELSE: FAILURE 56 | val it = () : unit 57 | ``` 58 | 59 | ## Notes 60 | 61 | The code uses Successor ML features, such as leading vertical bars and 62 | single line comments. 63 | 64 | Code was run using these SML/NJ options, of which the mandatory one is just 65 | `-Cparser.succ-ml=true`: 66 | 67 | ``` 68 | sml \ 69 | -Cprint.length=100 \ 70 | -Cprint.depth=20 \ 71 | -Ccontrol.poly-eq-warn=false \ 72 | -Cprint.signatures=2 \ 73 | -Cparser.succ-ml=true \ 74 | -Cparser.secondary-prompt='… ' \ 75 | -Cparser.quotations=true \ 76 | -Ctdp.instrument=true \ 77 | '$smlnj-tdp/back-trace.cm' 78 | ``` 79 | 80 | [paper]: ./doc/ml-pattern-match-compilation-and-partial-evaluation.pdf 81 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/basis/list.sml: -------------------------------------------------------------------------------- 1 | structure List : LIST = 2 | struct 3 | open List 4 | 5 | val head = hd 6 | val tail = tl 7 | 8 | fun cons x xs = x :: xs 9 | 10 | fun snoc x xs = xs @ [x] 11 | 12 | fun takeWhile predicate xs = 13 | let 14 | fun recur xs result = 15 | case xs of 16 | [] => rev result 17 | | x :: xs => if predicate x then recur xs (x :: result) else rev result 18 | in 19 | recur xs [] 20 | end 21 | 22 | fun dropWhile predicate xs = 23 | case xs of 24 | [] => [] 25 | | x :: rest => if predicate x then dropWhile predicate rest else xs 26 | 27 | fun headOption xs = case xs of [] => NONE | x :: _ => SOME x 28 | 29 | fun tailOption xs = case xs of [] => NONE | _ :: xs => SOME xs 30 | 31 | fun initLastOption xs = 32 | let 33 | fun recur xs result = 34 | case xs of 35 | [] => NONE 36 | | x :: [] => SOME (rev result, x) 37 | | x :: xs => recur xs (x :: result) 38 | in 39 | recur xs [] 40 | end 41 | 42 | fun initOption xs = 43 | Option.map #1 (initLastOption xs) 44 | 45 | fun lastOption xs = 46 | case xs of 47 | [] => NONE 48 | | x :: [] => SOME x 49 | | x :: xs => lastOption xs 50 | 51 | fun interleave i l = 52 | let 53 | fun recur [] acc = rev acc 54 | | recur (x :: []) acc = recur [] (x :: acc) 55 | | recur (x :: xs) acc = recur xs (i :: x :: acc) 56 | in 57 | recur l [] 58 | end 59 | 60 | local 61 | open Tuples 62 | 63 | fun prepend xs x = x :: xs 64 | fun folder mapFolder (x, (result, acc)) = 65 | Tuple2.map1 (prepend result) (mapFolder (x, acc)) 66 | in 67 | fun mapFoldl mapFolder seed xs = 68 | Tuple2.map1 rev (foldl (folder mapFolder) ([], seed) xs) 69 | 70 | fun mapFoldr mapFolder seed xs = 71 | foldr (folder mapFolder) ([], seed) xs 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/constraint.sml: -------------------------------------------------------------------------------- 1 | structure Constraint = 2 | struct 3 | datatype ty = 4 | EQ of Type.ty * Type.ty 5 | | GEN of TypeEnv.ty * TypeScheme.ty * Type.ty 6 | | INST of TypeScheme.Var.ty * Type.ty 7 | 8 | fun isEQ (EQ _) = true 9 | | isEQ _ = false 10 | 11 | fun isINST (TypeScheme.SVAR tsVarA) (INST (tsVarB, _)) = tsVarA = tsVarB 12 | | isINST _ _ = false 13 | 14 | fun substitute constraints subst = 15 | let 16 | fun substitute constraint = 17 | case constraint of 18 | EQ (tyA, tyB) => 19 | EQ (Subst.apply subst tyA, Subst.apply subst tyB) 20 | | GEN (tenv, typeScheme, ty) => 21 | GEN (TypeEnv.substitute tenv subst, typeScheme, Subst.apply subst ty) 22 | | INST (typeScheme, ty) => 23 | INST (typeScheme, Subst.apply subst ty) 24 | in 25 | List.map substitute constraints 26 | end 27 | 28 | (** 29 | * Instantiate a list of INST constraints based on a type environment. 30 | *) 31 | fun instantiate constraints tenv ty = 32 | let 33 | val gen = TypeEnv.generalize tenv ty 34 | fun loop constraints = 35 | case constraints of 36 | [] => [] 37 | | INST (_, ty) :: tail => 38 | let 39 | val instTy = TypeScheme.instantiate gen 40 | val constrs = loop tail 41 | in 42 | EQ (ty, instTy) :: constrs 43 | end 44 | | _ => raise Fail "Bug: bad constraint type in `instantiate`." 45 | in 46 | loop constraints 47 | end 48 | 49 | fun toString constraint = 50 | let 51 | open Show 52 | in 53 | case constraint of 54 | EQ (a, b) => "EQ " ^ (tuple2 (Type.toString, Type.toString) (a, b)) 55 | | GEN (_, b, c) => "GEN " ^ (tuple2 (TypeScheme.toString, Type.toString) (b, c)) 56 | | INST (a, b) => "INST " ^ (tuple2 (Int.toString, Type.toString) (a, b)) 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/src/main/scala/linguae/ImperativeShuntingYardParser.scala: -------------------------------------------------------------------------------- 1 | package linguae 2 | 3 | import scala.collection.mutable 4 | 5 | final case class ImperativeShuntingYardParser(operatorTable: Map[String, Fixity]) 6 | extends ExprParser { 7 | 8 | def parse(tokens: List[Token]): Expr = { 9 | val toknStack = mutable.Stack.from(tokens) 10 | val exprStack = mutable.Stack.empty[Expr] 11 | val operStack = mutable.Stack.empty[String] 12 | 13 | def applyOperator() = { 14 | val op = operStack.pop() 15 | val a1 = exprStack.pop() 16 | val a0 = exprStack.pop() 17 | exprStack.push(Expr.BinOp(op, a0, a1)) 18 | } 19 | 20 | while (toknStack.nonEmpty) { 21 | toknStack.pop() match { 22 | case Token.Const(const) => exprStack.push(Expr.Const(const)) 23 | case Token.ParenL => operStack.push("(") 24 | 25 | case Token.ParenR => 26 | while (operStack.nonEmpty && operStack.top != "(") { 27 | applyOperator() 28 | } 29 | 30 | if operStack.top == "(" 31 | then operStack.pop() 32 | else sys.error("missing open parenthesis") 33 | 34 | case Token.BinOp(binOp) => 35 | val binOpFixity = operatorTable(binOp) 36 | var pendingOperators = true 37 | 38 | while (pendingOperators) { 39 | if operStack.isEmpty || operStack.top == "(" 40 | then pendingOperators = false 41 | else { 42 | val topOpFixity = operatorTable(operStack.top) 43 | 44 | if binOpFixity.appliesAfter(topOpFixity) 45 | then applyOperator() 46 | else pendingOperators = false 47 | } 48 | } 49 | 50 | operStack.push(binOp) 51 | } 52 | } 53 | 54 | while (operStack.nonEmpty) { 55 | applyOperator() 56 | } 57 | 58 | exprStack 59 | .pop() 60 | .ensuring(exprStack.isEmpty, s"non-empty expression stack: $exprStack") 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/test/scala/InferTest.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | package test 3 | 4 | import codecamp.Type._ 5 | import codecamp.parser.Parser 6 | 7 | class InferTest extends Test { 8 | test("infer identity function") { 9 | val ty = Infer.typeOf(Parser.parse(""" 10 | fn a => a 11 | """)) 12 | 13 | inside (ty) { case FUN(t1, t2) => t1 should be(t2) } 14 | } 15 | 16 | test("infer const function") { 17 | val ty = Infer.typeOf(Parser.parse(""" 18 | fn a => fn b => a 19 | """)) 20 | 21 | inside (ty) { 22 | case FUN(t1, FUN(t2, t3)) => 23 | t1 should be(t3) 24 | t1 should not be(t2) 25 | } 26 | } 27 | 28 | test("infer compose function") { 29 | val ty = Infer.typeOf(Parser.parse(""" 30 | fn f => fn g => fn x => f (g x) 31 | """)) 32 | 33 | inside (ty) { 34 | case FUN(FUN(t1,t2), FUN(FUN(t3,t4), FUN(t5,t6))) => 35 | t5 should be(t3) 36 | t4 should be(t1) 37 | t2 should be(t6) 38 | } 39 | } 40 | 41 | test("infer pred function") { 42 | val ty = Infer.typeOf(Parser.parse(""" 43 | fn pred => if pred 1 then 2 else 3 44 | """)) 45 | 46 | ty should be(FUN(FUN(INT, BOOL), INT)) 47 | } 48 | 49 | test("infer inc function") { 50 | val ty = Infer.typeOf(Parser.parse(""" 51 | let 52 | val inc = fn a => a + 1 53 | in 54 | let 55 | val dec = fn a => a - 1 56 | in 57 | dec (inc 42) 58 | end 59 | end 60 | """)) 61 | 62 | ty should be(INT) 63 | } 64 | 65 | test("throws unification failure") { 66 | val e = intercept[RuntimeException] { 67 | Infer.typeOf(Parser.parse(""" 68 | let 69 | val const = fn y => 70 | let 71 | val f = fn x => y 72 | in 73 | f 74 | end 75 | in 76 | (const true 1) + 2 77 | end 78 | """)) 79 | } 80 | 81 | e.getMessage should include("cannot unify") 82 | e.getMessage should include("BOOL") 83 | e.getMessage should include("INT") 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/Lingua001.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | 3 | import nodes._ 4 | import visitors._ 5 | 6 | object Main { 7 | val log = logger("Main") 8 | 9 | def main(args: Array[String]): Unit = { 10 | val initialState = Interpreter.Environment.empty[(String, Int)] -> Interpreter.Store.empty[Int, Value] 11 | // val tree = App( 12 | // Fun("makeAdder", 13 | // App( 14 | // Fun("add10", App(Ref("add10"), Num(2))), // 12 15 | // App(Ref("makeAdder"), Num(10)) 16 | // )), 17 | // Fun("base", Fun("n", Add(Ref("base"), Ref("n"))))) 18 | 19 | // val counter = Fun("n", Fun("_", Seq(Set("n", Add(Ref("n"), Num(1))), Ref("n")))) 20 | // val tree = Let("counter", counter) { 21 | // Let("c", App(Ref("counter"), Num(0))) { 22 | // Seq( 23 | // App(Ref("c"), Num(-1)), 24 | // Seq( 25 | // App(Ref("c"), Num(-1)), 26 | // App(Ref("c"), Num(-1)) 27 | // ) 28 | // ) 29 | // } 30 | // } 31 | 32 | val Y = Fun("h", App( 33 | Fun("f", 34 | App(Ref("f"), Ref("f"))), 35 | Fun("f", 36 | App(Ref("h"), 37 | Fun("n", 38 | App(App(Ref("f"), Ref("f")), Ref("n"))))))) 39 | val factorial = App(Ref("Y"), Fun("fact", 40 | Fun("n", 41 | When(Equal(Ref("n"), Num(0)), 42 | Num(1), 43 | Mul(Ref("n"), App(Ref("fact"), Sub(Ref("n"), Num(1)))))))) 44 | 45 | val tree = Let("Y", Y) { 46 | Let("factorial", factorial) { 47 | App(Ref("factorial"), Num(5)) // 120 48 | } 49 | } 50 | 51 | val intrp = tree.accept(JsCompiler)(Trace.empty)._1 52 | 53 | println(s"Intrp: $intrp") 54 | 55 | // val tree = Let("a", Num(40)) { 56 | // Let("b", Num(2)) { 57 | // Add(Ref("a"), Ref("c")) 58 | // } 59 | // } 60 | 61 | // val depth = tree.accept(Depth)(()) 62 | // val intrp = tree.accept(Interpreter.Visitor) 63 | 64 | // println(s"Tree: $tree") 65 | // println(s"Depth: $depth") 66 | // println(s"Intrp: $intrp") 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/ast.sml: -------------------------------------------------------------------------------- 1 | structure Ast = 2 | struct 3 | type pos = int 4 | type symbol = Symbol.symbol 5 | 6 | datatype var = 7 | SimpleVar of symbol * pos (* l-value *) 8 | | FieldVar of var * symbol * pos (* l-value.id *) 9 | | SubscriptVar of var * exp * pos (* l-value[exp] *) 10 | 11 | and exp = 12 | VarExp of var 13 | | NilExp 14 | | IntExp of int 15 | | StringExp of string * pos 16 | | CallExp of { func: symbol, args: exp list, pos: pos } 17 | | OpExp of { left: exp, oper: oper, right: exp, pos: pos } 18 | | RecordExp of { fields: (symbol * exp * pos) list, name: symbol, pos: pos } 19 | | SeqExp of (exp * pos) list 20 | | AssignExp of { var: var, exp: exp, pos: pos } 21 | | IfExp of { test: exp, then': exp, else': exp option, pos: pos } 22 | | WhileExp of { test: exp, body: exp, pos: pos } 23 | | ForExp of { var: symbol, escape: bool ref, lo: exp, hi: exp, body: exp, pos: pos } 24 | | BreakExp of pos 25 | | LetExp of { decs: dec list, body: exp, pos: pos } 26 | | ArrayExp of { typ: symbol, size: exp, init: exp, pos: pos } 27 | 28 | and dec = 29 | TypeDec of { name: symbol, ty: ty, pos: pos } list 30 | | FunctionDec of fundec list 31 | | VarDec of { 32 | name: symbol, 33 | escape: bool ref, 34 | typ: (symbol * pos) option, 35 | init: exp, 36 | pos: pos 37 | } 38 | 39 | and ty = 40 | NameTy of symbol * pos 41 | | RecordTy of field list 42 | | ArrayTy of symbol * pos 43 | 44 | and oper = 45 | PlusOp 46 | | MinusOp 47 | | TimesOp 48 | | DivideOp 49 | | EqOp 50 | | NeqOp 51 | | LtOp 52 | | LeOp 53 | | GtOp 54 | | GeOp 55 | 56 | and field = 57 | Field of { 58 | name: symbol, 59 | escape: bool ref, 60 | typ: symbol, 61 | pos: pos 62 | } 63 | 64 | and fundec = 65 | FunDec of { 66 | name: symbol, 67 | params: field list, 68 | result: (symbol * pos) option, 69 | body: exp, 70 | pos: pos 71 | } 72 | 73 | fun isComparisonOperator oper = 74 | case oper of 75 | EqOp => true 76 | | NeqOp => true 77 | | LtOp => true 78 | | LeOp => true 79 | | GtOp => true 80 | | GeOp => true 81 | | _ => false 82 | end 83 | -------------------------------------------------------------------------------- /lingua-001-visitor-interpreter/src/main/scala/visitors/DecoratedVisitor.scala: -------------------------------------------------------------------------------- 1 | package lingua001 2 | package visitors 3 | 4 | trait DecoratedVisitor extends NodeVisitor { 5 | 6 | def decorate(result: (R, S)): (R, S) 7 | 8 | abstract override def num(n: Int, state: S): (R, S) = decorate(super.num(n, state)) 9 | abstract override def bool(b: Boolean, state: S): (R, S) = decorate(super.bool(b, state)) 10 | abstract override def add(a: N, b: N, state: S): (R, S) = decorate(super.add(a, b, state)) 11 | abstract override def sub(a: N, b: N, state: S): (R, S) = decorate(super.sub(a, b, state)) 12 | abstract override def mul(a: N, b: N, state: S): (R, S) = decorate(super.mul(a, b, state)) 13 | abstract override def div(a: N, b: N, state: S): (R, S) = decorate(super.div(a, b, state)) 14 | abstract override def let(id: String, value: N, body: N, state: S): (R, S) = decorate(super.let(id, value, body, state)) 15 | abstract override def ref(id: String, state: S): (R, S) = decorate(super.ref(id, state)) 16 | abstract override def fun(id: String, body: N, state: S): (R, S) = decorate(super.fun(id, body, state)) 17 | abstract override def app(fn: N, arg: N, state: S): (R, S) = decorate(super.app(fn, arg, state)) 18 | abstract override def seq(a: N, b: N, state: S): (R, S) = decorate(super.seq(a, b, state)) 19 | abstract override def set(id: String, value: N, state: S): (R, S) = decorate(super.set(id, value, state)) 20 | abstract override def equal(a: N, b: N, state: S): (R, S) = decorate(super.equal(a, b, state)) 21 | abstract override def when(cond: N, yes: N, no: N, state: S): (R, S) = decorate(super.when(cond, yes, no, state)) 22 | } 23 | 24 | trait SomeTrait { 25 | def foo(a: Int): Int 26 | def bar(a: Int): Int 27 | def baz(a: Int): Int 28 | } 29 | 30 | trait DecoratedTrait extends SomeTrait { 31 | def decorate(a: Int): Int 32 | abstract override def foo(a: Int) = decorate(super.foo(a)) 33 | abstract override def bar(a: Int) = decorate(super.foo(a)) 34 | abstract override def baz(a: Int) = decorate(super.foo(a)) 35 | } 36 | -------------------------------------------------------------------------------- /lingua-000-tiger/01-introduction/tree.sml: -------------------------------------------------------------------------------- 1 | structure Tree = 2 | struct 3 | open Lang 4 | 5 | type key = string 6 | 7 | datatype 'a tree = LEAF 8 | | TREE of 'a tree * key * 'a * 'a tree 9 | 10 | val empty = LEAF 11 | 12 | fun repeat s times = 13 | let 14 | fun go 0 acc = acc 15 | | go t acc = go (t - 1) acc ^ s 16 | in 17 | go times "" 18 | end 19 | 20 | fun showDepth LEAF depth = "LEAF" 21 | | showDepth (TREE(l, k, v, r)) depth = 22 | let 23 | val prefix = repeat " " 12 24 | in 25 | "[TREE left: " ^ (showDepth l (depth + 1)) ^ "\n" ^ (repeat prefix depth) ^ 26 | " key: " ^ "\"" ^ k ^ "\"" ^ "\n" ^ (repeat prefix depth) ^ 27 | " right: " ^ (showDepth r (depth + 1)) ^ "]" 28 | end 29 | 30 | (* 31 | * Sample Output 32 | * 33 | * [TREE left: LEAF 34 | * key: "a" 35 | * right: [TREE left: LEAF 36 | * key: "b" 37 | * right: [TREE left: LEAF 38 | * key: "c" 39 | * right: LEAF]]] 40 | *) 41 | fun show tree = (showDepth tree 0) ^ "\n" 42 | 43 | fun insert LEAF key value = TREE(LEAF, key, value, LEAF) 44 | | insert (TREE(l, k, v, r)) key value = 45 | if key < k then TREE(insert l key value, k, v, r) else 46 | if key > k then TREE(l, k, v, insert r key value) else TREE(l, k, v, r) 47 | 48 | (* Exercise 1.1 a., page 12. *) 49 | fun member LEAF key = false 50 | | member (TREE(l, k, _, r)) key = 51 | if key < k then member l key else 52 | if key > k then member r key else true 53 | 54 | (* Exercise 1.1 b., page 12. *) 55 | fun lookup LEAF key = NONE 56 | | lookup (TREE(l, k, v, r)) key = 57 | if key < k then lookup l key else 58 | if key > k then lookup r key else SOME(v) 59 | 60 | fun main () = 61 | let 62 | val folder = fn (c, tree) => insert tree (Char.toString c) (Char.toString c) 63 | val tree1 = List.foldl folder LEAF (String.explode "tspipfbst") 64 | val tree2 = List.foldl folder LEAF (String.explode "abcdefghi") 65 | in 66 | (* Exercise 1.1 c., page 12. *) 67 | print <| (show tree1) ^ "\n" ^ (show tree2) 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/src/main/scala/linguae/FunctionalShuntingYardParser.scala: -------------------------------------------------------------------------------- 1 | package linguae 2 | 3 | import scala.annotation.tailrec 4 | 5 | final case class FunctionalShuntingYardParser(operatorTable: Map[String, Fixity]) 6 | extends ExprParser { 7 | 8 | def parse(tokens: List[Token]): Expr = { 9 | def applyOp(op: String, exprs: List[Expr]): List[Expr] = 10 | exprs match { 11 | case b :: a :: restExprs => 12 | Expr.BinOp(op, a, b) :: restExprs 13 | case _ => 14 | sys.error(s"insufficient operands for operator: $op") 15 | } 16 | 17 | @tailrec 18 | def binOp( 19 | opX: String, 20 | tokens: List[Token], 21 | ops: List[String], 22 | exprs: List[Expr], 23 | ): Expr = 24 | ops match { 25 | case opY :: restOps if opY != "(" => 26 | val xFixity = operatorTable(opX) 27 | val yFixity = operatorTable(opY) 28 | 29 | if xFixity.appliesAfter(yFixity) 30 | then binOp(opX, tokens, restOps, applyOp(opY, exprs)) 31 | else loop(tokens, opX :: ops, exprs) 32 | 33 | case _ => 34 | loop(tokens, opX :: ops, exprs) 35 | } 36 | 37 | @tailrec 38 | def rparen(tokens: List[Token], ops: List[String], exprs: List[Expr]): Expr = 39 | ops match { 40 | case Nil => loop(tokens, Nil, exprs) 41 | case "(" :: restOps => loop(tokens, restOps, exprs) 42 | case op :: restOps => rparen(tokens, restOps, applyOp(op, exprs)) 43 | } 44 | 45 | @tailrec 46 | def loop(tokens: List[Token], ops: List[String], exprs: List[Expr]): Expr = 47 | tokens match { 48 | case Nil => 49 | ops match { 50 | case Nil => exprs.head 51 | case op :: restOps => rparen(tokens, restOps, applyOp(op, exprs)) 52 | } 53 | 54 | case token :: restTokens => 55 | token match { 56 | case Token.Const(value) => loop(restTokens, ops, Expr.Const(value) :: exprs) 57 | case Token.ParenL => loop(restTokens, "(" :: ops, exprs) 58 | case Token.ParenR => rparen(restTokens, ops, exprs) 59 | case Token.BinOp(op) => binOp(op, restTokens, ops, exprs) 60 | } 61 | } 62 | 63 | loop(tokens, List.empty, List.empty) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/basis/tuples.sml: -------------------------------------------------------------------------------- 1 | structure Tuples = 2 | struct 3 | (* structure Syntax = 4 | struct 5 | structure ~> = 6 | struct 7 | infix 2 ~> 8 | fun a ~> b = (a, b) 9 | end 10 | 11 | open ~> 12 | end *) 13 | 14 | structure Tuple2 = 15 | struct 16 | fun swap (a, b) = (b, a) 17 | fun map1 m (a, b) = (m a, b) 18 | fun map2 m (a, b) = (a, m b) 19 | end 20 | 21 | structure Tuple3 = 22 | struct 23 | fun map1 m (a, b, c) = (m a, b, c) 24 | fun map2 m (a, b, c) = (a, m b, c) 25 | fun map3 m (a, b, c) = (a, b, m c) 26 | end 27 | 28 | structure Tuple4 = 29 | struct 30 | fun map1 m (a, b, c, d) = (m a, b, c, d) 31 | fun map2 m (a, b, c, d) = (a, m b, c, d) 32 | fun map3 m (a, b, c, d) = (a, b, m c, d) 33 | fun map4 m (a, b, c, d) = (a, b, c, m d) 34 | end 35 | 36 | structure Tuple5 = 37 | struct 38 | fun map1 m (a, b, c, d, e) = (m a, b, c, d, e) 39 | fun map2 m (a, b, c, d, e) = (a, m b, c, d, e) 40 | fun map3 m (a, b, c, d, e) = (a, b, m c, d, e) 41 | fun map4 m (a, b, c, d, e) = (a, b, c, m d, e) 42 | fun map5 m (a, b, c, d, e) = (a, b, c, d, m e) 43 | end 44 | 45 | structure Tuple6 = 46 | struct 47 | fun map1 m (a, b, c, d, e, f) = (m a, b, c, d, e, f) 48 | fun map2 m (a, b, c, d, e, f) = (a, m b, c, d, e, f) 49 | fun map3 m (a, b, c, d, e, f) = (a, b, m c, d, e, f) 50 | fun map4 m (a, b, c, d, e, f) = (a, b, c, m d, e, f) 51 | fun map5 m (a, b, c, d, e, f) = (a, b, c, d, m e, f) 52 | fun map6 m (a, b, c, d, e, f) = (a, b, c, d, e, m f) 53 | end 54 | 55 | structure Tuple7 = 56 | struct 57 | fun map1 m (a, b, c, d, e, f, g) = (m a, b, c, d, e, f, g) 58 | fun map2 m (a, b, c, d, e, f, g) = (a, m b, c, d, e, f, g) 59 | fun map3 m (a, b, c, d, e, f, g) = (a, b, m c, d, e, f, g) 60 | fun map4 m (a, b, c, d, e, f, g) = (a, b, c, m d, e, f, g) 61 | fun map5 m (a, b, c, d, e, f, g) = (a, b, c, d, m e, f, g) 62 | fun map6 m (a, b, c, d, e, f, g) = (a, b, c, d, e, m f, g) 63 | fun map7 m (a, b, c, d, e, f, g) = (a, b, c, d, e, f, m g) 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/src/main/scala/peval/Parser.scala: -------------------------------------------------------------------------------- 1 | package peval 2 | 3 | import scala.annotation.tailrec 4 | import scala.util.Try 5 | import peval.Program.Defs 6 | 7 | object Parser { 8 | object INT { 9 | def unapply(s: String): Option[Int] = Try(Integer.parseInt(s)).toOption 10 | } 11 | 12 | def apply(sexpr: List[NODE]): Program = { 13 | @tailrec 14 | def loop(sexpr: List[NODE], main: Option[Expr], defs: Defs): Program = 15 | sexpr match { 16 | case Nil => 17 | main match { 18 | case None => throw new RuntimeException("no main entry") 19 | case Some(main) => Program(defs, main) 20 | } 21 | 22 | case head :: tail => 23 | head match { 24 | case LIST(ATOM("def"), ATOM("main"), LIST(), body) => 25 | loop(tail, Some(apply(body)), defs) 26 | 27 | case LIST(ATOM("def"), ATOM(name), LIST(values @ _*), body) => 28 | val args = values.toList.map { 29 | case ATOM(name) => name 30 | case _ => throw new RuntimeException(s"params must be atoms") 31 | } 32 | val func = Def(args, apply(body)) 33 | 34 | loop(tail, main, defs + (name -> func)) 35 | 36 | case expr => 37 | throw new RuntimeException(s"illegal top-level expression: $expr") 38 | } 39 | } 40 | 41 | loop(sexpr, Option.empty, Map.empty) 42 | } 43 | 44 | def apply(sexpr: NODE): Expr = 45 | sexpr match { 46 | case LIST(ATOM("if"), a, b, c) => Expr.If(apply(a), apply(b), apply(c)) 47 | case LIST(ATOM("="), a, b) => Expr.Prim(Op.Eqv, apply(a), apply(b)) 48 | case LIST(ATOM("+"), a, b) => Expr.Prim(Op.Add, apply(a), apply(b)) 49 | case LIST(ATOM("-"), a, b) => Expr.Prim(Op.Sub, apply(a), apply(b)) 50 | case LIST(ATOM("*"), a, b) => Expr.Prim(Op.Mul, apply(a), apply(b)) 51 | case LIST(ATOM(fun), args @ _*) => Expr.Apply(fun, args.map(apply).toList) 52 | case ATOM("true") => Expr.Const(Val.B(true)) 53 | case ATOM("false") => Expr.Const(Val.B(true)) 54 | 55 | case ATOM(name) => 56 | try { 57 | Expr.Const(Val.I(name.toInt)) 58 | } catch { 59 | case _: NumberFormatException => Expr.Var(name) 60 | } 61 | 62 | case _ => throw new RuntimeException(s"can't parse: $sexpr") 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/infer.sml: -------------------------------------------------------------------------------- 1 | structure Infer = 2 | struct 3 | fun typeOf term tenv = 4 | let 5 | open Unify 6 | val _ = Type.resetFreshness () 7 | val termTy = Type.freshVar () 8 | val constraints = constrain tenv termTy term 9 | val subst = unify constraints 10 | in 11 | TypeEnv.generalize tenv (Subst.apply subst termTy) 12 | end handle 13 | Unify.UnificationFailure (a, b) => 14 | raise Fail ("cannot unify "^ Type.toString a ^" with "^ Type.toString b) 15 | 16 | structure GenVar = 17 | struct 18 | structure M = BinaryMapFn ( 19 | struct 20 | type ord_key = int 21 | val compare = Int.compare 22 | end 23 | ) 24 | 25 | val prefix = ref "" 26 | val counter = ref 0 27 | val varEnv : string M.map ref = ref M.empty 28 | 29 | fun genvar var = 30 | case M.find (!varEnv, var) of 31 | SOME v => v 32 | | NONE => 33 | let 34 | val suffix = Char.toString (Char.chr (97 + !counter)) 35 | val varName = !prefix ^ suffix 36 | in 37 | counter := !counter + 1; 38 | varEnv := M.insert (!varEnv, var, varName); 39 | varName 40 | end 41 | 42 | fun reset () = let in 43 | prefix := ""; 44 | counter := 0; 45 | varEnv := M.empty 46 | end 47 | end 48 | 49 | fun typeSignature term tenv = 50 | let 51 | open Type 52 | 53 | fun typeString INT = "int" 54 | | typeString BOOL = "bool" 55 | | typeString (VAR v) = GenVar.genvar v 56 | | typeString (FUN (p as FUN _, r)) = 57 | let 58 | val return = typeString r 59 | val param = typeString p 60 | in 61 | "(" ^ param ^ ") -> " ^ return 62 | end 63 | | typeString (FUN (p, r)) = typeString p ^ " -> " ^ typeString r 64 | 65 | fun typeScheme (TypeScheme.SVAR _) = raise Fail "TypeScheme VAR" 66 | | typeScheme (TypeScheme.FORALL (vars, ty)) = 67 | let 68 | val tsVars = String.concat (List.map GenVar.genvar vars) 69 | val tsType = typeString ty 70 | in 71 | case vars of 72 | [] => tsType 73 | | _ => "forall " ^ tsVars ^ ". " ^ tsType 74 | end 75 | in 76 | GenVar.reset (); 77 | typeScheme (typeOf term tenv) 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/.scalafmt.conf: -------------------------------------------------------------------------------- 1 | # 2 | # See: https://scalameta.org/scalafmt/docs/configuration.html 3 | # 4 | version = "2.3.1" 5 | 6 | maxColumn = 120 7 | docstrings = JavaDoc 8 | 9 | project.git = true 10 | 11 | align = none 12 | align.tokens = [ 13 | { code = "//" } 14 | { code = "%", owner = "Term.ApplyInfix" } 15 | { code = "%%", owner = "Term.ApplyInfix" } 16 | { code = ":=", owner = "Term.ApplyInfix" } 17 | ] 18 | 19 | assumeStandardLibraryStripMargin = false 20 | includeCurlyBraceInSelectChains = true 21 | includeNoParensInSelectChains = true 22 | 23 | continuationIndent { 24 | callSite = 2 25 | defnSite = 2 26 | extendSite = 2 27 | } 28 | 29 | trailingCommas = always 30 | 31 | newlines { 32 | alwaysBeforeTopLevelStatements = false 33 | sometimesBeforeColonInMethodReturnType = true 34 | penalizeSingleSelectMultiArgList = false 35 | alwaysBeforeElseAfterCurlyIf = false 36 | neverInResultType = false 37 | } 38 | 39 | spaces { 40 | inImportCurlyBraces = true 41 | afterKeywordBeforeParen = true 42 | } 43 | 44 | binPack { 45 | parentConstructors = true 46 | literalArgumentLists = true 47 | } 48 | 49 | optIn { 50 | breaksInsideChains = false 51 | breakChainOnFirstMethodDot = true 52 | configStyleArguments = true 53 | } 54 | 55 | runner { 56 | optimizer { 57 | forceConfigStyleOnOffset = 120 58 | forceConfigStyleMinArgCount = 2 59 | } 60 | } 61 | 62 | rewrite { 63 | rules = [ 64 | AvoidInfix 65 | PreferCurlyFors 66 | RedundantBraces 67 | RedundantParens 68 | SortImports 69 | SortModifiers 70 | ] 71 | 72 | neverInfix.excludeFilters = [ 73 | at 74 | cross 75 | exclude 76 | ] 77 | 78 | redundantBraces.methodBodies = true 79 | redundantBraces.includeUnitMethods = true 80 | redundantBraces.maxLines = 100 81 | redundantBraces.stringInterpolation = true 82 | redundantBraces.generalExpressions = false 83 | 84 | sortModifiers.order = [ 85 | "private" 86 | "protected" 87 | "final" 88 | "sealed" 89 | "abstract" 90 | "override" 91 | "implicit" 92 | "lazy" 93 | ] 94 | } 95 | 96 | verticalMultiline { 97 | atDefnSite = true 98 | arityThreshold = 4 99 | newlineAfterOpenParen = true 100 | newlineBeforeImplicitKW = false 101 | newlineAfterImplicitKW = true 102 | excludeDanglingParens = ["`trait`"] 103 | } 104 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/src/main/scala/peval/NaiveSpecializer.scala: -------------------------------------------------------------------------------- 1 | package peval 2 | 3 | import cats.implicits._ 4 | 5 | object NaiveSpecializer { 6 | final case class Env(bindings: Map[String, Expr]) extends AnyVal 7 | 8 | object Env { 9 | val empty: Env = Env(Map.empty) 10 | } 11 | 12 | def specialize(program: Program): Expr = { 13 | def go(expr: Expr, env: Env): Expr = 14 | expr match { 15 | case Expr.Const(_) => expr 16 | 17 | case Expr.Var(v) => 18 | env.bindings.get(v) match { 19 | case Some(e) => e 20 | case None => expr 21 | } 22 | 23 | case Expr.Prim(op, a, b) => 24 | (go(a, env), go(b, env)) match { 25 | case (Expr.Const(va), Expr.Const(vb)) => Expr.Const(prim(op, va, vb)) 26 | case (Expr.Const(Val.I(0)), a) if op == Op.Add => a 27 | case (a, Expr.Const(Val.I(0))) if op == Op.Add => a 28 | case (a, Expr.Const(Val.I(0))) if op == Op.Sub => a 29 | case (Expr.Const(Val.I(1)), a) if op == Op.Mul => a 30 | case (a, Expr.Const(Val.I(1))) if op == Op.Mul => a 31 | case (pa, pb) => Expr.Prim(op, pa, pb) 32 | } 33 | 34 | case Expr.If(cond, condT, condF) => 35 | go(cond, env) match { 36 | case Expr.Const(Val.B(true)) => go(condT, env) 37 | case Expr.Const(Val.B(false)) => go(condF, env) 38 | case cond => Expr.If(cond, go(condT, env), go(condF, env)) 39 | } 40 | 41 | case Expr.Apply(fn, args) => 42 | program.defs.get(fn) match { 43 | case None => sys.error(show"undefined function: $fn") 44 | case Some(Def(params, body)) => 45 | val pargs = args.map(go(_, env)) 46 | go(body, Env(params.zip(pargs).toMap)) 47 | } 48 | } 49 | 50 | go(program.main, Env.empty) 51 | } 52 | 53 | private def prim(op: Op, a: Val, b: Val): Val = 54 | (a, b) match { 55 | case (Val.I(va), Val.I(vb)) => 56 | op match { 57 | case Op.Eqv => Val.B(va === vb) 58 | case Op.Add => Val.I(va + vb) 59 | case Op.Sub => Val.I(va - vb) 60 | case Op.Mul => Val.I(va * vb) 61 | } 62 | 63 | case (Val.B(va), Val.B(vb)) => 64 | op match { 65 | case Op.Eqv => Val.B(va === vb) 66 | case _ => sys.error("boolean values can only be compared for equality") 67 | } 68 | 69 | case _ => sys.error("operands of different types") 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lingua-004-lisp-parser/src/test/scala/ReaderTest.scala: -------------------------------------------------------------------------------- 1 | package leesp 2 | package test 3 | 4 | class ReaderTest extends FunSuite with Matchers { 5 | val reader = new Reader(traceExecution = false) 6 | 7 | test("reads single-character atoms") { 8 | reader.read("1") should be(List(ATOM("1"))) 9 | reader.read("a") should be(List(ATOM("a"))) 10 | reader.read("+") should be(List(ATOM("+"))) 11 | } 12 | 13 | test("reads multi-character atoms") { 14 | reader.read("foo") should be(List(ATOM("foo"))) 15 | reader.read("foo-bar") should be(List(ATOM("foo-bar"))) 16 | reader.read("bar^tax") should be(List(ATOM("bar^tax"))) 17 | } 18 | 19 | test("reads multiple atoms") { 20 | reader.read("foo 2") should be(List( 21 | ATOM("foo"), 22 | ATOM("2") 23 | )) 24 | } 25 | 26 | test("reads empty list") { 27 | reader.read("()") should be(List( 28 | LIST(List()) 29 | )) 30 | } 31 | 32 | test("reads list") { 33 | reader.read("(foo 2)") should be(List( 34 | LIST(List( 35 | ATOM("foo"), 36 | ATOM("2") 37 | )) 38 | )) 39 | } 40 | 41 | test("reads nested lists") { 42 | reader.read("(+ 2 (* 3 4))") should be(List( 43 | LIST(List( 44 | ATOM("+"), 45 | ATOM("2"), 46 | LIST(List( 47 | ATOM("*"), 48 | ATOM("3"), 49 | ATOM("4") 50 | )) 51 | )) 52 | )) 53 | } 54 | 55 | test("reads more definitions") { 56 | reader.read(""" 57 | (define a 1) 58 | (define b 2) 59 | (define add (lambda (a b) (+ a b))) 60 | (add a b) 61 | """) should be(List( 62 | LIST(List(ATOM("define"), ATOM("a"), ATOM("1"))), 63 | LIST(List(ATOM("define"), ATOM("b"), ATOM("2"))), 64 | LIST(List( 65 | ATOM("define"), 66 | ATOM("add"), 67 | LIST(List( 68 | ATOM("lambda"), 69 | LIST(List(ATOM("a"), ATOM("b"))), 70 | LIST(List(ATOM("+"), ATOM("a"), ATOM("b"))) 71 | )) 72 | )), 73 | LIST(List(ATOM("add"), ATOM("a"), ATOM("b"))) 74 | )) 75 | } 76 | 77 | test("throws on unmatched left parenthesis") { 78 | val e = intercept[UnmatchedLeftParen] { 79 | reader.read("(+ 2 (* 3 4") 80 | } 81 | 82 | e.row should be(1) 83 | e.col should be(6) 84 | } 85 | 86 | test("throws on unmatched right parenthesis") { 87 | val e = intercept[UnmatchedRightParen] { 88 | reader.read("(+ 2 (* 3 4)\n))") 89 | } 90 | 91 | e.row should be(2) 92 | e.col should be(2) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lingua-009-shunting-yard/.scalafmt.conf: -------------------------------------------------------------------------------- 1 | # 2 | # See: https://scalameta.org/scalafmt/docs/configuration.html 3 | # 4 | version = "3.4.3" 5 | 6 | runner.dialect = scala3 7 | 8 | maxColumn = 100 9 | docstrings.style = Asterisk 10 | 11 | project.git = true 12 | 13 | align = none 14 | align.tokens = [ 15 | { code = "//" } 16 | { code = "%", owner = "Term.ApplyInfix" } 17 | { code = "%%", owner = "Term.ApplyInfix" } 18 | { code = ":=", owner = "Term.ApplyInfix" } 19 | ] 20 | 21 | assumeStandardLibraryStripMargin = false 22 | includeCurlyBraceInSelectChains = true 23 | includeNoParensInSelectChains = true 24 | 25 | continuationIndent { 26 | callSite = 2 27 | defnSite = 2 28 | extendSite = 2 29 | } 30 | 31 | trailingCommas = always 32 | 33 | newlines { 34 | sometimesBeforeColonInMethodReturnType = true 35 | penalizeSingleSelectMultiArgList = false 36 | alwaysBeforeElseAfterCurlyIf = false 37 | neverInResultType = false 38 | implicitParamListModifierForce = [before] 39 | 40 | beforeTemplateBodyIfBreakInParentCtors = true 41 | 42 | topLevelStatementBlankLines = [ 43 | { blanks { before = 0, after = 0, beforeEndMarker = 0 } } 44 | ] 45 | } 46 | 47 | spaces { 48 | inImportCurlyBraces = true 49 | afterKeywordBeforeParen = true 50 | } 51 | 52 | binPack { 53 | parentConstructors = true 54 | literalArgumentLists = true 55 | } 56 | 57 | optIn { 58 | breaksInsideChains = false 59 | breakChainOnFirstMethodDot = true 60 | configStyleArguments = true 61 | } 62 | 63 | runner { 64 | optimizer { 65 | forceConfigStyleOnOffset = 120 66 | forceConfigStyleMinArgCount = 2 67 | } 68 | } 69 | 70 | rewrite { 71 | rules = [ 72 | AvoidInfix 73 | PreferCurlyFors 74 | RedundantBraces 75 | RedundantParens 76 | SortImports 77 | SortModifiers 78 | ] 79 | 80 | neverInfix.excludeFilters = [ 81 | at 82 | cross 83 | exclude 84 | ] 85 | 86 | redundantBraces.methodBodies = true 87 | redundantBraces.includeUnitMethods = true 88 | redundantBraces.maxLines = 100 89 | redundantBraces.stringInterpolation = true 90 | redundantBraces.generalExpressions = false 91 | 92 | sortModifiers.order = [ 93 | "private" 94 | "protected" 95 | "final" 96 | "sealed" 97 | "abstract" 98 | "override" 99 | "implicit" 100 | "lazy" 101 | ] 102 | } 103 | 104 | verticalMultiline { 105 | atDefnSite = true 106 | arityThreshold = 4 107 | newlineAfterOpenParen = true 108 | } 109 | 110 | danglingParentheses.exclude = [trait] 111 | -------------------------------------------------------------------------------- /lingua-011-bidirectional-typechecking/.scalafmt.conf: -------------------------------------------------------------------------------- 1 | # 2 | # See: https://scalameta.org/scalafmt/docs/configuration.html 3 | # 4 | version = "3.8.1" 5 | 6 | runner.dialect = scala3 7 | 8 | maxColumn = 100 9 | docstrings.style = Asterisk 10 | 11 | project.git = true 12 | 13 | align = none 14 | align.tokens = [ 15 | { code = "//" } 16 | { code = "%", owner = "Term.ApplyInfix" } 17 | { code = "%%", owner = "Term.ApplyInfix" } 18 | { code = ":=", owner = "Term.ApplyInfix" } 19 | ] 20 | 21 | assumeStandardLibraryStripMargin = false 22 | includeCurlyBraceInSelectChains = true 23 | includeNoParensInSelectChains = true 24 | 25 | continuationIndent { 26 | callSite = 2 27 | defnSite = 2 28 | extendSite = 2 29 | } 30 | 31 | trailingCommas = always 32 | 33 | newlines { 34 | sometimesBeforeColonInMethodReturnType = true 35 | penalizeSingleSelectMultiArgList = false 36 | alwaysBeforeElseAfterCurlyIf = false 37 | neverInResultType = false 38 | implicitParamListModifierForce = [before] 39 | 40 | beforeTemplateBodyIfBreakInParentCtors = true 41 | 42 | topLevelStatementBlankLines = [ 43 | { blanks { before = 0, after = 0, beforeEndMarker = 0 } } 44 | ] 45 | } 46 | 47 | spaces { 48 | inImportCurlyBraces = true 49 | afterKeywordBeforeParen = true 50 | } 51 | 52 | binPack { 53 | parentConstructors = true 54 | literalArgumentLists = true 55 | } 56 | 57 | optIn { 58 | breaksInsideChains = false 59 | breakChainOnFirstMethodDot = true 60 | configStyleArguments = true 61 | } 62 | 63 | runner { 64 | optimizer { 65 | forceConfigStyleOnOffset = 120 66 | forceConfigStyleMinArgCount = 2 67 | } 68 | } 69 | 70 | rewrite { 71 | rules = [ 72 | AvoidInfix 73 | PreferCurlyFors 74 | RedundantBraces 75 | RedundantParens 76 | SortImports 77 | SortModifiers 78 | ] 79 | 80 | neverInfix.excludeFilters = [ 81 | at 82 | cross 83 | exclude 84 | ] 85 | 86 | redundantBraces.methodBodies = true 87 | redundantBraces.includeUnitMethods = true 88 | redundantBraces.maxLines = 100 89 | redundantBraces.stringInterpolation = true 90 | redundantBraces.generalExpressions = false 91 | 92 | sortModifiers.order = [ 93 | "private" 94 | "protected" 95 | "final" 96 | "sealed" 97 | "abstract" 98 | "override" 99 | "implicit" 100 | "lazy" 101 | ] 102 | } 103 | 104 | verticalMultiline { 105 | atDefnSite = true 106 | arityThreshold = 4 107 | newlineAfterOpenParen = true 108 | } 109 | 110 | danglingParentheses.exclude = [trait] 111 | -------------------------------------------------------------------------------- /lingua-007-µml-swift/SwiftML/annotate.swift: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------- // 2 | // SwiftML // 3 | // -------------------------------------------------------------------------- // 4 | 5 | func annotate(term: Term) -> Result, TypeError> { 6 | func loop(_ term: Term, _ env: [String:Type], _ tvarCounter: Int) -> Result<(Term<(Attr, Type)>, Int), TypeError> { 7 | switch term { 8 | case let .Num(attr, n): return .Success((.Num((attr, .Var(tvarCounter)), n), tvarCounter + 1)) 9 | case let .Bool(attr, n): return .Success((.Bool((attr, .Var(tvarCounter)), n), tvarCounter + 1)) 10 | case let .Var(attr, n): 11 | return Result.fromOptional(env[n], TypeError.Unbound(identifier: n)).map { type in 12 | (.Var((attr, type), n), tvarCounter) 13 | } 14 | case let .Def(attr, param, body): 15 | let defType = Type.Var(tvarCounter) 16 | let paramType = Type.Var(tvarCounter + 1) 17 | var env = env 18 | env[param.name] = paramType 19 | return loop(body, env, tvarCounter + 2).map { (typedBody, tvarCounter) in 20 | let binder = Binder(name: param.name, attr: (param.attr, paramType)) 21 | return (.Def((attr, defType), binder, typedBody), tvarCounter) 22 | } 23 | case let .App(attr, fun, arg): 24 | let appType = Type.Var(tvarCounter) 25 | return loop(fun, env, tvarCounter + 1).flatMap { (fun, tvarCounter) in 26 | loop(arg, env, tvarCounter).map { (arg, tvarCounter) in 27 | (.App((attr, appType), fun, arg), tvarCounter + 1) 28 | } 29 | } 30 | case let .When(attr, cond, test, otherwise): 31 | let whenType = Type.Var(tvarCounter) 32 | return loop(cond, env, tvarCounter + 1).flatMap { (cond, tvarCounter) in 33 | loop(test, env, tvarCounter).flatMap { (test, tvarCounter) in 34 | loop(otherwise, env, tvarCounter).map { (otherwise, tvarCounter) in 35 | (.When((attr, whenType), cond, test, otherwise), tvarCounter) 36 | } 37 | } 38 | } 39 | case let .Let(attr, name, value, body): 40 | let letType = Type.Var(tvarCounter) 41 | let valueType = Type.Var(tvarCounter + 1) 42 | var env = env 43 | env[name.name] = valueType 44 | return loop(value, env, tvarCounter + 2).flatMap { (value, tvarCounter) in 45 | return loop(body, env, tvarCounter).map { (body, tvarCounter) in 46 | let binder = Binder(name: name.name, attr: (name.attr, valueType)) 47 | return (.Let((attr, letType), binder, value, body), tvarCounter) 48 | } 49 | } 50 | } 51 | } 52 | 53 | return loop(term, [:], 0).map { $0.0 } 54 | } 55 | -------------------------------------------------------------------------------- /lingua-000-tiger/01-introduction/lingua.sml: -------------------------------------------------------------------------------- 1 | structure Lingua = 2 | struct 3 | open Lang 4 | 5 | type id = string 6 | 7 | type table = (id * int) list 8 | 9 | datatype binop = Plus | Minus | Times | Div 10 | 11 | datatype stm = 12 | CompoundStm of stm * stm 13 | | AssignStm of id * exp 14 | | PrintStm of exp list 15 | 16 | and exp = 17 | IdExp of id 18 | | NumExp of int 19 | | OpExp of exp * binop * exp 20 | | EseqExp of stm * exp 21 | 22 | val prog = 23 | CompoundStm( 24 | AssignStm("a", OpExp(NumExp 5, Plus, NumExp 3)), 25 | CompoundStm( 26 | AssignStm("b", EseqExp( 27 | PrintStm [IdExp "a", OpExp(IdExp "a", Minus, NumExp 1)], 28 | OpExp(NumExp 10, Times, IdExp"a") 29 | )), 30 | PrintStm[IdExp "b"])) 31 | 32 | (* Exercise 1, page 11. *) 33 | (* http://stackoverflow.com/a/9323417/58808 *) 34 | (* http://stackoverflow.com/a/21205572/58808 *) 35 | fun maxargs (s: stm): int = 36 | let fun loop count [] = count 37 | | loop count (top :: stack) = 38 | case top of 39 | PrintStm args => loop (Int.max (count, length args)) stack 40 | | CompoundStm (a, b) => loop count (a :: b :: stack) 41 | | AssignStm (_, EseqExp (a, _)) => loop count (a :: stack) 42 | | AssignStm _ => loop count stack 43 | in 44 | loop 0 [s] 45 | end 46 | 47 | fun lookup id table = 48 | #2 (valOf (List.find (fn (id', _) => id' = id) table)) 49 | 50 | fun interpStm statement t = 51 | case statement of 52 | CompoundStm (s1, s2) => interpStm s2 <| interpStm s1 t 53 | | AssignStm (id, e) => let val (v, t') = interpExp e t in (id, v) :: t' end 54 | | PrintStm exps => printArgs t exps 55 | 56 | and interpExp exp t = 57 | case exp of 58 | IdExp id => (lookup id t, t) 59 | | NumExp n => (n, t) 60 | | OpExp (e1, binop, e2) => binOp e1 binop e2 t 61 | | EseqExp (s, e) => interpExp e <| interpStm s t 62 | 63 | and binOp e1 binop e2 t = 64 | let 65 | val (v1, t1) = interpExp e1 t 66 | val (v2, t2) = interpExp e2 t1 67 | in 68 | case binop of 69 | Plus => (v1 + v2, t2) 70 | | Minus => (v1 - v2, t2) 71 | | Times => (v1 * v2, t2) 72 | | Div => (v1 div v2, t2) 73 | end 74 | 75 | and printArgs t exps = 76 | let 77 | fun folder (e, (acc, prefix)) = 78 | let val (v, t') = interpExp e acc 79 | in 80 | (t', " ") before print (prefix ^ (Int.toString v)) 81 | end 82 | val result = foldl folder (t, "") exps 83 | in 84 | (#1 result) before print "\n" 85 | end 86 | 87 | (* Exercise 2, page 11. *) 88 | fun interp stm: unit = ignore <| interpStm stm [] 89 | end 90 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/test/scala/parser/ScannerTest.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | package test 3 | package parser 4 | 5 | import codecamp.parser.{ Scanner, Token } 6 | 7 | class ScannerTest extends Test { 8 | test("scans identity") { 9 | val tokens = Scanner.scan(""" 10 | fn a => a 11 | """) 12 | 13 | tokens should be(List( 14 | Token.FN, 15 | Token.VAR("a"), 16 | Token.DARROW, 17 | Token.VAR("a") 18 | )) 19 | } 20 | 21 | test("scans const") { 22 | val tokens = Scanner.scan(""" 23 | fn a => fn b => a 24 | """) 25 | 26 | tokens should be(List( 27 | Token.FN, 28 | Token.VAR("a"), 29 | Token.DARROW, 30 | Token.FN, 31 | Token.VAR("b"), 32 | Token.DARROW, 33 | Token.VAR("a") 34 | )) 35 | } 36 | 37 | test("scans compose") { 38 | val tokens = Scanner.scan(""" 39 | fn f => fn g => fn x => f (g x) 40 | """) 41 | 42 | tokens should be(List( 43 | Token.FN, 44 | Token.VAR("f"), 45 | Token.DARROW, 46 | Token.FN, 47 | Token.VAR("g"), 48 | Token.DARROW, 49 | Token.FN, 50 | Token.VAR("x"), 51 | Token.DARROW, 52 | Token.VAR("f"), 53 | Token.LPAREN, 54 | Token.VAR("g"), 55 | Token.VAR("x"), 56 | Token.RPAREN 57 | )) 58 | } 59 | 60 | test("scans pred") { 61 | val tokens = Scanner.scan(""" 62 | fn pred => if pred 1 then 2 else 3 63 | """) 64 | 65 | tokens should be(List( 66 | Token.FN, 67 | Token.VAR("pred"), 68 | Token.DARROW, 69 | Token.IF, 70 | Token.VAR("pred"), 71 | Token.INT(1), 72 | Token.THEN, 73 | Token.INT(2), 74 | Token.ELSE, 75 | Token.INT(3) 76 | )) 77 | } 78 | 79 | test("scans inc") { 80 | val tokens = Scanner.scan(""" 81 | let 82 | val inc = fn a => a + 1 83 | in 84 | let 85 | val dec = fn a => a - 1 86 | in 87 | dec (inc 42) 88 | end 89 | end 90 | """) 91 | 92 | tokens should be(List( 93 | Token.LET, 94 | Token.VAL, 95 | Token.VAR("inc"), 96 | Token.EQUAL, 97 | Token.FN, 98 | Token.VAR("a"), 99 | Token.DARROW, 100 | Token.VAR("a"), 101 | Token.ADD, 102 | Token.INT(1), 103 | Token.IN, 104 | Token.LET, 105 | Token.VAL, 106 | Token.VAR("dec"), 107 | Token.EQUAL, 108 | Token.FN, 109 | Token.VAR("a"), 110 | Token.DARROW, 111 | Token.VAR("a"), 112 | Token.SUB, 113 | Token.INT(1), 114 | Token.IN, 115 | Token.VAR("dec"), 116 | Token.LPAREN, 117 | Token.VAR("inc"), 118 | Token.INT(42), 119 | Token.RPAREN, 120 | Token.END, 121 | Token.END 122 | )) 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/frame.sig: -------------------------------------------------------------------------------- 1 | signature FRAME = 2 | sig 3 | (** 4 | * Holds information about formal parameters and local variables allocated in 5 | * the frame: 6 | * 7 | * - the locations of all the formals 8 | * - instructions required to implement the "view shift" 9 | * - the number of locals allocated so far 10 | * - the label at which the function's machine code is to begin 11 | *) 12 | type frame 13 | 14 | (** 15 | * Describes where formals or locals are stored — frame or register. 16 | *) 17 | type access 18 | 19 | type register = string 20 | 21 | datatype frag = 22 | PROC of { body : Tree.stm, frame : frame } 23 | | STRING of Temp.label * string 24 | 25 | (** 26 | * The stack pointer. 27 | *) 28 | val SP : Temp.temp 29 | 30 | (** 31 | * The frame pointer. 32 | *) 33 | val FP : Temp.temp 34 | 35 | (** 36 | * The return value of a function. 37 | *) 38 | val RV : Temp.temp 39 | 40 | (** 41 | * The return address of a function. 42 | *) 43 | val RA : Temp.temp 44 | 45 | (** 46 | * Machine's word size. 47 | *) 48 | val wordSize : int 49 | 50 | structure TempMap : ORD_MAP where type Key.ord_key = Temp.temp 51 | 52 | val tempMap : register TempMap.map 53 | 54 | val tempName : Temp.temp -> string 55 | 56 | structure Registers : sig 57 | val special : Temp.temp list 58 | val arguments : Temp.temp list 59 | val callerSave : Temp.temp list 60 | val calleeSave : Temp.temp list 61 | end 62 | 63 | val outermost : frame 64 | 65 | val string : Temp.label * string -> string 66 | 67 | val name : frame -> string 68 | 69 | val exp : access -> Tree.exp -> Tree.exp 70 | 71 | val externalCall : string * Tree.exp list -> Tree.exp 72 | 73 | (** 74 | * For each formal parameter, this function must calculate two things: 75 | * 76 | * - how the parameter will be seen from inside the function (in a register 77 | * or in a frame location) 78 | * - what instructions must be produced to implement the "view shift" 79 | * 80 | * For example, a frame-resident parameter will be seen as "memory at offset 81 | * X from the frame pointer", and the view shift will be implemented by 82 | * copying the stack pointer to the frame pointer on entry to the procedure. 83 | *) 84 | val newFrame : { name : Temp.label, formals : bool list } -> frame 85 | 86 | val formals : frame -> access list 87 | 88 | (** 89 | * The boolean parameter tells whether the local escapes. 90 | *) 91 | val allocLocal : frame -> bool -> access 92 | 93 | type proc = { 94 | prolog : string, 95 | body : Assem.instr list, 96 | epilog : string 97 | } 98 | 99 | val procEntryExit1 : frame * Tree.stm -> Tree.stm 100 | val procEntryExit2 : frame * Assem.instr list -> Assem.instr list 101 | val procEntryExit3 : frame * Assem.instr list -> proc 102 | end 103 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/escape-analysis.sml: -------------------------------------------------------------------------------- 1 | structure EscapeAnalysis :> ESCAPE_ANALYSIS = 2 | struct 3 | open Fn 4 | infix 1 |> 5 | 6 | fun analyse program = 7 | let 8 | type depth = int 9 | type env = (depth * bool ref) Symbol.table 10 | val initialEnv : env = Symbol.empty 11 | val initialDepth : depth = 0 12 | in 13 | analyseExp initialEnv initialDepth program 14 | end 15 | 16 | and analyseExp env depth exp = 17 | case exp of 18 | Ast.NilExp => () 19 | | Ast.IntExp _ => () 20 | | Ast.BreakExp _ => () 21 | | Ast.StringExp _ => () 22 | | Ast.VarExp var => analyseVar env depth var 23 | | Ast.CallExp { args, ... } => analyseExps env depth args 24 | | Ast.OpExp { left, right, ... } => analyseExps env depth [left, right] 25 | | Ast.RecordExp { fields, ... } => List.map #2 fields |> analyseExps env depth 26 | | Ast.SeqExp exps => List.map #1 exps |> analyseExps env depth 27 | | Ast.AssignExp { var, exp, ... } => (analyseVar env depth var ; analyseExp env depth exp) 28 | | Ast.WhileExp { test, body, ... } => analyseExps env depth [test, body] 29 | | Ast.ArrayExp { size, init, ... } => analyseExps env depth [size, init] 30 | | Ast.IfExp { test, then', else', ... } => List.app (Option.app (analyseExp env depth)) [SOME test, SOME then', else'] 31 | | Ast.LetExp { decs, body, ... } => analyseExp (analyseDecs env depth decs) depth body 32 | | Ast.ForExp { var, escape, lo, hi, body, ... } => 33 | let 34 | val bodyEnv = Symbol.set env var (depth, escape) 35 | in 36 | analyseExps env depth [lo, hi] 37 | ; analyseExp bodyEnv depth body 38 | end 39 | 40 | and analyseExps env depth exps = List.app (analyseExp env depth) exps 41 | 42 | and analyseVar env depth var = 43 | case var of 44 | Ast.FieldVar (var, _, _) => analyseVar env depth var 45 | | Ast.SubscriptVar (var, exp, _) => (analyseVar env depth var ; analyseExp env depth exp) 46 | | Ast.SimpleVar (name, _) => 47 | case Symbol.get env name of 48 | NONE => () (* Let Semant report unbound variables. *) 49 | | SOME (declarationDepth, escape) => escape := declarationDepth < depth 50 | 51 | and analyseDec env depth decs = 52 | case decs of 53 | Ast.TypeDec types => env 54 | | Ast.VarDec { name, escape, init, ... } => (analyseExp env depth init ; Symbol.set env name (depth, escape)) 55 | | Ast.FunctionDec fundecs => 56 | let 57 | fun addParamToEnv (Ast.Field { name, escape, ... }, env) = 58 | Symbol.set env name (depth + 1, escape) 59 | fun folder (Ast.FunDec { params, body, ... }, env) = 60 | let 61 | val bodyEnv = List.foldl addParamToEnv env params 62 | in 63 | analyseExp bodyEnv (depth + 1) body 64 | ; env 65 | end 66 | in 67 | List.foldl folder env fundecs 68 | end 69 | 70 | and analyseDecs env depth decs = 71 | List.foldl (fn (dec, env) => analyseDec env depth dec) env decs 72 | end 73 | -------------------------------------------------------------------------------- /lingua-006-hm-inference-scala/src/test/scala/parser/ParserTest.scala: -------------------------------------------------------------------------------- 1 | package codecamp 2 | package test 3 | package parser 4 | 5 | import codecamp.parser.{ Parser, Token } 6 | 7 | class ParserTest extends Test { 8 | test("parses identity") { 9 | val ast = Parser.parse(List( 10 | Token.FN, 11 | Token.VAR("a"), 12 | Token.DARROW, 13 | Token.VAR("a") 14 | )) 15 | 16 | ast should be { 17 | FUN("a", VAR("a")) 18 | } 19 | } 20 | 21 | test("parses const") { 22 | val ast = Parser.parse(List( 23 | Token.FN, 24 | Token.VAR("a"), 25 | Token.DARROW, 26 | Token.FN, 27 | Token.VAR("b"), 28 | Token.DARROW, 29 | Token.VAR("a") 30 | )) 31 | 32 | ast should be { 33 | FUN("a", FUN("b", VAR("a"))) 34 | } 35 | } 36 | 37 | test("parses compose") { 38 | val ast = Parser.parse(List( 39 | Token.FN, 40 | Token.VAR("f"), 41 | Token.DARROW, 42 | Token.FN, 43 | Token.VAR("g"), 44 | Token.DARROW, 45 | Token.FN, 46 | Token.VAR("x"), 47 | Token.DARROW, 48 | Token.VAR("f"), 49 | Token.LPAREN, 50 | Token.VAR("g"), 51 | Token.VAR("x"), 52 | Token.RPAREN 53 | )) 54 | 55 | ast should be { 56 | FUN("f", FUN("g", FUN("x", APP(VAR("f"), APP(VAR("g"), VAR("x")))))) 57 | } 58 | } 59 | 60 | test("parses pred") { 61 | val ast = Parser.parse(List( 62 | Token.FN, 63 | Token.VAR("pred"), 64 | Token.DARROW, 65 | Token.IF, 66 | Token.VAR("pred"), 67 | Token.INT(1), 68 | Token.THEN, 69 | Token.INT(2), 70 | Token.ELSE, 71 | Token.INT(3) 72 | )) 73 | 74 | ast should be { 75 | FUN( 76 | "pred", 77 | IF( 78 | APP(VAR("pred"), INT(1)), 79 | INT(2), 80 | INT(3) 81 | ) 82 | ) 83 | } 84 | } 85 | 86 | test("parses inc") { 87 | val ast = Parser.parse(List( 88 | Token.LET, 89 | Token.VAL, 90 | Token.VAR("inc"), 91 | Token.EQUAL, 92 | Token.FN, 93 | Token.VAR("a"), 94 | Token.DARROW, 95 | Token.VAR("a"), 96 | Token.ADD, 97 | Token.INT(1), 98 | Token.IN, 99 | Token.LET, 100 | Token.VAL, 101 | Token.VAR("dec"), 102 | Token.EQUAL, 103 | Token.FN, 104 | Token.VAR("a"), 105 | Token.DARROW, 106 | Token.VAR("a"), 107 | Token.SUB, 108 | Token.INT(1), 109 | Token.IN, 110 | Token.VAR("dec"), 111 | Token.LPAREN, 112 | Token.VAR("inc"), 113 | Token.INT(42), 114 | Token.RPAREN, 115 | Token.END, 116 | Token.END 117 | )) 118 | 119 | ast should be { 120 | LET( 121 | "inc", FUN("a", APP(APP(VAR("+"), VAR("a")), INT(1))), 122 | LET( 123 | "dec", FUN("a", APP(APP(VAR("-"), VAR("a")), INT(1))), 124 | APP(VAR("dec"), APP(VAR("inc"), INT(42))) 125 | ) 126 | ) 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/src/main/scala/peval/Reader.scala: -------------------------------------------------------------------------------- 1 | package peval 2 | 3 | import java.io.{ BufferedReader, ByteArrayInputStream, InputStream, InputStreamReader } 4 | import java.lang.Character.isWhitespace 5 | 6 | /* 7 | * The tree produced by the reader. 8 | */ 9 | sealed trait NODE 10 | case class ATOM(value: String) extends NODE 11 | case class LIST(value: NODE*) extends NODE 12 | 13 | /* 14 | * Exceptions throw by the reader. 15 | */ 16 | final case class UnbalancedParenL(row: Int, col: Int) 17 | extends RuntimeException(s"row: $row; col: $col") 18 | final case class UnbalancedParenR(row: Int, col: Int) 19 | extends RuntimeException(s"row: $row; col: $col") 20 | 21 | object Reader { 22 | def read(source: String): List[NODE] = 23 | read(new ByteArrayInputStream(source.getBytes("UTF-8"))) 24 | 25 | def read(stream: InputStream): List[NODE] = { 26 | val reader = new BufferedReader(new InputStreamReader(stream, "UTF-8")) 27 | var program = Vector.empty[NODE] 28 | var pendingList = List.empty[Vector[NODE]] 29 | var pendingAtom = "" 30 | var insideComment = false 31 | var col = 1 32 | var row = 1 33 | 34 | def adjustPosition(char: Char): Unit = 35 | if (char == '\n') { 36 | col = 1 37 | row = row + 1 38 | } else { 39 | col = col + 1 40 | } 41 | 42 | def commitAtom(): Unit = 43 | if (pendingAtom.nonEmpty) { 44 | pendingList match { 45 | case Nil => program = program :+ ATOM(pendingAtom) 46 | case h :: t => pendingList = (h :+ ATOM(pendingAtom)) :: t 47 | } 48 | 49 | pendingAtom = "" 50 | } 51 | 52 | def adjustAtom(char: Char): Unit = pendingAtom += char 53 | 54 | def startList(): Unit = 55 | pendingList = Vector.empty[NODE] :: pendingList 56 | 57 | def commitList(): Unit = 58 | pendingList match { 59 | case Nil => throw UnbalancedParenR(row, col) 60 | case list :: Nil => 61 | program = program :+ LIST(list: _*) 62 | pendingList = List.empty 63 | case list :: h :: t => 64 | pendingList = (h :+ LIST(list: _*)) :: t 65 | } 66 | 67 | try { 68 | var char = reader.read() 69 | 70 | while (char > -1) { 71 | if (insideComment) { 72 | if (char == '\n') { 73 | insideComment = false 74 | } 75 | } else { 76 | char match { 77 | case ';' => insideComment = true 78 | case '[' => commitAtom(); startList() 79 | case ']' => commitAtom(); commitList() 80 | case chr => 81 | if (isWhitespace(chr)) commitAtom() else adjustAtom(chr.toChar) 82 | } 83 | } 84 | 85 | adjustPosition(char.toChar) 86 | char = reader.read() 87 | } 88 | } finally { 89 | reader.close() 90 | } 91 | 92 | commitAtom() 93 | 94 | if (pendingList.nonEmpty) { 95 | throw UnbalancedParenL(row, col - 1) 96 | } 97 | 98 | program.toList 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/src/main/resources/leesp/mix.leesp: -------------------------------------------------------------------------------- 1 | ; Parigot Encoding? External Visitor as it were. 2 | [def null [] 3 | [fun [on-null _] [on-null]]] 4 | 5 | [def cons [head tail] 6 | [fun [_ on-cons] [on-cons head tail]]] 7 | 8 | [def head [list] 9 | [list 10 | [def [] [fail "empty list"]] 11 | [def [head _] c]]] 12 | 13 | [def tail [list] 14 | [list 15 | [def [] [fail "empty list"]] 16 | [def [_ tail] tail]]] 17 | 18 | [def drop [list n] 19 | [let 20 | [loop [fun [list n] [if [= n 0] list [loop [tail list] [- n 1]]]]] 21 | [loop list n]]] 22 | 23 | [def nth [list n] 24 | [head [drop list n]]] 25 | 26 | [def size [list] 27 | [list 28 | [fun [] 0] 29 | [fun [_ n] [+ 1 n]]]] 30 | 31 | [def not [bool] 32 | [if bool] false true]] 33 | 34 | tree ::= "(" many ")" | leaf 35 | many ::= ε | tree many 36 | 37 | 38 | [def success [a] 39 | [fun [file] [cons a file]]] 40 | 41 | [def failure [a] 42 | [fun [file] [null]]] 43 | 44 | [def item [] 45 | [fun [file] 46 | [let [[char [read-char file]]] 47 | [if [not char] 48 | [null] 49 | [cons char file]]]]] 50 | 51 | [def bind [parser action] 52 | [fun [file] 53 | ]] 54 | 55 | [def char [] 56 | [fun [file] 57 | [cons [read-char file] file]]] 58 | 59 | [def matches [c] 60 | [fun [file] 61 | [if [= c [read-char file]] 62 | [cons c file] 63 | null]]] 64 | 65 | [def read [file] 66 | [let [ 67 | [empty-atom [null]] 68 | [inside-comment true] 69 | [outside-comment false] 70 | [loop [fun [program comment atom list-stack] 71 | [let 72 | [[char [read-char file]]] 73 | [if [> char -1] 74 | program 75 | [if comment 76 | [if [= char '\n'] 77 | [loop program outside-comment] 78 | [loop program inside-comment]] 79 | [if [= char ';'] 80 | [loop program true] 81 | [if [= char '('] 82 | [loop 83 | [cons [str atom] program] 84 | inside-comment 85 | empty-atom 86 | [cons null list-stack]] 87 | [if [= char ')'] 88 | [loop 89 | [cons [str atom] program] 90 | inside-comment 91 | empty-atom 92 | [cons null list-stack]] 93 | 94 | ]]]]]]]]] 95 | [loop null false]]] 96 | 97 | ; ;; assumes all variables are defined 98 | ; [define env:get [lambda [env k] 99 | ; [if [= k [head [head env]]] 100 | ; [tail [head env]] 101 | ; [env:get [tail env] k]]]] 102 | 103 | ; [define env:put [lambda [env k v] 104 | ; [cons [list k v] env] 105 | 106 | ; ; lexer == mărunțitor 107 | 108 | ; ;; reader 109 | ; [define read [lamdba chars 110 | ; [if [empty]]]] 111 | -------------------------------------------------------------------------------- /lingua-000-tiger/tiger/graph.sml: -------------------------------------------------------------------------------- 1 | structure Graph :> GRAPH = 2 | struct 3 | type node' = int 4 | type temp = Temp.temp 5 | 6 | datatype noderep = 7 | NODE of { succ : node' list, pred : node' list } 8 | 9 | val emptyNode = NODE { succ = [], pred = [] } 10 | 11 | val bogusNode = NODE { succ = [~1], pred = [] } 12 | 13 | fun isBogus (NODE { succ = [~1], ... }) = true 14 | | isBogus _ = false 15 | 16 | structure A = DynamicArrayFn(struct 17 | open Array 18 | type elem = noderep 19 | type vector = noderep vector 20 | type array = noderep array 21 | end) 22 | 23 | type graph = A.array 24 | type node = graph * node' 25 | 26 | structure NodeMap = BinaryMapFn(struct 27 | type ord_key = node 28 | fun compare ((_, a), (_, b)) = Int.compare (a, b) 29 | end) 30 | 31 | structure TempSet = BinarySetFn(struct 32 | type ord_key = Temp.temp 33 | val compare = Int.compare 34 | end) 35 | 36 | type 'a node_map = 'a NodeMap.map 37 | type temp_set = TempSet.set 38 | 39 | exception GraphEdge 40 | 41 | fun eq ((_, a), (_, b)) = a = b 42 | 43 | fun augment (g : graph) (n : node') : node = (g, n) 44 | 45 | fun newGraph () = A.array (0, bogusNode) 46 | 47 | fun nodes g = 48 | let 49 | val b = A.bound g 50 | fun f i = 51 | if isBogus (A.sub (g, i)) 52 | then nil 53 | else (g, i) :: f (i + 1) 54 | in 55 | f 0 56 | end 57 | 58 | fun succ (g, i) = 59 | let 60 | val NODE { succ = s, ... } = A.sub (g, i) 61 | in 62 | List.map (augment g) s 63 | end 64 | 65 | fun pred (g, i) = 66 | let 67 | val NODE { pred = p, ... } = A.sub (g, i) 68 | in 69 | map (augment g) p 70 | end 71 | 72 | fun adj gi = pred gi @ succ gi 73 | 74 | fun newNode g = (* binary search for unused node *) 75 | let 76 | fun look(lo,hi) = 77 | (* i < lo indicates i in use; i >= hi indicates i not in use *) 78 | if lo = hi 79 | then (A.update (g, lo, emptyNode); (g, lo)) 80 | else 81 | let 82 | val m = (lo+hi) div 2 83 | in 84 | if isBogus (A.sub (g, m)) 85 | then look (lo, m) 86 | else look (m + 1, hi) 87 | end 88 | in 89 | look(0, 1 + A.bound g) 90 | end 91 | 92 | fun check (g, g') = (* if g=g' then () else raise GraphEdge *) () 93 | 94 | fun delete (i, j :: rest) = if i = j then rest else j :: delete (i, rest) 95 | | delete (_, nil) = raise GraphEdge 96 | 97 | fun diddleEdge change { from = (g : graph, i), to = (g' : graph, j) } = 98 | let 99 | val _ = check (g, g') 100 | val NODE { succ = si, pred = pi } = A.sub (g, i) 101 | val _ = A.update (g, i, NODE { succ = change (j, si), pred = pi }) 102 | val NODE { succ = sj, pred = pj } = A.sub (g, j) 103 | val _ = A.update (g, j, NODE { succ = sj, pred = change (i, pj) }) 104 | in 105 | () 106 | end 107 | 108 | val mkEdge = diddleEdge (op ::) 109 | 110 | val rmEdge = diddleEdge delete 111 | 112 | fun nodename (_, i : int) = "n" ^ Int.toString i 113 | end 114 | -------------------------------------------------------------------------------- /lingua-002-hm-inference-sml/src/terms.sml: -------------------------------------------------------------------------------- 1 | structure Terms = 2 | struct 3 | local 4 | open Term 5 | in 6 | val predef = TypeEnv.fromList [ 7 | ("+", TypeScheme.FORALL ([], Type.FUN (Type.INT, Type.FUN (Type.INT, Type.INT)))), 8 | ("-", TypeScheme.FORALL ([], Type.FUN (Type.INT, Type.FUN (Type.INT, Type.INT)))), 9 | ("*", TypeScheme.FORALL ([], Type.FUN (Type.INT, Type.FUN (Type.INT, Type.INT)))), 10 | ("/", TypeScheme.FORALL ([], Type.FUN (Type.INT, Type.FUN (Type.INT, Type.INT)))), 11 | ("zero?", TypeScheme.FORALL ([], Type.FUN (Type.INT, Type.BOOL))) 12 | ] 13 | 14 | val identity = FUN ("a", VAR "a") 15 | val constant = FUN ("a", FUN ("b", VAR "a")) 16 | val compose = FUN ("f", FUN ("g", FUN ("x", APP (VAR "f", APP (VAR "g", VAR "x"))))) 17 | val counter = FUN ("counter", INT 1) 18 | val add10 = FUN ("x", APP (APP (VAR "+", VAR "x"), INT 10)) 19 | 20 | val isZero = FUN ("x", 21 | IF ( 22 | APP (VAR "zero?", VAR "x"), 23 | BOOL true, 24 | BOOL false 25 | ) 26 | ) 27 | 28 | val letTerm = FUN ("x", 29 | LET ( 30 | "y", FUN ("a", VAR "a"), 31 | APP (VAR "y", BOOL true) 32 | ) 33 | ) 34 | 35 | val letPolymorphism = 36 | LET ("id", FUN ("a", VAR "a"), 37 | IF ( 38 | APP (VAR "id", BOOL true), 39 | APP (VAR "id", INT 1), 40 | APP (VAR "id", INT 0) 41 | ) 42 | ) 43 | 44 | (* 45 | * let 46 | * val const = fn y => 47 | * let 48 | * val f = fn x => y 49 | * in 50 | * f 51 | * end 52 | * in 53 | * if const true 1 54 | * then 2 55 | * else 3 56 | * end 57 | *) 58 | val closureLetPolymorphism = 59 | LET ( 60 | "const", FUN ("y", LET ("f", FUN ("x", VAR "y"), VAR "f")), 61 | IF ( 62 | APP (APP (VAR "const", BOOL true), INT 1), 63 | INT 2, 64 | INT 3 65 | ) 66 | ) 67 | 68 | (* 69 | * Taken from: "Wand's Algorithm Extended For the Polymorphic ML-Let". 70 | * 71 | * ```sml 72 | * let 73 | * val x1 = fn y => fn z => (z y) y 74 | * in 75 | * let 76 | * val x2 = fn z => x1 (x1 z) 77 | * in 78 | * let 79 | * val x3 = fn z => x2 (x2 z) 80 | * in 81 | * let 82 | * val x4 = fn z => x3 (x3 z) 83 | * in 84 | * x4 (fn z => z) 85 | * end 86 | * end 87 | * end 88 | * end 89 | * ``` 90 | *) 91 | val nestedLets = 92 | LET ( 93 | "x1", FUN ("y", FUN ("z", APP (APP (VAR "z", VAR "y"), VAR "y"))), 94 | LET ( 95 | "x2", FUN ("z", APP (VAR "x1", APP (VAR "x1", VAR "z"))), 96 | LET ( 97 | "x3", FUN ("z", APP (VAR "x2", APP (VAR "x2", VAR "z"))), 98 | LET ( 99 | "x4", FUN ("z", APP (VAR "x3", APP (VAR "x3", VAR "z"))), 100 | APP (VAR "x4", FUN ("z", VAR "z")) 101 | ) 102 | ) 103 | ) 104 | ) 105 | end 106 | end 107 | -------------------------------------------------------------------------------- /lingua-008-partial-evaluation/src/main/scala/peval/syntax.scala: -------------------------------------------------------------------------------- 1 | package peval 2 | 3 | import cats.implicits._ 4 | 5 | final case class Program(defs: Program.Defs, main: Expr) { 6 | override def toString: String = { 7 | (defs ++ Map("main" -> Def(List.empty, main))) 8 | .map { 9 | case (name, body) => s"[def $name $body]" 10 | } 11 | .mkString("\n") 12 | } 13 | } 14 | 15 | object Program { 16 | type Defs = Map[Def.Name, Def] 17 | } 18 | 19 | final case class Def(params: List[String], body: Expr) { 20 | override def toString: String = 21 | s"[fun [${params.mkString(" ")}] $body]" 22 | } 23 | 24 | object Def { 25 | type Name = String 26 | } 27 | 28 | sealed trait Val extends Any with Product with Serializable { 29 | override def toString: String = 30 | this match { 31 | case Val.I(value) => s"$value" 32 | case Val.B(value) => s"$value" 33 | } 34 | } 35 | 36 | sealed trait Expr extends Product with Serializable { 37 | /** Determine whether the expression tree contains `Apply` nodes. */ 38 | def hasApplies: Boolean = 39 | this match { 40 | case Expr.Const(_) => false 41 | case Expr.Var(_) => false 42 | case Expr.Apply(_, _) => true 43 | case Expr.Prim(_, a, b) => a.hasApplies || b.hasApplies 44 | case Expr.If(a, b, c) => a.hasApplies || b.hasApplies || c.hasApplies 45 | } 46 | 47 | override def toString: String = 48 | this match { 49 | case Expr.Const(value) => value.toString 50 | case Expr.Var(name) => name 51 | case Expr.Apply(fn, args) => s"[$fn ${args.mkString(" ")}]" 52 | case Expr.Prim(op, a, b) => s"[$op $a $b]" 53 | case Expr.If(a, b, c) => s"[if $a $b $c]" 54 | } 55 | } 56 | 57 | sealed trait Op extends Product with Serializable { 58 | override def toString: String = 59 | this match { 60 | case Op.Eqv => "=" 61 | case Op.Add => "+" 62 | case Op.Sub => "-" 63 | case Op.Mul => "*" 64 | } 65 | 66 | def apply(a: Val, b: Val): Val = 67 | (a, b) match { 68 | case (Val.I(va), Val.I(vb)) => 69 | this match { 70 | case Op.Eqv => Val.B(va === vb) 71 | case Op.Add => Val.I(va + vb) 72 | case Op.Sub => Val.I(va - vb) 73 | case Op.Mul => Val.I(va * vb) 74 | } 75 | 76 | case (Val.B(va), Val.B(vb)) => 77 | this match { 78 | case Op.Eqv => Val.B(va === vb) 79 | case _ => sys.error("boolean values can only be compared for equality") 80 | } 81 | 82 | case _ => sys.error("operands of different types") 83 | } 84 | } 85 | 86 | object Val { 87 | final case class I(value: Int) extends AnyVal with Val 88 | final case class B(value: Boolean) extends AnyVal with Val 89 | } 90 | 91 | object Expr { 92 | final case class Const(value: Val) extends Expr 93 | final case class Var(name: String) extends Expr 94 | final case class Apply(fn: String, args: List[Expr]) extends Expr 95 | final case class Prim(op: Op, a: Expr, b: Expr) extends Expr 96 | final case class If(a: Expr, b: Expr, c: Expr) extends Expr 97 | } 98 | 99 | object Op { 100 | case object Eqv extends Op 101 | case object Add extends Op 102 | case object Sub extends Op 103 | case object Mul extends Op 104 | } 105 | --------------------------------------------------------------------------------