From 19950b9f1de3fe5d928cd329d2b5c6f1c2d6e922 Mon Sep 17 00:00:00 2001 From: Dov Murik Date: Fri, 12 Feb 2016 10:32:03 -0500 Subject: [PATCH 01/14] ocaml: Clearer top-level exception handling --- ocaml/step9_try.ml | 10 +++++++++- ocaml/stepA_mal.ml | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/ocaml/step9_try.ml b/ocaml/step9_try.ml index dd220db1fa..2eab66eabb 100644 --- a/ocaml/step9_try.ml +++ b/ocaml/step9_try.ml @@ -138,7 +138,12 @@ let rec main = ignore (rep "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))" repl_env); if Array.length Sys.argv > 1 then - ignore (rep ("(load-file \"" ^ Sys.argv.(1) ^ "\")") repl_env) + try + ignore (rep ("(load-file \"" ^ Sys.argv.(1) ^ "\")") repl_env); + with + | Types.MalExn exc -> + output_string stderr ("Exception: " ^ (print exc) ^ "\n"); + flush stderr else while true do print_string "user> "; @@ -146,6 +151,9 @@ let rec main = try print_endline (rep line repl_env); with End_of_file -> () + | Types.MalExn exc -> + output_string stderr ("Exception: " ^ (print exc) ^ "\n"); + flush stderr | Invalid_argument x -> output_string stderr ("Invalid_argument exception: " ^ x ^ "\n"); flush stderr diff --git a/ocaml/stepA_mal.ml b/ocaml/stepA_mal.ml index 8e582348c7..fc43eb69a2 100644 --- a/ocaml/stepA_mal.ml +++ b/ocaml/stepA_mal.ml @@ -141,7 +141,12 @@ let rec main = ignore (rep "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) (let* (condvar (gensym)) `(let* (~condvar ~(first xs)) (if ~condvar ~condvar (or ~@(rest xs)))))))))" repl_env); if Array.length Sys.argv > 1 then - ignore (rep ("(load-file \"" ^ Sys.argv.(1) ^ "\")") repl_env) + try + ignore (rep ("(load-file \"" ^ Sys.argv.(1) ^ "\")") repl_env); + with + | Types.MalExn exc -> + output_string stderr ("Exception: " ^ (print exc) ^ "\n"); + flush stderr else begin ignore (rep "(println (str \"Mal [\" *host-language* \"]\"))" repl_env); while true do @@ -150,6 +155,9 @@ let rec main = try print_endline (rep line repl_env); with End_of_file -> () + | Types.MalExn exc -> + output_string stderr ("Exception: " ^ (print exc) ^ "\n"); + flush stderr | Invalid_argument x -> output_string stderr ("Invalid_argument exception: " ^ x ^ "\n"); flush stderr From 75787d777fa57bf22c3084ce2dc8e01690810658 Mon Sep 17 00:00:00 2001 From: Prat Date: Mon, 15 Feb 2016 20:25:32 -0500 Subject: [PATCH 02/14] Bump Kotlin version to 1.0. Remove unnecessary cast. --- README.md | 2 +- kotlin/Dockerfile | 4 ++-- kotlin/src/mal/reader.kt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1d8973aaa0..7305978a1f 100644 --- a/README.md +++ b/README.md @@ -371,7 +371,7 @@ julia stepX_YYY.jl *The Kotlin implementation was created by [Javier Fernandez-Ivern](https://github.com/ivern)* -The Kotlin implementation of mal has been tested with Kotlin 1.0.0-beta. +The Kotlin implementation of mal has been tested with Kotlin 1.0. ``` cd kotlin diff --git a/kotlin/Dockerfile b/kotlin/Dockerfile index c3f53fe6ca..2d3ae15aa7 100644 --- a/kotlin/Dockerfile +++ b/kotlin/Dockerfile @@ -25,10 +25,10 @@ WORKDIR /mal RUN apt-get -y install openjdk-7-jdk RUN apt-get -y install unzip -RUN curl -O -J -L https://github.com/JetBrains/kotlin/releases/download/build-1.0.0-beta-4584/kotlin-compiler-1.0.0-beta-4584.zip +RUN curl -O -J -L https://github.com/JetBrains/kotlin/releases/download/build-1.0.0/kotlin-compiler-1.0.0.zip RUN mkdir -p /kotlin-compiler -RUN unzip kotlin-compiler-1.0.0-beta-4584.zip -d /kotlin-compiler +RUN unzip kotlin-compiler-1.0.0.zip -d /kotlin-compiler ENV KOTLIN_HOME /kotlin-compiler/kotlinc ENV PATH $KOTLIN_HOME/bin:$PATH diff --git a/kotlin/src/mal/reader.kt b/kotlin/src/mal/reader.kt index a8a33f05e0..2adddcbeb0 100644 --- a/kotlin/src/mal/reader.kt +++ b/kotlin/src/mal/reader.kt @@ -95,7 +95,7 @@ fun read_hashmap(reader: Reader): MalType { } if (key != null) { - hashMap.assoc_BANG(key as MalString, value as MalType) + hashMap.assoc_BANG(key, value as MalType) } } while (key != null) From b50a4105912c24631f08e23715cc29817bcdcf27 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Tue, 23 Feb 2016 00:49:28 -0600 Subject: [PATCH 03/14] swift3: step0-step5 basics --- swift3/Makefile | 15 +++ swift3/Sources/core.swift | 72 +++++++++++ swift3/Sources/env.swift | 82 ++++++++++++ swift3/Sources/printer.swift | 34 +++++ swift3/Sources/reader.swift | 141 +++++++++++++++++++++ swift3/Sources/step0_repl/main.swift | 10 ++ swift3/Sources/step1_read_print/main.swift | 31 +++++ swift3/Sources/step2_eval/main.swift | 82 ++++++++++++ swift3/Sources/step3_env/main.swift | 107 ++++++++++++++++ swift3/Sources/step4_if_fn_do/main.swift | 119 +++++++++++++++++ swift3/Sources/step5_tco/main.swift | 124 ++++++++++++++++++ swift3/Sources/types.swift | 70 ++++++++++ 12 files changed, 887 insertions(+) create mode 100644 swift3/Makefile create mode 100644 swift3/Sources/core.swift create mode 100644 swift3/Sources/env.swift create mode 100644 swift3/Sources/printer.swift create mode 100644 swift3/Sources/reader.swift create mode 100644 swift3/Sources/step0_repl/main.swift create mode 100644 swift3/Sources/step1_read_print/main.swift create mode 100644 swift3/Sources/step2_eval/main.swift create mode 100644 swift3/Sources/step3_env/main.swift create mode 100644 swift3/Sources/step4_if_fn_do/main.swift create mode 100644 swift3/Sources/step5_tco/main.swift create mode 100644 swift3/Sources/types.swift diff --git a/swift3/Makefile b/swift3/Makefile new file mode 100644 index 0000000000..90ba33bd29 --- /dev/null +++ b/swift3/Makefile @@ -0,0 +1,15 @@ +STEP3_DEPS = Sources/types.swift Sources/reader.swift Sources/printer.swift Sources/env.swift +STEP4_DEPS = $(STEP3_DEPS) Sources/core.swift + +STEPS = step0_repl step1_read_print step2_eval step3_env \ + step4_if_fn_do step5_tco step6_file step7_quote \ + step8_macros step9_try stepA_mal + +step1_read_print step2_eval step3_env: $(STEP3_DEPS) +step4_if_fn_do step5_tco step6_file step7_quote step8_macros step9_try stepA_mal: $(STEP4_DEPS) + +step%: Sources/step%/main.swift + swiftc $+ -o $@ + +clean: + rm -f $(STEPS) diff --git a/swift3/Sources/core.swift b/swift3/Sources/core.swift new file mode 100644 index 0000000000..7b28f022a3 --- /dev/null +++ b/swift3/Sources/core.swift @@ -0,0 +1,72 @@ +func IntOp(op: (Int, Int) -> Int, _ a: MalVal, _ b: MalVal) throws -> MalVal { + switch (a, b) { + case (MV.MalInt(let i1), MV.MalInt(let i2)): + return MV.MalInt(op(i1, i2)) + default: + throw MalError.General(msg: "Invalid IntOp call") + } +} + +func CmpOp(op: (Int, Int) -> Bool, _ a: MalVal, _ b: MalVal) throws -> MalVal { + switch (a, b) { + case (MV.MalInt(let i1), MV.MalInt(let i2)): + return wraptf(op(i1, i2)) + default: + throw MalError.General(msg: "Invalid CmpOp call") + } +} + + + +let core_ns: Dictionary) throws -> MalVal> = [ + "=": { wraptf(equal_Q($0[0], $0[1])) }, + + "pr-str": { + return MV.MalString($0.map { pr_str($0,true) }.joinWithSeparator(" ")) + }, + "str": { + return MV.MalString($0.map { pr_str($0,false) }.joinWithSeparator("")) + }, + "prn": { + print($0.map { pr_str($0,true) }.joinWithSeparator(" ")) + return MV.MalNil + }, + "println": { + print($0.map { pr_str($0,false) }.joinWithSeparator(" ")) + return MV.MalNil + }, + + + "<": { try CmpOp({ $0 < $1}, $0[0], $0[1]) }, + "<=": { try CmpOp({ $0 <= $1}, $0[0], $0[1]) }, + ">": { try CmpOp({ $0 > $1}, $0[0], $0[1]) }, + ">=": { try CmpOp({ $0 >= $1}, $0[0], $0[1]) }, + "+": { try IntOp({ $0 + $1}, $0[0], $0[1]) }, + "-": { try IntOp({ $0 - $1}, $0[0], $0[1]) }, + "*": { try IntOp({ $0 * $1}, $0[0], $0[1]) }, + "/": { try IntOp({ $0 / $1}, $0[0], $0[1]) }, + + "list": { MV.MalList($0) }, + "list?": { + switch $0[0] { + case MV.MalList(_): return MV.MalTrue + default: return MV.MalFalse + } + }, + + "empty?": { + switch $0[0] { + case MV.MalList(let lst): + return lst.count == 0 ? MV.MalTrue : MV.MalFalse + case MV.MalNil: return MV.MalTrue + default: throw MalError.General(msg: "Invalid empty? call") + } + }, + "count": { + switch $0[0] { + case MV.MalList(let lst): return MV.MalInt(lst.count) + case MV.MalNil: return MV.MalInt(0) + default: throw MalError.General(msg: "Invalid count call") + } + } +] diff --git a/swift3/Sources/env.swift b/swift3/Sources/env.swift new file mode 100644 index 0000000000..f88fea8a53 --- /dev/null +++ b/swift3/Sources/env.swift @@ -0,0 +1,82 @@ +class Env { + var outer: Env? = nil + var data: Dictionary = [:] + + init(_ outer: Env? = nil, binds: MalVal? = nil, + exprs: MalVal? = nil) throws { + self.outer = outer + + if binds != nil { + switch (binds!, exprs!) { + case (MalVal.MalList(let bs), MalVal.MalList(let es)): + var pos = bs.startIndex + + bhandle: + while pos < bs.endIndex { + let b = bs[pos] + switch b { + case MalVal.MalSymbol("&"): + switch bs[pos.successor()] { + case MalVal.MalSymbol(let sym): + if pos < es.endIndex { + let slc = es[pos.. Env? { + switch key { + case MalVal.MalSymbol(let str): + if data[str] != nil { + return self + } else if outer != nil { + return try outer!.find(key) + } else { + return nil + } + default: + throw MalError.General(msg: "invalid Env.find call") + } + } + + func get(key: MalVal) throws -> MalVal { + switch key { + case MalVal.MalSymbol(let str): + let env = try self.find(key) + if env == nil { + throw MalError.General(msg: "'\(str)' not found") + } + return env!.data[str]! + default: + throw MalError.General(msg: "invalid Env.find call") + } + } + + func set(key: MalVal, _ val: MalVal) throws -> MalVal { + switch key { + case MalVal.MalSymbol(let str): + data[str] = val + return val + default: + throw MalError.General(msg: "invalid Env.find call") + } + } +} diff --git a/swift3/Sources/printer.swift b/swift3/Sources/printer.swift new file mode 100644 index 0000000000..6b861fe0ec --- /dev/null +++ b/swift3/Sources/printer.swift @@ -0,0 +1,34 @@ + +func pr_str(obj: MalVal, _ print_readably: Bool = true) -> String { + switch obj { + case MalVal.MalList(let lst): + let elems = lst.map { pr_str($0, print_readably) } + return "(" + elems.joinWithSeparator(" ") + ")" + case MalVal.MalVector(let lst): + let elems = lst.map { pr_str($0, print_readably) } + return "[" + elems.joinWithSeparator(" ") + "]" + case MalVal.MalString(let str): + if print_readably { + let s1 = str.stringByReplacingOccurrencesOfString( + "\\", withString: "\\\\") + let s2 = s1.stringByReplacingOccurrencesOfString( + "\"", withString: "\\\"") + let s3 = s2.stringByReplacingOccurrencesOfString( + "\n", withString: "\\n") + return "\"" + s3 + "\"" + } else { + return str + } + case MalVal.MalSymbol(let str): + return str + case MalVal.MalInt(let i): return String(i) + case MalVal.MalNil: return "nil" + case MalVal.MalFalse: return "false" + case MalVal.MalTrue: return "true" + case MalVal.MalFunc(_, nil, _, _): + return "#" + case MalVal.MalFunc(_, let ast, _, let params): + return "(fn* \(pr_str(params![0])) \(pr_str(ast![0])))" + default: return String(obj) + } +} diff --git a/swift3/Sources/reader.swift b/swift3/Sources/reader.swift new file mode 100644 index 0000000000..4a2bbfda70 --- /dev/null +++ b/swift3/Sources/reader.swift @@ -0,0 +1,141 @@ +let token_delim: Set = [ + ";", ",", "\"", "`", " ", "\n", "{", "}", "(", ")", "[", "]" +] + +let int_char: Set = [ + "-", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" +] + +let float_char: Set = [ + ".", "-", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" +] + +let whitespace: Set = [" ", "\t", "\n", ","] + +class Reader { + var str: String + var pos: String.Index + init(_ str: String) { + self.str = str + pos = str.startIndex + } +} + +func read_int(rdr: Reader) -> MalVal { + let start = rdr.pos + for cidx in rdr.pos.. MalVal { + let start = rdr.pos + var escaped = false + if rdr.str[rdr.pos] != "\"" { + throw MalError.Reader(msg: "read_string call on non-string") + } + for cidx in rdr.pos.successor().. rdr.str.endIndex { + throw MalError.Reader(msg: "Expected '\"', got EOF") + } + let matchStr = rdr.str.substringWithRange( + start.successor().. MalVal { + let start = rdr.pos + for cidx in rdr.pos.. MalVal { + if rdr.str.characters.count == 0 { + throw MalError.Reader(msg: "Empty string passed to read_atom") + } + switch rdr.str[rdr.pos] { + case let c where int_char.contains(c): return read_int(rdr) + case "\"": return try read_string(rdr) + default: return try read_symbol(rdr) + } +} + +func read_list(rdr: Reader, start: Character = "(", end: Character = ")") throws -> Array { + if rdr.str[rdr.pos] != start { + throw MalError.Reader(msg: "expected '\(start)'") + } + rdr.pos = rdr.pos.successor() + var lst: [MalVal] = [] + while rdr.pos < rdr.str.endIndex { + if (rdr.str[rdr.pos] == end) { break } + lst.append(try read_form(rdr)) + } + if rdr.pos >= rdr.str.endIndex { + throw MalError.Reader(msg: "Expected '\(end)', got EOF") + } + rdr.pos = rdr.pos.successor() + return lst +} + +func read_form(rdr: Reader) throws -> MalVal { + if rdr.str.characters.count == 0 { + throw MalError.Reader(msg: "Empty string passed to read_form") + } + //print("read_form: \(rdr.pos): \(rdr.str[rdr.pos])") + skip_whitespace(rdr) + var res: MalVal + switch rdr.str[rdr.pos] { + case "(": res = MalVal.MalList(try read_list(rdr)) + case ")": throw MalError.Reader(msg: "unexpected ')'") + + case "[": res = MalVal.MalVector(try read_list(rdr, start: "[", end: "]")) + case "]": throw MalError.Reader(msg: "unexpected ']'") + + default: res = try read_atom(rdr) + } + skip_whitespace(rdr) + return res +} + +func read_str(str: String) throws -> MalVal { + return try read_form(Reader(str)) +} diff --git a/swift3/Sources/step0_repl/main.swift b/swift3/Sources/step0_repl/main.swift new file mode 100644 index 0000000000..2fadc16c56 --- /dev/null +++ b/swift3/Sources/step0_repl/main.swift @@ -0,0 +1,10 @@ +import Foundation + +while true { + print("user> ", terminator: "") + let line = readLine(stripNewline: true) + if line == nil { break } + if line == "" { continue } + + print("\(line!)") +} diff --git a/swift3/Sources/step1_read_print/main.swift b/swift3/Sources/step1_read_print/main.swift new file mode 100644 index 0000000000..60d76aaba6 --- /dev/null +++ b/swift3/Sources/step1_read_print/main.swift @@ -0,0 +1,31 @@ +import Foundation + +func READ(str: String) throws -> MalVal { + return try read_str(str) +} + +func EVAL(ast: MalVal, _ env: String) throws -> MalVal { + return ast +} + +func PRINT(exp: MalVal) -> String { + return pr_str(exp, true) +} + + +func rep(str:String) throws -> String { + return PRINT(try EVAL(try READ(str), "")) +} + +while true { + print("user> ", terminator: "") + let line = readLine(stripNewline: true) + if line == nil { break } + if line == "" { continue } + + do { + print(try rep(line!)) + } catch (MalError.Reader(let msg)) { + print("Error: \(msg)") + } +} diff --git a/swift3/Sources/step2_eval/main.swift b/swift3/Sources/step2_eval/main.swift new file mode 100644 index 0000000000..1b11d3a839 --- /dev/null +++ b/swift3/Sources/step2_eval/main.swift @@ -0,0 +1,82 @@ +import Foundation + +func READ(str: String) throws -> MalVal { + return try read_str(str) +} + +func eval_ast(ast: MalVal, _ env: Dictionary) throws -> MalVal { + switch ast { + case MalVal.MalSymbol(let sym): + if env[sym] == nil { + throw MalError.General(msg: "'\(sym)' not found") + } + return env[sym]! + case MalVal.MalList(let lst): + return MalVal.MalList(try lst.map { try EVAL($0, env) }) + default: + return ast + } +} + +func EVAL(ast: MalVal, _ env: Dictionary) throws -> MalVal { + switch ast { + case MalVal.MalList: true + default: return try eval_ast(ast, env) + } + + switch try eval_ast(ast, env) { + case MalVal.MalList(let elst): + switch elst[0] { + case MalVal.MalFunc(let fn,_,_,_): + let args = Array(elst[1.. String { + return pr_str(exp, true) +} + + +func rep(str:String) throws -> String { + return PRINT(try EVAL(try READ(str), repl_env)) +} + +func IntOp(op: (Int, Int) -> Int, _ a: MalVal, _ b: MalVal) throws -> MalVal { + switch (a, b) { + case (MalVal.MalInt(let i1), MalVal.MalInt(let i2)): + return MalVal.MalInt(op(i1, i2)) + default: + throw MalError.General(msg: "Invalid IntOp call") + } +} + +var repl_env: Dictionary = [ + "+": MalVal.MalFunc({ try IntOp({ $0 + $1}, $0[0], $0[1]) }, + ast:nil, env:nil, params:nil), + "-": MalVal.MalFunc({ try IntOp({ $0 - $1}, $0[0], $0[1]) }, + ast:nil, env:nil, params:nil), + "*": MalVal.MalFunc({ try IntOp({ $0 * $1}, $0[0], $0[1]) }, + ast:nil, env:nil, params:nil), + "/": MalVal.MalFunc({ try IntOp({ $0 / $1}, $0[0], $0[1]) }, + ast:nil, env:nil, params:nil) +] + +while true { + print("user> ", terminator: "") + let line = readLine(stripNewline: true) + if line == nil { break } + if line == "" { continue } + + do { + print(try rep(line!)) + } catch (MalError.Reader(let msg)) { + print("Error: \(msg)") + } catch (MalError.General(let msg)) { + print("Error: \(msg)") + } +} diff --git a/swift3/Sources/step3_env/main.swift b/swift3/Sources/step3_env/main.swift new file mode 100644 index 0000000000..6e7529362e --- /dev/null +++ b/swift3/Sources/step3_env/main.swift @@ -0,0 +1,107 @@ +import Foundation + +func READ(str: String) throws -> MalVal { + return try read_str(str) +} + +func eval_ast(ast: MalVal, _ env: Env) throws -> MalVal { + switch ast { + case MalVal.MalSymbol: + return try env.get(ast) + case MalVal.MalList(let lst): + return MalVal.MalList(try lst.map { try EVAL($0, env) }) + default: + return ast + } +} + +func EVAL(ast: MalVal, _ env: Env) throws -> MalVal { + switch ast { + case MalVal.MalList: true + default: return try eval_ast(ast, env) + } + + switch ast { + case MalVal.MalList(let lst): + switch lst[0] { + case MalVal.MalSymbol("def!"): + return try env.set(lst[1], try EVAL(lst[2], env)) + case MalVal.MalSymbol("let*"): + let let_env = try Env(env) + switch lst[1] { + case MalVal.MalList(let binds): + var idx = binds.startIndex + while idx < binds.endIndex { + let v = try EVAL(binds[idx.successor()], let_env) + try let_env.set(binds[idx], v) + idx = idx.successor().successor() + } + return try EVAL(lst[2], let_env) + default: + throw MalError.General(msg: "Invalid let* bindings") + } + default: + switch try eval_ast(ast, env) { + case MalVal.MalList(let elst): + switch elst[0] { + case MalVal.MalFunc(let fn,_,_,_): + let args = Array(elst[1.. String { + return pr_str(exp, true) +} + + +func rep(str:String) throws -> String { + return PRINT(try EVAL(try READ(str), repl_env)) +} + +func IntOp(op: (Int, Int) -> Int, _ a: MalVal, _ b: MalVal) throws -> MalVal { + switch (a, b) { + case (MalVal.MalInt(let i1), MalVal.MalInt(let i2)): + return MalVal.MalInt(op(i1, i2)) + default: + throw MalError.General(msg: "Invalid IntOp call") + } +} + +var repl_env: Env = try Env() +try repl_env.set(MalVal.MalSymbol("+"), + MalVal.MalFunc({ try IntOp({ $0 + $1}, $0[0], $0[1]) }, + ast:nil, env:nil, params:nil)) +try repl_env.set(MalVal.MalSymbol("-"), + MalVal.MalFunc({ try IntOp({ $0 - $1}, $0[0], $0[1]) }, + ast:nil, env:nil, params:nil)) +try repl_env.set(MalVal.MalSymbol("*"), + MalVal.MalFunc({ try IntOp({ $0 * $1}, $0[0], $0[1]) }, + ast:nil, env:nil, params:nil)) +try repl_env.set(MalVal.MalSymbol("/"), + MalVal.MalFunc({ try IntOp({ $0 / $1}, $0[0], $0[1]) }, + ast:nil, env:nil, params:nil)) + + +while true { + print("user> ", terminator: "") + let line = readLine(stripNewline: true) + if line == nil { break } + if line == "" { continue } + + do { + print(try rep(line!)) + } catch (MalError.Reader(let msg)) { + print("Error: \(msg)") + } catch (MalError.General(let msg)) { + print("Error: \(msg)") + } +} diff --git a/swift3/Sources/step4_if_fn_do/main.swift b/swift3/Sources/step4_if_fn_do/main.swift new file mode 100644 index 0000000000..61b1552011 --- /dev/null +++ b/swift3/Sources/step4_if_fn_do/main.swift @@ -0,0 +1,119 @@ +import Foundation + +func READ(str: String) throws -> MalVal { + return try read_str(str) +} + +func eval_ast(ast: MalVal, _ env: Env) throws -> MalVal { + switch ast { + case MalVal.MalSymbol: + return try env.get(ast) + case MalVal.MalList(let lst): + return MalVal.MalList(try lst.map { try EVAL($0, env) }) + default: + return ast + } +} + +func EVAL(ast: MalVal, _ env: Env) throws -> MalVal { + switch ast { + case MalVal.MalList: true + default: return try eval_ast(ast, env) + } + + switch ast { + case MalVal.MalList(let lst): + switch lst[0] { + case MalVal.MalSymbol("def!"): + return try env.set(lst[1], try EVAL(lst[2], env)) + case MalVal.MalSymbol("let*"): + let let_env = try Env(env) + switch lst[1] { + case MalVal.MalList(let binds): + var idx = binds.startIndex + while idx < binds.endIndex { + let v = try EVAL(binds[idx.successor()], let_env) + try let_env.set(binds[idx], v) + idx = idx.successor().successor() + } + return try EVAL(lst[2], let_env) + default: + throw MalError.General(msg: "Invalid let* bindings") + } + case MalVal.MalSymbol("do"): + let slc = lst[lst.startIndex.successor().. 3 { + return try EVAL(lst[3], env) + } else { + return MalVal.MalNil + } + default: + return try EVAL(lst[2], env) + } + case MalVal.MalSymbol("fn*"): + return MalVal.MalFunc( { + return try EVAL(lst[2], Env(env, binds: lst[1], + exprs: MalVal.MalList($0))) + }, ast:nil, env:nil, params:nil) + default: + switch try eval_ast(ast, env) { + case MalVal.MalList(let elst): + switch elst[0] { + case MalVal.MalFunc(let fn, _, _, _): + let args = Array(elst[1.. String { + return pr_str(exp, true) +} + + +func rep(str:String) throws -> String { + return PRINT(try EVAL(try READ(str), repl_env)) +} + +var repl_env: Env = try Env() + +// core.swift: defined using Swift +for (k, fn) in core_ns { + try repl_env.set(MalVal.MalSymbol(k), + MalVal.MalFunc(fn,ast:nil,env:nil,params:nil)) +} + +// core.mal: defined using the language itself +try rep("(def! not (fn* (a) (if a false true)))") + + +while true { + print("user> ", terminator: "") + let line = readLine(stripNewline: true) + if line == nil { break } + if line == "" { continue } + + do { + print(try rep(line!)) + } catch (MalError.Reader(let msg)) { + print("Error: \(msg)") + } catch (MalError.General(let msg)) { + print("Error: \(msg)") + } +} diff --git a/swift3/Sources/step5_tco/main.swift b/swift3/Sources/step5_tco/main.swift new file mode 100644 index 0000000000..df1b43903b --- /dev/null +++ b/swift3/Sources/step5_tco/main.swift @@ -0,0 +1,124 @@ +import Foundation + +func READ(str: String) throws -> MalVal { + return try read_str(str) +} + +func eval_ast(ast: MalVal, _ env: Env) throws -> MalVal { + switch ast { + case MalVal.MalSymbol: + return try env.get(ast) + case MalVal.MalList(let lst): + return MalVal.MalList(try lst.map { try EVAL($0, env) }) + default: + return ast + } +} + +func EVAL(orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { + var ast = orig_ast, env = orig_env + while true { + switch ast { + case MalVal.MalList: true + default: return try eval_ast(ast, env) + } + + switch ast { + case MalVal.MalList(let lst): + switch lst[0] { + case MalVal.MalSymbol("def!"): + return try env.set(lst[1], try EVAL(lst[2], env)) + case MalVal.MalSymbol("let*"): + let let_env = try Env(env) + switch lst[1] { + case MalVal.MalList(let binds): + var idx = binds.startIndex + while idx < binds.endIndex { + let v = try EVAL(binds[idx.successor()], let_env) + try let_env.set(binds[idx], v) + idx = idx.successor().successor() + } + env = let_env + ast = lst[2] // TCO + default: + throw MalError.General(msg: "Invalid let* bindings") + } + case MalVal.MalSymbol("do"): + let slc = lst[lst.startIndex.successor().. 3 { + ast = lst[3] // TCO + } else { + return MalVal.MalNil + } + default: + ast = lst[2] // TCO + } + case MalVal.MalSymbol("fn*"): + return MalVal.MalFunc( { + return try EVAL(lst[2], Env(env, binds: lst[1], + exprs: MalVal.MalList($0))) + }, ast:[lst[2]], env:env, params:[lst[1]]) + default: + switch try eval_ast(ast, env) { + case MalVal.MalList(let elst): + switch elst[0] { + case MalVal.MalFunc(let fn, nil, _, _): + let args = Array(elst[1.. String { + return pr_str(exp, true) +} + + +func rep(str:String) throws -> String { + return PRINT(try EVAL(try READ(str), repl_env)) +} + +var repl_env: Env = try Env() + +// core.swift: defined using Swift +for (k, fn) in core_ns { + try repl_env.set(MalVal.MalSymbol(k), + MalVal.MalFunc(fn,ast:nil,env:nil,params:nil)) +} + +// core.mal: defined using the language itself +try rep("(def! not (fn* (a) (if a false true)))") + + +while true { + print("user> ", terminator: "") + let line = readLine(stripNewline: true) + if line == nil { break } + if line == "" { continue } + + do { + print(try rep(line!)) + } catch (MalError.Reader(let msg)) { + print("Error: \(msg)") + } catch (MalError.General(let msg)) { + print("Error: \(msg)") + } +} diff --git a/swift3/Sources/types.swift b/swift3/Sources/types.swift new file mode 100644 index 0000000000..9cdb849f57 --- /dev/null +++ b/swift3/Sources/types.swift @@ -0,0 +1,70 @@ + +enum MalError: ErrorType { + case Reader(msg: String) + case General(msg: String) +} + +enum MalVal { + case MalNil + case MalTrue + case MalFalse + case MalInt(Int) + case MalFloat(Float) + case MalString(String) + case MalSymbol(String) + case MalList(Array) + case MalVector(Array) + // TODO: ast and params wrapped in arrays because otherwise + // compiler throws a fault + case MalFunc((Array) throws -> MalVal, + ast: Array?, env: Env?, params: Array?) +} + +typealias MV = MalVal + +// General functions + +func wraptf(a: Bool) -> MalVal { + return a ? MV.MalTrue : MV.MalFalse +} + +func cmp_seqs(a: Array, _ b: Array) -> Bool { + if a.count != b.count { return false } + var idx = a.startIndex + while idx < a.endIndex { + if !equal_Q(a[idx], b[idx]) { return false } + idx = idx.successor() + } + return true +} + +func equal_Q(a: MalVal, _ b: MalVal) -> Bool { + switch (a, b) { + case (MV.MalNil, MV.MalNil): return true + case (MV.MalFalse, MV.MalFalse): return true + case (MV.MalTrue, MV.MalTrue): return true + case (MV.MalInt(let i1), MV.MalInt(let i2)): return i1 == i2 + case (MV.MalString(let s1), MV.MalString(let s2)): return s1 == s2 + case (MV.MalSymbol(let s1), MV.MalSymbol(let s2)): return s1 == s2 + case (MV.MalList(let l1), MV.MalList(let l2)): + return cmp_seqs(l1, l2) + case (MV.MalList(let l1), MV.MalVector(let l2)): + return cmp_seqs(l1, l2) + case (MV.MalVector(let l1), MV.MalList(let l2)): + return cmp_seqs(l1, l2) + case (MV.MalVector(let l1), MV.MalVector(let l2)): + return cmp_seqs(l1, l2) + default: + return false + } +} + +func rest(a: MalVal) throws -> MalVal { + switch a { + case MV.MalList(let lst): + let slc = lst[lst.startIndex.successor().. Date: Wed, 24 Feb 2016 00:27:23 -0600 Subject: [PATCH 04/14] swift3: steps6-A, vectors, maps, keywords, meta. Everything except conj and meta on lists, vectors and hash-maps. --- Makefile | 5 +- swift3/Makefile | 14 + swift3/Sources/core.swift | 26 ++ swift3/Sources/env.swift | 56 ++-- swift3/Sources/printer.swift | 20 +- swift3/Sources/reader.swift | 89 ++++++- swift3/Sources/step1_read_print/main.swift | 4 + swift3/Sources/step2_eval/main.swift | 24 +- swift3/Sources/step3_env/main.swift | 42 ++- swift3/Sources/step4_if_fn_do/main.swift | 40 ++- swift3/Sources/step5_tco/main.swift | 50 ++-- swift3/Sources/step6_file/main.swift | 155 +++++++++++ swift3/Sources/step7_quote/main.swift | 193 ++++++++++++++ swift3/Sources/step8_macros/main.swift | 245 ++++++++++++++++++ swift3/Sources/step9_try/main.swift | 280 ++++++++++++++++++++ swift3/Sources/stepA_mal/main.swift | 284 +++++++++++++++++++++ 16 files changed, 1434 insertions(+), 93 deletions(-) create mode 100644 swift3/Sources/step6_file/main.swift create mode 100644 swift3/Sources/step7_quote/main.swift create mode 100644 swift3/Sources/step8_macros/main.swift create mode 100644 swift3/Sources/step9_try/main.swift create mode 100644 swift3/Sources/stepA_mal/main.swift diff --git a/Makefile b/Makefile index b2d0c60132..5b6bb50a74 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ mal_TEST_OPTS = --start-timeout 60 --test-timeout 120 IMPLS = awk bash c d clojure coffee cpp crystal cs erlang elixir es6 \ factor forth fsharp go groovy guile haskell haxe java julia \ js kotlin lua make mal ocaml matlab miniMAL nim perl php ps \ - python r racket rpython ruby rust scala swift tcl vb vimscript + python r racket rpython ruby rust scala swift swift3 tcl vb vimscript step0 = step0_repl step1 = step1_read_print @@ -73,6 +73,7 @@ STEP5_EXCLUDES += php # test completes, even at 100,000 STEP5_EXCLUDES += racket # test completes STEP5_EXCLUDES += ruby # test completes, even at 100,000 STEP5_EXCLUDES += rust # no catching stack overflows +STEP5_EXCLUDES += swift3 # no catching stack overflows STEP5_EXCLUDES += ocaml # test completes, even at 1,000,000 STEP5_EXCLUDES += vb # completes at 10,000 STEP5_EXCLUDES += crystal # test completes, even at 1,000,000 @@ -147,6 +148,7 @@ ruby_STEP_TO_PROG = ruby/$($(1)).rb rust_STEP_TO_PROG = rust/target/release/$($(1)) scala_STEP_TO_PROG = scala/$($(1)).scala swift_STEP_TO_PROG = swift/$($(1)) +swift3_STEP_TO_PROG = swift3/$($(1)) tcl_STEP_TO_PROG = tcl/$($(1)).tcl vb_STEP_TO_PROG = vb/$($(1)).exe vimscript_STEP_TO_PROG = vimscript/$($(1)).vim @@ -205,6 +207,7 @@ ruby_RUNSTEP = ruby ../$(2) $(3) rust_RUNSTEP = ../$(2) $(3) scala_RUNSTEP = sbt 'run-main $($(1))$(if $(3), $(3),)' swift_RUNSTEP = ../$(2) $(3) +swift3_RUNSTEP = ../$(2) $(3) tcl_RUNSTEP = tclsh ../$(2) --raw $(3) vb_RUNSTEP = mono ../$(2) --raw $(3) vimscript_RUNSTEP = ./run_vimscript.sh ../$(2) $(3) diff --git a/swift3/Makefile b/swift3/Makefile index 90ba33bd29..c4e2deeeb9 100644 --- a/swift3/Makefile +++ b/swift3/Makefile @@ -1,10 +1,15 @@ STEP3_DEPS = Sources/types.swift Sources/reader.swift Sources/printer.swift Sources/env.swift STEP4_DEPS = $(STEP3_DEPS) Sources/core.swift +SOURCES = $(STEP4_DEPS) Sources/stepA_mal/main.swift +SOURCES_LISP = Sources/env.swift Sources/core.swift Sources/stepA_mal/main.swift + STEPS = step0_repl step1_read_print step2_eval step3_env \ step4_if_fn_do step5_tco step6_file step7_quote \ step8_macros step9_try stepA_mal +all: $(STEPS) + step1_read_print step2_eval step3_env: $(STEP3_DEPS) step4_if_fn_do step5_tco step6_file step7_quote step8_macros step9_try stepA_mal: $(STEP4_DEPS) @@ -13,3 +18,12 @@ step%: Sources/step%/main.swift clean: rm -f $(STEPS) + +.PHONY: stats tests + +stats: $(SOURCES) + @wc $^ + @printf "%5s %5s %5s %s\n" `grep -E "^[[:space:]]*//|^[[:space:]]*$$" $^ | wc` "[comments/blanks]" +stats-lisp: $(SOURCES_LISP) + @wc $^ + @printf "%5s %5s %5s %s\n" `grep -E "^[[:space:]]*//|^[[:space:]]*$$" $^ | wc` "[comments/blanks]" diff --git a/swift3/Sources/core.swift b/swift3/Sources/core.swift index 7b28f022a3..93384e98aa 100644 --- a/swift3/Sources/core.swift +++ b/swift3/Sources/core.swift @@ -1,3 +1,5 @@ +import Glibc + func IntOp(op: (Int, Int) -> Int, _ a: MalVal, _ b: MalVal) throws -> MalVal { switch (a, b) { case (MV.MalInt(let i1), MV.MalInt(let i2)): @@ -35,6 +37,30 @@ let core_ns: Dictionary) throws -> MalVal> = [ print($0.map { pr_str($0,false) }.joinWithSeparator(" ")) return MV.MalNil }, + "read-string": { + switch $0[0] { + case MV.MalString(let str): return try read_str(str) + default: throw MalError.General(msg: "Invalid read-string call") + } + }, + "slurp": { + switch $0[0] { + case MV.MalString(let file): + // TODO: replace with this when it is available + // let data = try String(contentsOfFile: file, encoding: NSUTF8StringEncoding) + + let BUFSIZE = 1024 + var pp = popen("cat " + file, "r") + var buf = [CChar](count:BUFSIZE, repeatedValue:CChar(0)) + var data = String() + + while fgets(&buf, Int32(BUFSIZE), pp) != nil { + data = data + String.fromCString(buf)!; + } + return MalVal.MalString(data) + default: throw MalError.General(msg: "Invalid slurp call") + } + }, "<": { try CmpOp({ $0 < $1}, $0[0], $0[1]) }, diff --git a/swift3/Sources/env.swift b/swift3/Sources/env.swift index f88fea8a53..95edf46fb5 100644 --- a/swift3/Sources/env.swift +++ b/swift3/Sources/env.swift @@ -7,37 +7,43 @@ class Env { self.outer = outer if binds != nil { + var bs = Array(), es = Array() + //print("binds: \(binds), exprs: \(exprs)") switch (binds!, exprs!) { - case (MalVal.MalList(let bs), MalVal.MalList(let es)): - var pos = bs.startIndex + case (MalVal.MalList(let l1), MalVal.MalList(let l2)): + bs = l1; es = l2 + case (MalVal.MalVector(let l1), MalVal.MalList(let l2)): + bs = l1; es = l2 + default: + throw MalError.General(msg: "invalid Env init call") + } - bhandle: - while pos < bs.endIndex { - let b = bs[pos] - switch b { - case MalVal.MalSymbol("&"): - switch bs[pos.successor()] { - case MalVal.MalSymbol(let sym): - if pos < es.endIndex { - let slc = es[pos.. String { case MalVal.MalVector(let lst): let elems = lst.map { pr_str($0, print_readably) } return "[" + elems.joinWithSeparator(" ") + "]" + case MalVal.MalHashMap(let dict): + let elems = dict.map { + pr_str(MalVal.MalString($0), print_readably) + + " " + pr_str($1, print_readably) + } + return "{" + elems.joinWithSeparator(" ") + "}" case MalVal.MalString(let str): - if print_readably { + //print("kw: '\(str[str.startIndex])'") + if str.characters.count > 0 && str[str.startIndex] == "\u{029e}" { + return ":" + str[str.startIndex.successor().. String { case MalVal.MalNil: return "nil" case MalVal.MalFalse: return "false" case MalVal.MalTrue: return "true" - case MalVal.MalFunc(_, nil, _, _): + case MalVal.MalFunc(_, nil, _, _, _, _): return "#" - case MalVal.MalFunc(_, let ast, _, let params): + case MalVal.MalFunc(_, let ast, _, let params, _, _): return "(fn* \(pr_str(params![0])) \(pr_str(ast![0])))" - default: return String(obj) + case MalVal.MalAtom(let ma): + return "(atom \(pr_str(ma.val, print_readably)))" + default: + return String(obj) } } diff --git a/swift3/Sources/reader.swift b/swift3/Sources/reader.swift index 4a2bbfda70..7efbc2e45f 100644 --- a/swift3/Sources/reader.swift +++ b/swift3/Sources/reader.swift @@ -19,6 +19,7 @@ class Reader { self.str = str pos = str.startIndex } + func next() { pos = pos.successor() } } func read_int(rdr: Reader) -> MalVal { @@ -36,10 +37,19 @@ func read_int(rdr: Reader) -> MalVal { } } -func skip_whitespace(rdr: Reader) { +func skip_whitespace_and_comments(rdr: Reader) { + var in_comment = false for cidx in rdr.pos.. MalVal { return MalVal.MalString(s3) } -func read_symbol(rdr: Reader) throws -> MalVal { +func read_token(rdr: Reader) -> String { let start = rdr.pos for cidx in rdr.pos.. MalVal { + let tok = read_token(rdr) + switch tok { case "nil": return MalVal.MalNil case "true": return MalVal.MalTrue case "false": return MalVal.MalFalse - default: return MalVal.MalSymbol(matchStr) + default: return MalVal.MalSymbol(tok) } } @@ -93,9 +107,17 @@ func read_atom(rdr: Reader) throws -> MalVal { throw MalError.Reader(msg: "Empty string passed to read_atom") } switch rdr.str[rdr.pos] { - case let c where int_char.contains(c): return read_int(rdr) - case "\"": return try read_string(rdr) - default: return try read_symbol(rdr) + case "-" where !int_char.contains(rdr.str[rdr.pos.successor()]): + return try read_symbol(rdr) + case let c where int_char.contains(c): + return read_int(rdr) + case "\"": + return try read_string(rdr) + case ":": + rdr.next() + return MalVal.MalString("\u{029e}\(read_token(rdr))") + default: + return try read_symbol(rdr) } } @@ -103,7 +125,7 @@ func read_list(rdr: Reader, start: Character = "(", end: Character = ")") throws if rdr.str[rdr.pos] != start { throw MalError.Reader(msg: "expected '\(start)'") } - rdr.pos = rdr.pos.successor() + rdr.next() var lst: [MalVal] = [] while rdr.pos < rdr.str.endIndex { if (rdr.str[rdr.pos] == end) { break } @@ -112,7 +134,7 @@ func read_list(rdr: Reader, start: Character = "(", end: Character = ")") throws if rdr.pos >= rdr.str.endIndex { throw MalError.Reader(msg: "Expected '\(end)', got EOF") } - rdr.pos = rdr.pos.successor() + rdr.next() return lst } @@ -121,21 +143,60 @@ func read_form(rdr: Reader) throws -> MalVal { throw MalError.Reader(msg: "Empty string passed to read_form") } //print("read_form: \(rdr.pos): \(rdr.str[rdr.pos])") - skip_whitespace(rdr) + skip_whitespace_and_comments(rdr) var res: MalVal switch rdr.str[rdr.pos] { + // reader macros/transforms + case "'": + rdr.next() + return MalVal.MalList([MalVal.MalSymbol("quote"), + try read_form(rdr)]) + case "`": + rdr.next() + return MalVal.MalList([MalVal.MalSymbol("quasiquote"), + try read_form(rdr)]) + case "~": + switch rdr.str[rdr.pos.successor()] { + case "@": + rdr.next() + rdr.next() + return MalVal.MalList([MalVal.MalSymbol("splice-unquote"), + try read_form(rdr)]) + default: + rdr.next() + return MalVal.MalList([MalVal.MalSymbol("unquote"), + try read_form(rdr)]) + } + case "^": + rdr.next() + let meta = try read_form(rdr) + return MalVal.MalList([MalVal.MalSymbol("with-meta"), + try read_form(rdr), + meta]) + case "@": + rdr.next() + return MalVal.MalList([MalVal.MalSymbol("deref"), + try read_form(rdr)]) + + // list case "(": res = MalVal.MalList(try read_list(rdr)) case ")": throw MalError.Reader(msg: "unexpected ')'") + // vector case "[": res = MalVal.MalVector(try read_list(rdr, start: "[", end: "]")) case "]": throw MalError.Reader(msg: "unexpected ']'") + // hash-map + case "{": res = try hash_map(try read_list(rdr, start: "{", end: "}")) + case "}": throw MalError.Reader(msg: "unexpected '}'") + + // atom default: res = try read_atom(rdr) } - skip_whitespace(rdr) + skip_whitespace_and_comments(rdr) return res } func read_str(str: String) throws -> MalVal { - return try read_form(Reader(str)) + return try read_form(Reader(str)) } diff --git a/swift3/Sources/step1_read_print/main.swift b/swift3/Sources/step1_read_print/main.swift index 60d76aaba6..a37d0e7876 100644 --- a/swift3/Sources/step1_read_print/main.swift +++ b/swift3/Sources/step1_read_print/main.swift @@ -1,18 +1,22 @@ import Foundation +// read func READ(str: String) throws -> MalVal { return try read_str(str) } +// eval func EVAL(ast: MalVal, _ env: String) throws -> MalVal { return ast } +// print func PRINT(exp: MalVal) -> String { return pr_str(exp, true) } +// repl func rep(str:String) throws -> String { return PRINT(try EVAL(try READ(str), "")) } diff --git a/swift3/Sources/step2_eval/main.swift b/swift3/Sources/step2_eval/main.swift index 1b11d3a839..fa84c01d15 100644 --- a/swift3/Sources/step2_eval/main.swift +++ b/swift3/Sources/step2_eval/main.swift @@ -1,9 +1,11 @@ import Foundation +// read func READ(str: String) throws -> MalVal { return try read_str(str) } +// eval func eval_ast(ast: MalVal, _ env: Dictionary) throws -> MalVal { switch ast { case MalVal.MalSymbol(let sym): @@ -13,6 +15,12 @@ func eval_ast(ast: MalVal, _ env: Dictionary) throws -> MalVal { return env[sym]! case MalVal.MalList(let lst): return MalVal.MalList(try lst.map { try EVAL($0, env) }) + case MalVal.MalVector(let lst): + return MalVal.MalVector(try lst.map { try EVAL($0, env) }) + case MalVal.MalHashMap(let dict): + var new_dict = Dictionary() + for (k,v) in dict { new_dict[k] = try EVAL(v, env) } + return MalVal.MalHashMap(new_dict) default: return ast } @@ -27,7 +35,7 @@ func EVAL(ast: MalVal, _ env: Dictionary) throws -> MalVal { switch try eval_ast(ast, env) { case MalVal.MalList(let elst): switch elst[0] { - case MalVal.MalFunc(let fn,_,_,_): + case MalVal.MalFunc(let fn,_,_,_,_,_): let args = Array(elst[1..) throws -> MalVal { } } +// print func PRINT(exp: MalVal) -> String { return pr_str(exp, true) } +// repl func rep(str:String) throws -> String { return PRINT(try EVAL(try READ(str), repl_env)) } @@ -57,13 +67,17 @@ func IntOp(op: (Int, Int) -> Int, _ a: MalVal, _ b: MalVal) throws -> MalVal { var repl_env: Dictionary = [ "+": MalVal.MalFunc({ try IntOp({ $0 + $1}, $0[0], $0[1]) }, - ast:nil, env:nil, params:nil), + ast:nil, env:nil, params:nil, + macro:false, meta:nil), "-": MalVal.MalFunc({ try IntOp({ $0 - $1}, $0[0], $0[1]) }, - ast:nil, env:nil, params:nil), + ast:nil, env:nil, params:nil, + macro:false, meta:nil), "*": MalVal.MalFunc({ try IntOp({ $0 * $1}, $0[0], $0[1]) }, - ast:nil, env:nil, params:nil), + ast:nil, env:nil, params:nil, + macro:false, meta:nil), "/": MalVal.MalFunc({ try IntOp({ $0 / $1}, $0[0], $0[1]) }, - ast:nil, env:nil, params:nil) + ast:nil, env:nil, params:nil, + macro:false, meta:nil), ] while true { diff --git a/swift3/Sources/step3_env/main.swift b/swift3/Sources/step3_env/main.swift index 6e7529362e..faddd7e064 100644 --- a/swift3/Sources/step3_env/main.swift +++ b/swift3/Sources/step3_env/main.swift @@ -1,15 +1,23 @@ import Foundation +// read func READ(str: String) throws -> MalVal { return try read_str(str) } +// eval func eval_ast(ast: MalVal, _ env: Env) throws -> MalVal { switch ast { case MalVal.MalSymbol: return try env.get(ast) case MalVal.MalList(let lst): return MalVal.MalList(try lst.map { try EVAL($0, env) }) + case MalVal.MalVector(let lst): + return MalVal.MalVector(try lst.map { try EVAL($0, env) }) + case MalVal.MalHashMap(let dict): + var new_dict = Dictionary() + for (k,v) in dict { new_dict[k] = try EVAL(v, env) } + return MalVal.MalHashMap(new_dict) default: return ast } @@ -28,23 +36,25 @@ func EVAL(ast: MalVal, _ env: Env) throws -> MalVal { return try env.set(lst[1], try EVAL(lst[2], env)) case MalVal.MalSymbol("let*"): let let_env = try Env(env) + var binds = Array() switch lst[1] { - case MalVal.MalList(let binds): - var idx = binds.startIndex - while idx < binds.endIndex { - let v = try EVAL(binds[idx.successor()], let_env) - try let_env.set(binds[idx], v) - idx = idx.successor().successor() - } - return try EVAL(lst[2], let_env) + case MalVal.MalList(let l): binds = l + case MalVal.MalVector(let l): binds = l default: throw MalError.General(msg: "Invalid let* bindings") } + var idx = binds.startIndex + while idx < binds.endIndex { + let v = try EVAL(binds[idx.successor()], let_env) + try let_env.set(binds[idx], v) + idx = idx.successor().successor() + } + return try EVAL(lst[2], let_env) default: switch try eval_ast(ast, env) { case MalVal.MalList(let elst): switch elst[0] { - case MalVal.MalFunc(let fn,_,_,_): + case MalVal.MalFunc(let fn,_,_,_,_,_): let args = Array(elst[1.. MalVal { } } +// print func PRINT(exp: MalVal) -> String { return pr_str(exp, true) } +// repl func rep(str:String) throws -> String { return PRINT(try EVAL(try READ(str), repl_env)) } @@ -79,16 +91,20 @@ func IntOp(op: (Int, Int) -> Int, _ a: MalVal, _ b: MalVal) throws -> MalVal { var repl_env: Env = try Env() try repl_env.set(MalVal.MalSymbol("+"), MalVal.MalFunc({ try IntOp({ $0 + $1}, $0[0], $0[1]) }, - ast:nil, env:nil, params:nil)) + ast:nil, env:nil, params:nil, + macro:false, meta:nil)) try repl_env.set(MalVal.MalSymbol("-"), MalVal.MalFunc({ try IntOp({ $0 - $1}, $0[0], $0[1]) }, - ast:nil, env:nil, params:nil)) + ast:nil, env:nil, params:nil, + macro:false, meta:nil)) try repl_env.set(MalVal.MalSymbol("*"), MalVal.MalFunc({ try IntOp({ $0 * $1}, $0[0], $0[1]) }, - ast:nil, env:nil, params:nil)) + ast:nil, env:nil, params:nil, + macro:false, meta:nil)) try repl_env.set(MalVal.MalSymbol("/"), MalVal.MalFunc({ try IntOp({ $0 / $1}, $0[0], $0[1]) }, - ast:nil, env:nil, params:nil)) + ast:nil, env:nil, params:nil, + macro:false, meta:nil)) while true { diff --git a/swift3/Sources/step4_if_fn_do/main.swift b/swift3/Sources/step4_if_fn_do/main.swift index 61b1552011..24a36c9af6 100644 --- a/swift3/Sources/step4_if_fn_do/main.swift +++ b/swift3/Sources/step4_if_fn_do/main.swift @@ -1,15 +1,23 @@ import Foundation +// read func READ(str: String) throws -> MalVal { return try read_str(str) } +// eval func eval_ast(ast: MalVal, _ env: Env) throws -> MalVal { switch ast { case MalVal.MalSymbol: return try env.get(ast) case MalVal.MalList(let lst): return MalVal.MalList(try lst.map { try EVAL($0, env) }) + case MalVal.MalVector(let lst): + return MalVal.MalVector(try lst.map { try EVAL($0, env) }) + case MalVal.MalHashMap(let dict): + var new_dict = Dictionary() + for (k,v) in dict { new_dict[k] = try EVAL(v, env) } + return MalVal.MalHashMap(new_dict) default: return ast } @@ -28,21 +36,23 @@ func EVAL(ast: MalVal, _ env: Env) throws -> MalVal { return try env.set(lst[1], try EVAL(lst[2], env)) case MalVal.MalSymbol("let*"): let let_env = try Env(env) + var binds = Array() switch lst[1] { - case MalVal.MalList(let binds): - var idx = binds.startIndex - while idx < binds.endIndex { - let v = try EVAL(binds[idx.successor()], let_env) - try let_env.set(binds[idx], v) - idx = idx.successor().successor() - } - return try EVAL(lst[2], let_env) + case MalVal.MalList(let l): binds = l + case MalVal.MalVector(let l): binds = l default: throw MalError.General(msg: "Invalid let* bindings") } + var idx = binds.startIndex + while idx < binds.endIndex { + let v = try EVAL(binds[idx.successor()], let_env) + try let_env.set(binds[idx], v) + idx = idx.successor().successor() + } + return try EVAL(lst[2], let_env) case MalVal.MalSymbol("do"): let slc = lst[lst.startIndex.successor().. MalVal { return try EVAL(lst[2], env) } case MalVal.MalSymbol("fn*"): - return MalVal.MalFunc( { + return MalVal.MalFunc( { return try EVAL(lst[2], Env(env, binds: lst[1], exprs: MalVal.MalList($0))) - }, ast:nil, env:nil, params:nil) + }, ast:nil, env:nil, params:nil, + macro:false, meta:nil) default: switch try eval_ast(ast, env) { case MalVal.MalList(let elst): switch elst[0] { - case MalVal.MalFunc(let fn, _, _, _): + case MalVal.MalFunc(let fn,_,_,_,_,_): let args = Array(elst[1.. MalVal { } } +// print func PRINT(exp: MalVal) -> String { return pr_str(exp, true) } +// repl func rep(str:String) throws -> String { return PRINT(try EVAL(try READ(str), repl_env)) } @@ -96,7 +109,8 @@ var repl_env: Env = try Env() // core.swift: defined using Swift for (k, fn) in core_ns { try repl_env.set(MalVal.MalSymbol(k), - MalVal.MalFunc(fn,ast:nil,env:nil,params:nil)) + MalVal.MalFunc(fn,ast:nil,env:nil,params:nil, + macro:false,meta:nil)) } // core.mal: defined using the language itself diff --git a/swift3/Sources/step5_tco/main.swift b/swift3/Sources/step5_tco/main.swift index df1b43903b..a7a73811bf 100644 --- a/swift3/Sources/step5_tco/main.swift +++ b/swift3/Sources/step5_tco/main.swift @@ -1,15 +1,23 @@ import Foundation +// read func READ(str: String) throws -> MalVal { return try read_str(str) } +// eval func eval_ast(ast: MalVal, _ env: Env) throws -> MalVal { switch ast { case MalVal.MalSymbol: return try env.get(ast) case MalVal.MalList(let lst): return MalVal.MalList(try lst.map { try EVAL($0, env) }) + case MalVal.MalVector(let lst): + return MalVal.MalVector(try lst.map { try EVAL($0, env) }) + case MalVal.MalHashMap(let dict): + var new_dict = Dictionary() + for (k,v) in dict { new_dict[k] = try EVAL(v, env) } + return MalVal.MalHashMap(new_dict) default: return ast } @@ -30,23 +38,25 @@ func EVAL(orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { return try env.set(lst[1], try EVAL(lst[2], env)) case MalVal.MalSymbol("let*"): let let_env = try Env(env) + var binds = Array() switch lst[1] { - case MalVal.MalList(let binds): - var idx = binds.startIndex - while idx < binds.endIndex { - let v = try EVAL(binds[idx.successor()], let_env) - try let_env.set(binds[idx], v) - idx = idx.successor().successor() - } - env = let_env - ast = lst[2] // TCO + case MalVal.MalList(let l): binds = l + case MalVal.MalVector(let l): binds = l default: throw MalError.General(msg: "Invalid let* bindings") } + var idx = binds.startIndex + while idx < binds.endIndex { + let v = try EVAL(binds[idx.successor()], let_env) + try let_env.set(binds[idx], v) + idx = idx.successor().successor() + } + env = let_env + ast = lst[2] // TCO case MalVal.MalSymbol("do"): - let slc = lst[lst.startIndex.successor().. MalVal { ast = lst[2] // TCO } case MalVal.MalSymbol("fn*"): - return MalVal.MalFunc( { + return MalVal.MalFunc( { return try EVAL(lst[2], Env(env, binds: lst[1], exprs: MalVal.MalList($0))) - }, ast:[lst[2]], env:env, params:[lst[1]]) + }, ast:[lst[2]], env:env, params:[lst[1]], + macro:false, meta:nil) default: switch try eval_ast(ast, env) { case MalVal.MalList(let elst): switch elst[0] { - case MalVal.MalFunc(let fn, nil, _, _): + case MalVal.MalFunc(let fn, nil, _, _, _, _): let args = Array(elst[1.. MalVal { } } +// print func PRINT(exp: MalVal) -> String { return pr_str(exp, true) } +// repl func rep(str:String) throws -> String { return PRINT(try EVAL(try READ(str), repl_env)) } @@ -101,7 +114,8 @@ var repl_env: Env = try Env() // core.swift: defined using Swift for (k, fn) in core_ns { try repl_env.set(MalVal.MalSymbol(k), - MalVal.MalFunc(fn,ast:nil,env:nil,params:nil)) + MalVal.MalFunc(fn,ast:nil,env:nil,params:nil, + macro:false,meta:nil)) } // core.mal: defined using the language itself diff --git a/swift3/Sources/step6_file/main.swift b/swift3/Sources/step6_file/main.swift new file mode 100644 index 0000000000..d8c5cf71c8 --- /dev/null +++ b/swift3/Sources/step6_file/main.swift @@ -0,0 +1,155 @@ +import Foundation + +// read +func READ(str: String) throws -> MalVal { + return try read_str(str) +} + +// eval +func eval_ast(ast: MalVal, _ env: Env) throws -> MalVal { + switch ast { + case MalVal.MalSymbol: + return try env.get(ast) + case MalVal.MalList(let lst): + return MalVal.MalList(try lst.map { try EVAL($0, env) }) + case MalVal.MalVector(let lst): + return MalVal.MalVector(try lst.map { try EVAL($0, env) }) + case MalVal.MalHashMap(let dict): + var new_dict = Dictionary() + for (k,v) in dict { new_dict[k] = try EVAL(v, env) } + return MalVal.MalHashMap(new_dict) + default: + return ast + } +} + +func EVAL(orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { + var ast = orig_ast, env = orig_env + while true { + switch ast { + case MalVal.MalList: true + default: return try eval_ast(ast, env) + } + + switch ast { + case MalVal.MalList(let lst): + switch lst[0] { + case MalVal.MalSymbol("def!"): + return try env.set(lst[1], try EVAL(lst[2], env)) + case MalVal.MalSymbol("let*"): + let let_env = try Env(env) + var binds = Array() + switch lst[1] { + case MalVal.MalList(let l): binds = l + case MalVal.MalVector(let l): binds = l + default: + throw MalError.General(msg: "Invalid let* bindings") + } + var idx = binds.startIndex + while idx < binds.endIndex { + let v = try EVAL(binds[idx.successor()], let_env) + try let_env.set(binds[idx], v) + idx = idx.successor().successor() + } + env = let_env + ast = lst[2] // TCO + case MalVal.MalSymbol("do"): + let slc = lst[1.. 3 { + ast = lst[3] // TCO + } else { + return MalVal.MalNil + } + default: + ast = lst[2] // TCO + } + case MalVal.MalSymbol("fn*"): + return MalVal.MalFunc( { + return try EVAL(lst[2], Env(env, binds: lst[1], + exprs: MalVal.MalList($0))) + }, ast:[lst[2]], env:env, params:[lst[1]], + macro:false, meta:nil) + default: + switch try eval_ast(ast, env) { + case MalVal.MalList(let elst): + switch elst[0] { + case MalVal.MalFunc(let fn, nil, _, _, _, _): + let args = Array(elst[1.. String { + return pr_str(exp, true) +} + + +// repl +func rep(str:String) throws -> String { + return PRINT(try EVAL(try READ(str), repl_env)) +} + +var repl_env: Env = try Env() + +// core.swift: defined using Swift +for (k, fn) in core_ns { + try repl_env.set(MalVal.MalSymbol(k), + MalVal.MalFunc(fn,ast:nil,env:nil,params:nil, + macro:false,meta:nil)) +} +try repl_env.set(MalVal.MalSymbol("eval"), + MalVal.MalFunc({ try EVAL($0[0], repl_env) }, + ast:nil,env:nil,params:nil, + macro:false,meta:nil)) +let pargs = Process.arguments.map { MalVal.MalString($0) } +// TODO: weird way to get empty list, fix this +var args = pargs[pargs.startIndex.. 1 { + try rep("(load-file \"" + Process.arguments[1] + "\")") + exit(0) +} + +while true { + print("user> ", terminator: "") + let line = readLine(stripNewline: true) + if line == nil { break } + if line == "" { continue } + + do { + print(try rep(line!)) + } catch (MalError.Reader(let msg)) { + print("Error: \(msg)") + } catch (MalError.General(let msg)) { + print("Error: \(msg)") + } +} diff --git a/swift3/Sources/step7_quote/main.swift b/swift3/Sources/step7_quote/main.swift new file mode 100644 index 0000000000..916c496129 --- /dev/null +++ b/swift3/Sources/step7_quote/main.swift @@ -0,0 +1,193 @@ +import Foundation + +// read +func READ(str: String) throws -> MalVal { + return try read_str(str) +} + +// eval +func is_pair(ast: MalVal) -> Bool { + switch ast { + case MalVal.MalList(let lst): return lst.count > 0 + case MalVal.MalVector(let lst): return lst.count > 0 + default: return false + } +} + +func quasiquote(ast: MalVal) -> MalVal { + if !is_pair(ast) { + return MalVal.MalList([MalVal.MalSymbol("quote"), ast]) + } + let a0 = try! _nth(ast, 0) + switch a0 { + case MalVal.MalSymbol("unquote"): + return try! _nth(ast, 1) + default: true // fallthrough + } + if is_pair(a0) { + let a00 = try! _nth(a0, 0) + switch a00 { + case MalVal.MalSymbol("splice-unquote"): + return MalVal.MalList([MalVal.MalSymbol("concat"), + try! _nth(a0, 1), + quasiquote(try! rest(ast))]) + default: true // fallthrough + } + } + + return MalVal.MalList([MalVal.MalSymbol("cons"), + quasiquote(a0), + quasiquote(try! rest(ast))]) +} + +func eval_ast(ast: MalVal, _ env: Env) throws -> MalVal { + switch ast { + case MalVal.MalSymbol: + return try env.get(ast) + case MalVal.MalList(let lst): + return MalVal.MalList(try lst.map { try EVAL($0, env) }) + case MalVal.MalVector(let lst): + return MalVal.MalVector(try lst.map { try EVAL($0, env) }) + case MalVal.MalHashMap(let dict): + var new_dict = Dictionary() + for (k,v) in dict { new_dict[k] = try EVAL(v, env) } + return MalVal.MalHashMap(new_dict) + default: + return ast + } +} + +func EVAL(orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { + var ast = orig_ast, env = orig_env + while true { + switch ast { + case MalVal.MalList: true + default: return try eval_ast(ast, env) + } + + switch ast { + case MalVal.MalList(let lst): + switch lst[0] { + case MalVal.MalSymbol("def!"): + return try env.set(lst[1], try EVAL(lst[2], env)) + case MalVal.MalSymbol("let*"): + let let_env = try Env(env) + var binds = Array() + switch lst[1] { + case MalVal.MalList(let l): binds = l + case MalVal.MalVector(let l): binds = l + default: + throw MalError.General(msg: "Invalid let* bindings") + } + var idx = binds.startIndex + while idx < binds.endIndex { + let v = try EVAL(binds[idx.successor()], let_env) + try let_env.set(binds[idx], v) + idx = idx.successor().successor() + } + env = let_env + ast = lst[2] // TCO + case MalVal.MalSymbol("quote"): + return lst[1] + case MalVal.MalSymbol("quasiquote"): + ast = quasiquote(lst[1]) // TCO + case MalVal.MalSymbol("do"): + let slc = lst[1.. 3 { + ast = lst[3] // TCO + } else { + return MalVal.MalNil + } + default: + ast = lst[2] // TCO + } + case MalVal.MalSymbol("fn*"): + return MalVal.MalFunc( { + return try EVAL(lst[2], Env(env, binds: lst[1], + exprs: MalVal.MalList($0))) + }, ast:[lst[2]], env:env, params:[lst[1]], + macro:false, meta:nil) + default: + switch try eval_ast(ast, env) { + case MalVal.MalList(let elst): + switch elst[0] { + case MalVal.MalFunc(let fn, nil, _, _, _, _): + let args = Array(elst[1.. String { + return pr_str(exp, true) +} + + +// repl +func rep(str:String) throws -> String { + return PRINT(try EVAL(try READ(str), repl_env)) +} + +var repl_env: Env = try Env() + +// core.swift: defined using Swift +for (k, fn) in core_ns { + try repl_env.set(MalVal.MalSymbol(k), + MalVal.MalFunc(fn,ast:nil,env:nil,params:nil, + macro:false,meta:nil)) +} +try repl_env.set(MalVal.MalSymbol("eval"), + MalVal.MalFunc({ try EVAL($0[0], repl_env) }, + ast:nil,env:nil,params:nil, + macro:false,meta:nil)) +let pargs = Process.arguments.map { MalVal.MalString($0) } +// TODO: weird way to get empty list, fix this +var args = pargs[pargs.startIndex.. 1 { + try rep("(load-file \"" + Process.arguments[1] + "\")") + exit(0) +} + +while true { + print("user> ", terminator: "") + let line = readLine(stripNewline: true) + if line == nil { break } + if line == "" { continue } + + do { + print(try rep(line!)) + } catch (MalError.Reader(let msg)) { + print("Error: \(msg)") + } catch (MalError.General(let msg)) { + print("Error: \(msg)") + } +} diff --git a/swift3/Sources/step8_macros/main.swift b/swift3/Sources/step8_macros/main.swift new file mode 100644 index 0000000000..a0632cda7a --- /dev/null +++ b/swift3/Sources/step8_macros/main.swift @@ -0,0 +1,245 @@ +import Foundation + +// read +func READ(str: String) throws -> MalVal { + return try read_str(str) +} + +// eval +func is_pair(ast: MalVal) -> Bool { + switch ast { + case MalVal.MalList(let lst): return lst.count > 0 + case MalVal.MalVector(let lst): return lst.count > 0 + default: return false + } +} + +func quasiquote(ast: MalVal) -> MalVal { + if !is_pair(ast) { + return MalVal.MalList([MalVal.MalSymbol("quote"), ast]) + } + let a0 = try! _nth(ast, 0) + switch a0 { + case MalVal.MalSymbol("unquote"): + return try! _nth(ast, 1) + default: true // fallthrough + } + if is_pair(a0) { + let a00 = try! _nth(a0, 0) + switch a00 { + case MalVal.MalSymbol("splice-unquote"): + return MalVal.MalList([MalVal.MalSymbol("concat"), + try! _nth(a0, 1), + quasiquote(try! rest(ast))]) + default: true // fallthrough + } + } + + return MalVal.MalList([MalVal.MalSymbol("cons"), + quasiquote(a0), + quasiquote(try! rest(ast))]) +} + +func is_macro(ast: MalVal, _ env: Env) -> Bool { + switch ast { + case MalVal.MalList(let lst) where lst.count > 0: + let a0 = lst[lst.startIndex] + switch a0 { + case MalVal.MalSymbol: + let e = try! env.find(a0) + if e != nil { + let mac = try! e!.get(a0) + switch mac { + case MalVal.MalFunc(_,_,_,_,let macro,_): return macro + default: return false + } + } else { + return false + } + default: return false + } + default: return false + } +} + +func macroexpand(orig_ast: MalVal, _ env: Env) throws -> MalVal { + var ast: MalVal = orig_ast + while is_macro(ast, env) { + switch try! env.get(try! _nth(ast, 0)) { + case MalVal.MalFunc(let mac,_,_,_,_,_): + ast = try mac(_rest(ast)) + default: throw MalError.General(msg: "impossible state in macroexpand") + } + } + return ast +} + +func eval_ast(ast: MalVal, _ env: Env) throws -> MalVal { + switch ast { + case MalVal.MalSymbol: + return try env.get(ast) + case MalVal.MalList(let lst): + return MalVal.MalList(try lst.map { try EVAL($0, env) }) + case MalVal.MalVector(let lst): + return MalVal.MalVector(try lst.map { try EVAL($0, env) }) + case MalVal.MalHashMap(let dict): + var new_dict = Dictionary() + for (k,v) in dict { new_dict[k] = try EVAL(v, env) } + return MalVal.MalHashMap(new_dict) + default: + return ast + } +} + +func EVAL(orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { + var ast = orig_ast, env = orig_env + while true { + switch ast { + case MalVal.MalList: true + default: return try eval_ast(ast, env) + } + + ast = try macroexpand(ast, env) + switch ast { + case MalVal.MalList: true + default: return try eval_ast(ast, env) + } + + switch ast { + case MalVal.MalList(let lst): + switch lst[0] { + case MalVal.MalSymbol("def!"): + return try env.set(lst[1], try EVAL(lst[2], env)) + case MalVal.MalSymbol("let*"): + let let_env = try Env(env) + var binds = Array() + switch lst[1] { + case MalVal.MalList(let l): binds = l + case MalVal.MalVector(let l): binds = l + default: + throw MalError.General(msg: "Invalid let* bindings") + } + var idx = binds.startIndex + while idx < binds.endIndex { + let v = try EVAL(binds[idx.successor()], let_env) + try let_env.set(binds[idx], v) + idx = idx.successor().successor() + } + env = let_env + ast = lst[2] // TCO + case MalVal.MalSymbol("quote"): + return lst[1] + case MalVal.MalSymbol("quasiquote"): + ast = quasiquote(lst[1]) // TCO + case MalVal.MalSymbol("defmacro!"): + var mac = try EVAL(lst[2], env) + switch mac { + case MalVal.MalFunc(let fn, let a, let e, let p, _, let m): + mac = MalVal.MalFunc(fn,ast:a,env:e,params:p,macro:true,meta:m) + default: throw MalError.General(msg: "invalid defmacro! form") + } + return try env.set(lst[1], mac) + case MalVal.MalSymbol("macroexpand"): + return try macroexpand(lst[1], env) + case MalVal.MalSymbol("do"): + let slc = lst[1.. 3 { + ast = lst[3] // TCO + } else { + return MalVal.MalNil + } + default: + ast = lst[2] // TCO + } + case MalVal.MalSymbol("fn*"): + return MalVal.MalFunc( { + return try EVAL(lst[2], Env(env, binds: lst[1], + exprs: MalVal.MalList($0))) + }, ast:[lst[2]], env:env, params:[lst[1]], + macro:false, meta:nil) + default: + switch try eval_ast(ast, env) { + case MalVal.MalList(let elst): + switch elst[0] { + case MalVal.MalFunc(let fn, nil, _, _, _, _): + let args = Array(elst[1.. String { + return pr_str(exp, true) +} + + +// repl +func rep(str:String) throws -> String { + return PRINT(try EVAL(try READ(str), repl_env)) +} + +var repl_env: Env = try Env() + +// core.swift: defined using Swift +for (k, fn) in core_ns { + try repl_env.set(MalVal.MalSymbol(k), + MalVal.MalFunc(fn,ast:nil,env:nil,params:nil, + macro:false,meta:nil)) +} +try repl_env.set(MalVal.MalSymbol("eval"), + MalVal.MalFunc({ try EVAL($0[0], repl_env) }, + ast:nil,env:nil,params:nil, + macro:false,meta:nil)) +let pargs = Process.arguments.map { MalVal.MalString($0) } +// TODO: weird way to get empty list, fix this +var args = pargs[pargs.startIndex.. (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))") +try rep("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))") + + +if Process.arguments.count > 1 { + try rep("(load-file \"" + Process.arguments[1] + "\")") + exit(0) +} + +while true { + print("user> ", terminator: "") + let line = readLine(stripNewline: true) + if line == nil { break } + if line == "" { continue } + + do { + print(try rep(line!)) + } catch (MalError.Reader(let msg)) { + print("Error: \(msg)") + } catch (MalError.General(let msg)) { + print("Error: \(msg)") + } +} diff --git a/swift3/Sources/step9_try/main.swift b/swift3/Sources/step9_try/main.swift new file mode 100644 index 0000000000..d0501eda5b --- /dev/null +++ b/swift3/Sources/step9_try/main.swift @@ -0,0 +1,280 @@ +import Foundation + +// read +func READ(str: String) throws -> MalVal { + return try read_str(str) +} + +// eval +func is_pair(ast: MalVal) -> Bool { + switch ast { + case MalVal.MalList(let lst): return lst.count > 0 + case MalVal.MalVector(let lst): return lst.count > 0 + default: return false + } +} + +func quasiquote(ast: MalVal) -> MalVal { + if !is_pair(ast) { + return MalVal.MalList([MalVal.MalSymbol("quote"), ast]) + } + let a0 = try! _nth(ast, 0) + switch a0 { + case MalVal.MalSymbol("unquote"): + return try! _nth(ast, 1) + default: true // fallthrough + } + if is_pair(a0) { + let a00 = try! _nth(a0, 0) + switch a00 { + case MalVal.MalSymbol("splice-unquote"): + return MalVal.MalList([MalVal.MalSymbol("concat"), + try! _nth(a0, 1), + quasiquote(try! rest(ast))]) + default: true // fallthrough + } + } + + return MalVal.MalList([MalVal.MalSymbol("cons"), + quasiquote(a0), + quasiquote(try! rest(ast))]) +} + +func is_macro(ast: MalVal, _ env: Env) -> Bool { + switch ast { + case MalVal.MalList(let lst) where lst.count > 0: + let a0 = lst[lst.startIndex] + switch a0 { + case MalVal.MalSymbol: + let e = try! env.find(a0) + if e != nil { + let mac = try! e!.get(a0) + switch mac { + case MalVal.MalFunc(_,_,_,_,let macro,_): return macro + default: return false + } + } else { + return false + } + default: return false + } + default: return false + } +} + +func macroexpand(orig_ast: MalVal, _ env: Env) throws -> MalVal { + var ast: MalVal = orig_ast + while is_macro(ast, env) { + switch try! env.get(try! _nth(ast, 0)) { + case MalVal.MalFunc(let mac,_,_,_,_,_): + ast = try mac(_rest(ast)) + default: throw MalError.General(msg: "impossible state in macroexpand") + } + } + return ast +} + +func eval_ast(ast: MalVal, _ env: Env) throws -> MalVal { + switch ast { + case MalVal.MalSymbol: + return try env.get(ast) + case MalVal.MalList(let lst): + return MalVal.MalList(try lst.map { try EVAL($0, env) }) + case MalVal.MalVector(let lst): + return MalVal.MalVector(try lst.map { try EVAL($0, env) }) + case MalVal.MalHashMap(let dict): + var new_dict = Dictionary() + for (k,v) in dict { new_dict[k] = try EVAL(v, env) } + return MalVal.MalHashMap(new_dict) + default: + return ast + } +} + +func EVAL(orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { + var ast = orig_ast, env = orig_env + while true { + switch ast { + case MalVal.MalList: true + default: return try eval_ast(ast, env) + } + + ast = try macroexpand(ast, env) + switch ast { + case MalVal.MalList: true + default: return try eval_ast(ast, env) + } + + switch ast { + case MalVal.MalList(let lst): + switch lst[0] { + case MalVal.MalSymbol("def!"): + return try env.set(lst[1], try EVAL(lst[2], env)) + case MalVal.MalSymbol("let*"): + let let_env = try Env(env) + var binds = Array() + switch lst[1] { + case MalVal.MalList(let l): binds = l + case MalVal.MalVector(let l): binds = l + default: + throw MalError.General(msg: "Invalid let* bindings") + } + var idx = binds.startIndex + while idx < binds.endIndex { + let v = try EVAL(binds[idx.successor()], let_env) + try let_env.set(binds[idx], v) + idx = idx.successor().successor() + } + env = let_env + ast = lst[2] // TCO + case MalVal.MalSymbol("quote"): + return lst[1] + case MalVal.MalSymbol("quasiquote"): + ast = quasiquote(lst[1]) // TCO + case MalVal.MalSymbol("defmacro!"): + var mac = try EVAL(lst[2], env) + switch mac { + case MalVal.MalFunc(let fn, let a, let e, let p, _, let m): + mac = MalVal.MalFunc(fn,ast:a,env:e,params:p,macro:true,meta:m) + default: throw MalError.General(msg: "invalid defmacro! form") + } + return try env.set(lst[1], mac) + case MalVal.MalSymbol("macroexpand"): + return try macroexpand(lst[1], env) + case MalVal.MalSymbol("try*"): + do { + return try EVAL(_nth(ast, 1), env) + } catch (let exc) { + if lst.count > 2 { + let a2 = lst[2] + switch a2 { + case MalVal.MalList(let a2lst): + let a20 = a2lst[0] + switch a20 { + case MalVal.MalSymbol("catch*"): + if a2lst.count < 3 { return MalVal.MalNil } + let a21 = a2lst[1], a22 = a2lst[2] + var err: MalVal + switch exc { + case MalError.Reader(let msg): + err = MalVal.MalString(msg) + case MalError.General(let msg): + err = MalVal.MalString(msg) + case MalError.MalException(let obj): + err = obj + default: + err = MalVal.MalString(String(exc)) + } + let binds = MalVal.MalList([a21]), + exprs = MalVal.MalList([err]) + return try EVAL(a22, Env(env, binds: binds, + exprs: exprs)) + default: true // fall through + } + default: true // fall through + } + } + throw exc + } + case MalVal.MalSymbol("do"): + let slc = lst[1.. 3 { + ast = lst[3] // TCO + } else { + return MalVal.MalNil + } + default: + ast = lst[2] // TCO + } + case MalVal.MalSymbol("fn*"): + return MalVal.MalFunc( { + return try EVAL(lst[2], Env(env, binds: lst[1], + exprs: MalVal.MalList($0))) + }, ast:[lst[2]], env:env, params:[lst[1]], + macro:false, meta:nil) + default: + switch try eval_ast(ast, env) { + case MalVal.MalList(let elst): + switch elst[0] { + case MalVal.MalFunc(let fn, nil, _, _, _, _): + let args = Array(elst[1.. String { + return pr_str(exp, true) +} + + +// repl +func rep(str:String) throws -> String { + return PRINT(try EVAL(try READ(str), repl_env)) +} + +var repl_env: Env = try Env() + +// core.swift: defined using Swift +for (k, fn) in core_ns { + try repl_env.set(MalVal.MalSymbol(k), + MalVal.MalFunc(fn,ast:nil,env:nil,params:nil, + macro:false,meta:nil)) +} +try repl_env.set(MalVal.MalSymbol("eval"), + MalVal.MalFunc({ try EVAL($0[0], repl_env) }, + ast:nil,env:nil,params:nil, + macro:false,meta:nil)) +let pargs = Process.arguments.map { MalVal.MalString($0) } +// TODO: weird way to get empty list, fix this +var args = pargs[pargs.startIndex.. (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))") +try rep("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))") + + +if Process.arguments.count > 1 { + try rep("(load-file \"" + Process.arguments[1] + "\")") + exit(0) +} + +while true { + print("user> ", terminator: "") + let line = readLine(stripNewline: true) + if line == nil { break } + if line == "" { continue } + + do { + print(try rep(line!)) + } catch (MalError.Reader(let msg)) { + print("Error: \(msg)") + } catch (MalError.General(let msg)) { + print("Error: \(msg)") + } +} diff --git a/swift3/Sources/stepA_mal/main.swift b/swift3/Sources/stepA_mal/main.swift new file mode 100644 index 0000000000..352fe8ce80 --- /dev/null +++ b/swift3/Sources/stepA_mal/main.swift @@ -0,0 +1,284 @@ +import Foundation + +// read +func READ(str: String) throws -> MalVal { + return try read_str(str) +} + +// eval +func is_pair(ast: MalVal) -> Bool { + switch ast { + case MalVal.MalList(let lst): return lst.count > 0 + case MalVal.MalVector(let lst): return lst.count > 0 + default: return false + } +} + +func quasiquote(ast: MalVal) -> MalVal { + if !is_pair(ast) { + return MalVal.MalList([MalVal.MalSymbol("quote"), ast]) + } + let a0 = try! _nth(ast, 0) + switch a0 { + case MalVal.MalSymbol("unquote"): + return try! _nth(ast, 1) + default: true // fallthrough + } + if is_pair(a0) { + let a00 = try! _nth(a0, 0) + switch a00 { + case MalVal.MalSymbol("splice-unquote"): + return MalVal.MalList([MalVal.MalSymbol("concat"), + try! _nth(a0, 1), + quasiquote(try! rest(ast))]) + default: true // fallthrough + } + } + + return MalVal.MalList([MalVal.MalSymbol("cons"), + quasiquote(a0), + quasiquote(try! rest(ast))]) +} + +func is_macro(ast: MalVal, _ env: Env) -> Bool { + switch ast { + case MalVal.MalList(let lst) where lst.count > 0: + let a0 = lst[lst.startIndex] + switch a0 { + case MalVal.MalSymbol: + let e = try! env.find(a0) + if e != nil { + let mac = try! e!.get(a0) + switch mac { + case MalVal.MalFunc(_,_,_,_,let macro,_): return macro + default: return false + } + } else { + return false + } + default: return false + } + default: return false + } +} + +func macroexpand(orig_ast: MalVal, _ env: Env) throws -> MalVal { + var ast: MalVal = orig_ast + while is_macro(ast, env) { + switch try! env.get(try! _nth(ast, 0)) { + case MalVal.MalFunc(let mac,_,_,_,_,_): + ast = try mac(_rest(ast)) + default: throw MalError.General(msg: "impossible state in macroexpand") + } + } + return ast +} + +func eval_ast(ast: MalVal, _ env: Env) throws -> MalVal { + switch ast { + case MalVal.MalSymbol: + return try env.get(ast) + case MalVal.MalList(let lst): + return MalVal.MalList(try lst.map { try EVAL($0, env) }) + case MalVal.MalVector(let lst): + return MalVal.MalVector(try lst.map { try EVAL($0, env) }) + case MalVal.MalHashMap(let dict): + var new_dict = Dictionary() + for (k,v) in dict { new_dict[k] = try EVAL(v, env) } + return MalVal.MalHashMap(new_dict) + default: + return ast + } +} + +func EVAL(orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { + var ast = orig_ast, env = orig_env + while true { + switch ast { + case MalVal.MalList: true + default: return try eval_ast(ast, env) + } + + ast = try macroexpand(ast, env) + switch ast { + case MalVal.MalList: true + default: return try eval_ast(ast, env) + } + + switch ast { + case MalVal.MalList(let lst): + switch lst[0] { + case MalVal.MalSymbol("def!"): + return try env.set(lst[1], try EVAL(lst[2], env)) + case MalVal.MalSymbol("let*"): + let let_env = try Env(env) + var binds = Array() + switch lst[1] { + case MalVal.MalList(let l): binds = l + case MalVal.MalVector(let l): binds = l + default: + throw MalError.General(msg: "Invalid let* bindings") + } + var idx = binds.startIndex + while idx < binds.endIndex { + let v = try EVAL(binds[idx.successor()], let_env) + try let_env.set(binds[idx], v) + idx = idx.successor().successor() + } + env = let_env + ast = lst[2] // TCO + case MalVal.MalSymbol("quote"): + return lst[1] + case MalVal.MalSymbol("quasiquote"): + ast = quasiquote(lst[1]) // TCO + case MalVal.MalSymbol("defmacro!"): + var mac = try EVAL(lst[2], env) + switch mac { + case MalVal.MalFunc(let fn, let a, let e, let p, _, let m): + mac = MalVal.MalFunc(fn,ast:a,env:e,params:p,macro:true,meta:m) + default: throw MalError.General(msg: "invalid defmacro! form") + } + return try env.set(lst[1], mac) + case MalVal.MalSymbol("macroexpand"): + return try macroexpand(lst[1], env) + case MalVal.MalSymbol("try*"): + do { + return try EVAL(_nth(ast, 1), env) + } catch (let exc) { + if lst.count > 2 { + let a2 = lst[2] + switch a2 { + case MalVal.MalList(let a2lst): + let a20 = a2lst[0] + switch a20 { + case MalVal.MalSymbol("catch*"): + if a2lst.count < 3 { return MalVal.MalNil } + let a21 = a2lst[1], a22 = a2lst[2] + var err: MalVal + switch exc { + case MalError.Reader(let msg): + err = MalVal.MalString(msg) + case MalError.General(let msg): + err = MalVal.MalString(msg) + case MalError.MalException(let obj): + err = obj + default: + err = MalVal.MalString(String(exc)) + } + let binds = MalVal.MalList([a21]), + exprs = MalVal.MalList([err]) + return try EVAL(a22, Env(env, binds: binds, + exprs: exprs)) + default: true // fall through + } + default: true // fall through + } + } + throw exc + } + case MalVal.MalSymbol("do"): + let slc = lst[1.. 3 { + ast = lst[3] // TCO + } else { + return MalVal.MalNil + } + default: + ast = lst[2] // TCO + } + case MalVal.MalSymbol("fn*"): + return MalVal.MalFunc( { + return try EVAL(lst[2], Env(env, binds: lst[1], + exprs: MalVal.MalList($0))) + }, ast:[lst[2]], env:env, params:[lst[1]], + macro:false, meta:nil) + default: + switch try eval_ast(ast, env) { + case MalVal.MalList(let elst): + switch elst[0] { + case MalVal.MalFunc(let fn, nil, _, _, _, _): + let args = Array(elst[1.. String { + return pr_str(exp, true) +} + + +// repl +func rep(str:String) throws -> String { + return PRINT(try EVAL(try READ(str), repl_env)) +} + +var repl_env: Env = try Env() + +// core.swift: defined using Swift +for (k, fn) in core_ns { + try repl_env.set(MalVal.MalSymbol(k), + MalVal.MalFunc(fn,ast:nil,env:nil,params:nil, + macro:false,meta:nil)) +} +try repl_env.set(MalVal.MalSymbol("eval"), + MalVal.MalFunc({ try EVAL($0[0], repl_env) }, + ast:nil,env:nil,params:nil, + macro:false,meta:nil)) +let pargs = Process.arguments.map { MalVal.MalString($0) } +// TODO: weird way to get empty list, fix this +var args = pargs[pargs.startIndex.. (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))") +try rep("(def! *gensym-counter* (atom 0))") +try rep("(def! gensym (fn* [] (symbol (str \"G__\" (swap! *gensym-counter* (fn* [x] (+ 1 x)))))))") +try rep("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) (let* (condvar (gensym)) `(let* (~condvar ~(first xs)) (if ~condvar ~condvar (or ~@(rest xs)))))))))") + + +if Process.arguments.count > 1 { + try rep("(load-file \"" + Process.arguments[1] + "\")") + exit(0) +} + +try rep("(println (str \"Mal [\" *host-language* \"]\"))") +while true { + print("user> ", terminator: "") + let line = readLine(stripNewline: true) + if line == nil { break } + if line == "" { continue } + + do { + print(try rep(line!)) + } catch (MalError.Reader(let msg)) { + print("Error: \(msg)") + } catch (MalError.General(let msg)) { + print("Error: \(msg)") + } +} From b6dc3e37aa6582e182598d09d5678e9202fe9abe Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Sun, 14 Feb 2016 20:57:31 -0600 Subject: [PATCH 05/14] awk-es6, Makefile: dist ruiles --- .gitignore | 91 +++++++++++++++++-------------- Makefile | 13 +++++ awk/Makefile | 11 +++- bash/Makefile | 5 +- c/Makefile | 4 +- clojure/Makefile | 11 +++- clojure/project.clj | 6 +- clojure/src/stepA_mal.clj | 3 +- coffee/Makefile | 12 +++- cpp/Makefile | 7 ++- cpp/stepA_mal.cpp | 3 +- crystal/Makefile | 4 +- cs/Makefile | 4 +- d/Makefile | 4 +- elixir/Makefile | 6 ++ elixir/lib/mix/tasks/stepA_mal.ex | 5 ++ elixir/mix.exs | 7 ++- erlang/Makefile | 11 +++- erlang/rebar.config.script | 3 +- es6/Makefile | 9 ++- es6/package.json | 3 +- 21 files changed, 159 insertions(+), 63 deletions(-) diff --git a/.gitignore b/.gitignore index e15740e9fb..ab08f8e507 100644 --- a/.gitignore +++ b/.gitignore @@ -1,25 +1,7 @@ */experiments */node_modules -c/*.o +*.o *.pyc -bash/mal.sh -c/mal -coffee/mal.coffee -crystal/mal -d/mal -erlang/mal -haskell/mal -haxe/*.n -haxe/*.py -haxe/cpp/ -haxe/*.js -js/mal.js -js/web/mal.js -make/mal.mk -mal/mal.mal -nim/mal -php/mal.php -python/mal.py */step0_repl */step1_read_print */step2_eval @@ -31,52 +13,77 @@ python/mal.py */step8_macros */step9_try */stepA_mal +.bash_history +.mal-history +.crystal +.lein +.m2 +.ivy2 +.sbt +awk/mal.awk +bash/mal.sh +c/mal +cpp/mal +clojure/mal.jar +clojure/target +clojure/.lein-repl-history +coffee/mal.coffee +crystal/mal cs/*.exe cs/*.dll cs/*.mdb -clojure/target -clojure/.lein-repl-history +d/mal +elixir/_build +elixir/deps +elixir/erl_crash.dump +elixir/mal +elixir/*.ez +erlang/mal erlang/ebin erlang/.rebar erlang/src/*.beam +es6/mal.js +es6/build fsharp/*.exe fsharp/*.dll fsharp/*.mdb go/step* go/mal +groovy/*.class +haskell/mal +haskell/*.hi +haskell/*.o +haxe/*.n +haxe/*.py +haxe/cpp/ +haxe/*.js java/target/ java/dependency-reduced-pom.xml +js/mal.js +js/web/mal.js +kotlin/*.jar +kotlin/.idea +kotlin/*.iml +lua/lib +lua/linenoise.so +make/mal.mk +mal/mal.mal +nim/mal +nim/nimcache* ocaml/*.cmi ocaml/*.cmo ocaml/*.swp ocaml/*.cmx ocaml/*.o ocaml/mal_lib.* +php/mal.php +python/mal.pyz rust/target/ rust/mal rust/Cargo.lock rust/.cargo r/lib -vb/*.exe -vb/*.dll scala/target scala/project -haskell/*.hi -haskell/*.o -lua/lib -lua/linenoise.so -nim/nimcache* -.lein -.m2 -.ivy2 -.sbt -groovy/*.class -.crystal -es6/build -elixir/_build -elixir/deps -elixir/erl_crash.dump -elixir/*.ez -kotlin/*.jar -kotlin/.idea -kotlin/*.iml +vb/*.exe +vb/*.dll diff --git a/Makefile b/Makefile index 5b6bb50a74..3927c0879f 100644 --- a/Makefile +++ b/Makefile @@ -233,6 +233,8 @@ ALL_TESTS = $(filter-out $(foreach impl,$(STEP5_EXCLUDES),test^$(impl)^step5),\ IMPL_STATS = $(foreach impl,$(DO_IMPLS),stats^$(impl)) IMPL_STATS_LISP = $(foreach impl,$(DO_IMPLS),stats-lisp^$(impl)) +IMPL_DIST = $(foreach impl,$(DO_IMPLS),dist^$(impl)) + DOCKER_BUILD = $(foreach impl,$(DO_IMPLS),docker-build^$(impl)) IMPL_PERF = $(foreach impl,$(filter-out $(PERF_EXCLUDES),$(DO_IMPLS)),perf^$(impl)) @@ -295,6 +297,17 @@ $(IMPL_STATS_LISP): echo "Stats (lisp only) for $(impl):"; \ $(MAKE) --no-print-directory -C $(impl) stats-lisp) +# dist rules + +dist: $(IMPL_DIST) + +.SECONDEXPANSION: +$(IMPL_DIST): + @echo "----------------------------------------------"; \ + $(foreach impl,$(word 2,$(subst ^, ,$(@))),\ + echo "Running: make -C $(impl) dist"; \ + $(MAKE) --no-print-directory -C $(impl) dist) + # Docker build rules docker-build: $(DOCKER_BUILD) diff --git a/awk/Makefile b/awk/Makefile index 2308b50510..1842efa3bd 100644 --- a/awk/Makefile +++ b/awk/Makefile @@ -6,13 +6,20 @@ SOURCES_BASE = types.awk reader.awk printer.awk SOURCES_LISP = env.awk core.awk stepA_mal.awk SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) -all: mal.awk +all: + true + +dist: mal.awk mal.awk: $(SOURCES) - echo "#!/usr/bin/awk -f" > $@ + echo '#!/bin/sh' > $@ + echo 'arbitrary_long_name==0 "exec" "/usr/bin/gawk" "-O" "-f" "$$0" "$$@"' >> $@ cat $+ | grep -v "^@include " >> $@ chmod +x $@ +clean: + rm -f mal.awk + .PHONY: stats tests $(TESTS) diff --git a/bash/Makefile b/bash/Makefile index b9a566fe30..0bbdc9a774 100644 --- a/bash/Makefile +++ b/bash/Makefile @@ -2,7 +2,10 @@ SOURCES_BASE = types.sh reader.sh printer.sh SOURCES_LISP = env.sh core.sh stepA_mal.sh SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) -all: mal.sh +all: + true + +dist: mal.sh mal.sh: $(SOURCES) echo "#!/usr/bin/env bash" > $@ diff --git a/c/Makefile b/c/Makefile index 8f01c0f9f7..0e87cda999 100644 --- a/c/Makefile +++ b/c/Makefile @@ -43,7 +43,9 @@ LDFLAGS += -l$(RL_LIBRARY) $(GLIB_LDFLAGS) -ldl -lffi ##################### -all: $(BINS) mal +all: $(BINS) + +dist: mal mal: $(word $(words $(BINS)),$(BINS)) cp $< $@ diff --git a/clojure/Makefile b/clojure/Makefile index 9d47fd857e..fb31b760dd 100644 --- a/clojure/Makefile +++ b/clojure/Makefile @@ -2,9 +2,18 @@ SOURCES_BASE = src/readline.clj src/reader.clj src/printer.clj SOURCES_LISP = src/env.clj src/core.clj src/stepA_mal.clj SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) -all: +all dist: deps mal.jar + +deps: lein deps +mal.jar: $(SOURCES) + lein with-profile +jar uberjar + cp target/mal-0.0.1-SNAPSHOT-standalone.jar $@ + +clear: + rm -rf target/ mal.jar + .PHONY: stats stats: $(SOURCES) diff --git a/clojure/project.clj b/clojure/project.clj index 00fc3f6e44..7500c11131 100644 --- a/clojure/project.clj +++ b/clojure/project.clj @@ -19,7 +19,9 @@ :step7 {:main step7-quote} :step8 {:main step8-macros} :step9 {:main step9-try} - :stepA {:main stepA-mal}} + :stepA {:main stepA-mal} + :jar {:main stepA-mal + :aot [stepA-mal]}} - :main stepA-more) + :main stepA-mal) diff --git a/clojure/src/stepA_mal.clj b/clojure/src/stepA_mal.clj index 7a5ec0b30c..bc6f84513a 100644 --- a/clojure/src/stepA_mal.clj +++ b/clojure/src/stepA_mal.clj @@ -5,7 +5,8 @@ [reader] [printer] [env] - [core])) + [core]) + (:gen-class)) ;; read (defn READ [& [strng]] diff --git a/coffee/Makefile b/coffee/Makefile index 93c957fb61..3397bb9461 100644 --- a/coffee/Makefile +++ b/coffee/Makefile @@ -5,11 +5,21 @@ SOURCES_BASE = node_readline.coffee types.coffee \ SOURCES_LISP = env.coffee core.coffee stepA_mal.coffee SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) -all: node_modules +all: node_modules dist node_modules: npm install +dist: mal.coffee + +mal.coffee: $(SOURCES) + echo "#!/usr/bin/env coffee" > $@ + cat $+ | grep -v "= *require('./" >> $@ + chmod +x $@ + +clean: + rm -f mal.coffee + .PHONY: stats tests $(TESTS) diff --git a/cpp/Makefile b/cpp/Makefile index 59750d36b5..5e464d51e8 100644 --- a/cpp/Makefile +++ b/cpp/Makefile @@ -31,6 +31,11 @@ TARGETS=$(MAINS:%.cpp=%) all: $(TARGETS) +dist: mal + +mal: stepA_mal + cp $< $@ + .deps: *.cpp *.h $(CXX) $(CXXFLAGS) -MM *.cpp > .deps @@ -44,7 +49,7 @@ libmal.a: $(LIBOBJS) $(CXX) $(CXXFLAGS) -c $< -o $@ clean: - rm -rf *.o $(TARGETS) libmal.a .deps + rm -rf *.o $(TARGETS) libmal.a .deps mal -include .deps diff --git a/cpp/stepA_mal.cpp b/cpp/stepA_mal.cpp index 5f64f0ef19..4ecd57a887 100644 --- a/cpp/stepA_mal.cpp +++ b/cpp/stepA_mal.cpp @@ -34,6 +34,7 @@ int main(int argc, char* argv[]) safeRep(STRF("(load-file %s)", filename.c_str()), replEnv); return 0; } + rep("(println (str \"Mal [\" *host-language* \"]\"))", replEnv); while (s_readLine.get(prompt, input)) { safeRep(input, replEnv); } @@ -353,7 +354,7 @@ static const char* malFunctionTable[] = { (cons (f (first xs)) (map f (rest xs))))))", "(def! *gensym-counter* (atom 0))", "(def! gensym (fn* [] (symbol (str \"G__\" (swap! *gensym-counter* (fn* [x] (+ 1 x)))))))", - "(def! *host-language* \"c++\")", + "(def! *host-language* \"C++\")", }; static void installFunctions(malEnvPtr env) { diff --git a/crystal/Makefile b/crystal/Makefile index 5edcfe9574..ba96eadb6a 100644 --- a/crystal/Makefile +++ b/crystal/Makefile @@ -5,7 +5,9 @@ STEPS = step0_repl.cr step1_read_print.cr step2_eval.cr step3_env.cr \ STEP_BINS = $(STEPS:%.cr=%) LAST_STEP_BIN = $(word $(words $(STEP_BINS)),$(STEP_BINS)) -all: $(STEP_BINS) mal +all: $(STEP_BINS) + +dist: mal mal: $(LAST_STEP_BIN) cp $< $@ diff --git a/cs/Makefile b/cs/Makefile index cc4f2eb718..eecc5f61fe 100644 --- a/cs/Makefile +++ b/cs/Makefile @@ -22,7 +22,9 @@ FLAGS = $(if $(strip $(DEBUG)),-debug+,) ##################### -all: mal.exe $(patsubst %.cs,%.exe,$(SRCS)) +all: $(patsubst %.cs,%.exe,$(SRCS)) + +dist: mal.exe mal.exe: $(patsubst %.cs,%.exe,$(word $(words $(SOURCES)),$(SOURCES))) cp $< $@ diff --git a/d/Makefile b/d/Makefile index 77594c4a59..57d4803f3a 100644 --- a/d/Makefile +++ b/d/Makefile @@ -24,7 +24,9 @@ LATE_STEPS_BINS = $(LATE_SRCS:%.d=%) ##################### -all: $(BINS) mal +all: $(BINS) + +dist: mal mal: $(word $(words $(BINS)),$(BINS)) cp $< $@ diff --git a/elixir/Makefile b/elixir/Makefile index 6facf3b93a..7f922cc097 100644 --- a/elixir/Makefile +++ b/elixir/Makefile @@ -5,8 +5,14 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: mix compile +dist: mal + +mal: $(SOURCES) + mix escript.build + clean: mix clean + rm -f mal stats: $(SOURCES) @wc $^ diff --git a/elixir/lib/mix/tasks/stepA_mal.ex b/elixir/lib/mix/tasks/stepA_mal.ex index da990912d7..a59d2768f6 100644 --- a/elixir/lib/mix/tasks/stepA_mal.ex +++ b/elixir/lib/mix/tasks/stepA_mal.ex @@ -2,6 +2,11 @@ defmodule Mix.Tasks.StepAMal do import Mal.Types alias Mal.Function + # for escript execution + def main(args) do + run(args) + end + def run(args) do env = Mal.Env.new() Mal.Env.merge(env, Mal.Core.namespace) diff --git a/elixir/mix.exs b/elixir/mix.exs index e5ed02c98b..aba14e7b0c 100644 --- a/elixir/mix.exs +++ b/elixir/mix.exs @@ -8,7 +8,12 @@ defmodule Mal.Mixfile do build_embedded: Mix.env == :prod, start_permanent: Mix.env == :prod, deps: deps, - default_task: "stepA_mal"] + default_task: "stepA_mal", + escript: escript] + end + + def escript do + [main_module: Mix.Tasks.StepAMal] end # Configuration for the OTP application diff --git a/erlang/Makefile b/erlang/Makefile index d7cd44ebf3..6797446025 100644 --- a/erlang/Makefile +++ b/erlang/Makefile @@ -14,10 +14,15 @@ BINS = $(SRCS:%.erl=%) .PHONY: all mal clean stats stats-lisp -all: $(BINS) mal +all: $(BINS) + +dist: mal + +mal: $(SOURCES) + sed 's/stepA_mal/mal/' src/stepA_mal.erl > src/mal.erl + MAL_STEP=mal rebar compile escriptize + rm src/mal.erl -mal: $(word $(words $(BINS)),$(BINS)) - cp $< $@ define dep_template .PHONY: $(1) diff --git a/erlang/rebar.config.script b/erlang/rebar.config.script index c20ba33c7a..9ad75efe05 100644 --- a/erlang/rebar.config.script +++ b/erlang/rebar.config.script @@ -6,5 +6,6 @@ case os:getenv("MAL_STEP") of false -> CONFIG; % env var not defined [] -> CONFIG; % env var set to empty string - Step -> CONFIG ++ [{escript_name, Step}] + Step -> CONFIG ++ [{escript_name, Step}]; + mal -> CONFIG ++ [{escript_name, mal}] end. diff --git a/es6/Makefile b/es6/Makefile index f2c982d07f..593a0ec7b2 100644 --- a/es6/Makefile +++ b/es6/Makefile @@ -9,9 +9,16 @@ STEPS = step0_repl step1_read_print step2_eval step3_env \ all: node_modules $(foreach s,$(STEPS),build/$(s).js) +dist: mal.js + build/%.js: %.js @mkdir -p $(dir $@) babel --source-maps true $< --out-file $@ + @echo >> $@ # workaround node-uglifier bug + +mal.js: $(foreach s,$(SOURCES),build/$(s)) + node -e 'nu = new (require("node-uglifier"))("./build/stepA_mal.js"); nu.merge().exportToFile("./mal.js")' + build/step0_repl.js: step0_repl.js build/node_readline.js build/step1_read_print.js: step1_read_print.js build/node_readline.js build/types.js build/reader.js build/printer.js @@ -30,7 +37,7 @@ node_modules: npm install clean: - rm -f build/* + rm -f build/* mal.js .PHONY: stats tests $(TESTS) diff --git a/es6/package.json b/es6/package.json index 45477b59e4..08641923d4 100644 --- a/es6/package.json +++ b/es6/package.json @@ -3,6 +3,7 @@ "version": "0.0.1", "description": "Make a Lisp (mal) language implemented in ES6 (ECMAScript 6 / ECMAScript 2015)", "dependencies": { - "ffi": "1.3.x" + "ffi": "1.3.x", + "node-uglifier": "0.4.3" } } From 5245b079e14796083aa114d516360ce454698584 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Thu, 18 Feb 2016 00:33:19 -0600 Subject: [PATCH 06/14] Add dist targets to most implementations. TODO: factor groovy guile julia matlab miniMAL swift --- .gitignore | 29 ++++++++++++++++++++++------- Makefile | 11 ++++++++--- clojure/Makefile | 4 +++- erlang/Makefile | 3 ++- forth/Makefile | 13 ++++++++++++- fsharp/Makefile | 5 +++++ go/Makefile | 4 +++- haskell/Makefile | 4 +++- haxe/Makefile | 15 +++++++++++++++ java/Makefile | 10 ++++++++++ java/pom.xml | 13 +++++++++++++ js/Makefile | 6 ++++-- kotlin/Makefile | 7 ++++++- lua/Makefile | 19 +++++++++++++++++-- make/Makefile | 5 +++++ nim/Makefile | 4 +++- ocaml/Makefile | 4 +++- perl/Dockerfile | 2 +- perl/Makefile | 11 ++++++++++- php/Makefile | 10 ++++++++++ ps/Makefile | 15 +++++++++++++++ python/Makefile | 14 +++++++++----- r/Makefile | 10 ++++++++++ racket/Makefile | 9 +++++++++ rpython/Makefile | 7 ++++++- ruby/Makefile | 13 ++++++++++++- rust/Makefile | 7 ++++--- scala/Makefile | 13 ++++++++++++- scala/assembly.sbt | 3 +++ scala/build.sbt | 1 + scala/project/assembly.sbt | 1 + tcl/Makefile | 14 ++++++++++++++ vb/Makefile | 4 +++- vimscript/Makefile | 13 ++++++++++++- 34 files changed, 266 insertions(+), 37 deletions(-) create mode 100644 scala/assembly.sbt create mode 100644 scala/project/assembly.sbt diff --git a/.gitignore b/.gitignore index ab08f8e507..379714fd42 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,11 @@ +.bash_history +.cache +.mal-history +.crystal +.lein +.m2 +.ivy2 +.sbt */experiments */node_modules *.o @@ -13,13 +21,6 @@ */step8_macros */step9_try */stepA_mal -.bash_history -.mal-history -.crystal -.lein -.m2 -.ivy2 -.sbt awk/mal.awk bash/mal.sh c/mal @@ -32,6 +33,7 @@ crystal/mal cs/*.exe cs/*.dll cs/*.mdb +d/*.o d/mal elixir/_build elixir/deps @@ -44,6 +46,7 @@ erlang/.rebar erlang/src/*.beam es6/mal.js es6/build +forth/mal.fs fsharp/*.exe fsharp/*.dll fsharp/*.mdb @@ -57,6 +60,7 @@ haxe/*.n haxe/*.py haxe/cpp/ haxe/*.js +java/mal.jar java/target/ java/dependency-reduced-pom.xml js/mal.js @@ -66,6 +70,7 @@ kotlin/.idea kotlin/*.iml lua/lib lua/linenoise.so +lua/mal.lua make/mal.mk mal/mal.mal nim/mal @@ -76,14 +81,24 @@ ocaml/*.swp ocaml/*.cmx ocaml/*.o ocaml/mal_lib.* +ocaml/mal +perl/mal.pl php/mal.php +ps/mal.ps python/mal.pyz +r/mal.r +racket/mal +rpython/mal +ruby/mal.rb rust/target/ rust/mal rust/Cargo.lock rust/.cargo r/lib +scala/mal.jar scala/target scala/project +tcl/mal.tcl vb/*.exe vb/*.dll +vimscript/mal.vim diff --git a/Makefile b/Makefile index 3927c0879f..cf6958a08d 100644 --- a/Makefile +++ b/Makefile @@ -80,6 +80,10 @@ STEP5_EXCLUDES += crystal # test completes, even at 1,000,000 PERF_EXCLUDES = mal # TODO: fix this +DIST_EXCLUDES += mal +# TODO: still need to implement dist +DIST_EXCLUDES += factor groovy guile io julia matlab miniMAL swift + # # Utility functions # @@ -182,6 +186,8 @@ forth_RUNSTEP = gforth ../$(2) $(3) fsharp_RUNSTEP = mono ../$(2) --raw $(3) go_RUNSTEP = ../$(2) $(3) groovy_RUNSTEP = groovy ../$(2) $(3) +# needs TERM=dumb to work with readline +guile_RUNSTEP = guile --no-auto-compile -L ../guile ../$(2) $(3) haskell_RUNSTEP = ../$(2) $(3) haxe_RUNSTEP = python3 ../$(2) $(3) haxe_RUNSTEP = $(haxe_RUNSTEP_$(HAXE_MODE)) @@ -211,8 +217,6 @@ swift3_RUNSTEP = ../$(2) $(3) tcl_RUNSTEP = tclsh ../$(2) --raw $(3) vb_RUNSTEP = mono ../$(2) --raw $(3) vimscript_RUNSTEP = ./run_vimscript.sh ../$(2) $(3) -# needs TERM=dumb to work with readline -guile_RUNSTEP = guile --no-auto-compile -L ../guile ../$(2) $(3) vimscript_TEST_OPTS = --test-timeout 30 @@ -233,7 +237,8 @@ ALL_TESTS = $(filter-out $(foreach impl,$(STEP5_EXCLUDES),test^$(impl)^step5),\ IMPL_STATS = $(foreach impl,$(DO_IMPLS),stats^$(impl)) IMPL_STATS_LISP = $(foreach impl,$(DO_IMPLS),stats-lisp^$(impl)) -IMPL_DIST = $(foreach impl,$(DO_IMPLS),dist^$(impl)) +IMPL_DIST = $(filter-out $(foreach impl,$(DIST_EXCLUDES),dist^$(impl)),\ + $(foreach impl,$(DO_IMPLS),dist^$(impl))) DOCKER_BUILD = $(foreach impl,$(DO_IMPLS),docker-build^$(impl)) diff --git a/clojure/Makefile b/clojure/Makefile index fb31b760dd..10c0abf873 100644 --- a/clojure/Makefile +++ b/clojure/Makefile @@ -2,7 +2,9 @@ SOURCES_BASE = src/readline.clj src/reader.clj src/printer.clj SOURCES_LISP = src/env.clj src/core.clj src/stepA_mal.clj SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) -all dist: deps mal.jar +all: deps + +dist: mal.jar deps: lein deps diff --git a/erlang/Makefile b/erlang/Makefile index 6797446025..808a2a9019 100644 --- a/erlang/Makefile +++ b/erlang/Makefile @@ -12,7 +12,7 @@ BINS = $(SRCS:%.erl=%) ##################### -.PHONY: all mal clean stats stats-lisp +.PHONY: all dist clean stats stats-lisp all: $(BINS) @@ -34,6 +34,7 @@ $(foreach b,$(BINS),$(eval $(call dep_template,$(b)))) clean: rebar clean + rm -f mal stats: $(SOURCES) @wc $^ diff --git a/forth/Makefile b/forth/Makefile index c744471682..1dee2ae7c7 100644 --- a/forth/Makefile +++ b/forth/Makefile @@ -1,8 +1,19 @@ -SOURCES_BASE = types.fs str.fs reader.fs printer.fs +SOURCES_BASE = str.fs types.fs reader.fs printer.fs SOURCES_LISP = env.fs core.fs stepA_mal.fs SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: + true + +dist: mal.fs + +mal.fs: $(SOURCES) + echo "#! /usr/bin/env gforth" > $@ + cat $+ | egrep -v "^require |^droprequire " >> $@ + chmod +x $@ + +clean: + rm -f mal.fs .PHONY: stats tests $(TESTS) diff --git a/fsharp/Makefile b/fsharp/Makefile index 4d909ae963..9a9c41b3db 100644 --- a/fsharp/Makefile +++ b/fsharp/Makefile @@ -24,6 +24,11 @@ CSFLAGS = $(if $(strip $(DEBUG)),-debug+,) all: $(patsubst %.fs,%.exe,$(SRCS)) +dist: mal.exe + +mal.exe: stepA_mal.exe + cp $< $@ + Mono.Terminal.dll: $(TERMINAL_SOURCES) mcs $(CSFLAGS) -target:library $+ -out:$@ diff --git a/go/Makefile b/go/Makefile index b83955c138..f35976a37d 100644 --- a/go/Makefile +++ b/go/Makefile @@ -18,7 +18,9 @@ BINS = $(SRCS:%.go=%) ##################### -all: $(BINS) mal +all: $(BINS) + +dist: mal mal: $(word $(words $(BINS)),$(BINS)) cp $< $@ diff --git a/haskell/Makefile b/haskell/Makefile index 71b62342b9..b5912c6927 100644 --- a/haskell/Makefile +++ b/haskell/Makefile @@ -12,7 +12,9 @@ BINS = $(SRCS:%.hs=%) ##################### -all: $(BINS) mal +all: $(BINS) + +dist: mal mal: $(word $(words $(BINS)),$(BINS)) cp $< $@ diff --git a/haxe/Makefile b/haxe/Makefile index 031fddbe1a..3257734684 100644 --- a/haxe/Makefile +++ b/haxe/Makefile @@ -16,6 +16,20 @@ all-cpp: $(foreach x,$(STEPS),cpp/$(x)) all-js: $(foreach x,$(STEPS),$(x).js) +dist: mal.n mal.py cpp/mal mal.js + +mal.n: stepA_mal.n + cp $< $@ + +mal.py: stepA_mal.py + cp $< $@ + +cpp/mal: cpp/stepA_mal + cp $< $@ + +mal.js: stepA_mal.js + cp $< $@ + # Neko target (neko) @@ -65,4 +79,5 @@ node_modules: ### clean: + rm -f mal.n mal.py cpp/mal mal.js rm -r step*.py cpp/ step*.js step*.n diff --git a/java/Makefile b/java/Makefile index 0610ea64d1..f5e28fe05c 100644 --- a/java/Makefile +++ b/java/Makefile @@ -11,12 +11,22 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: mvn install +dist: mal.jar + +mal.jar: target/classes/mal/stepA_mal.class + mvn assembly:assembly + cp target/mal-0.0.1.jar $@ + src/main/mal/%.java: mvn install target/classes/mal/step%.class: src/main/mal/step%.java ${SOURCES} mvn install +clean: + mvn clean + rm -f mal.jar + #.PHONY: stats tests $(TESTS) .PHONY: stats diff --git a/java/pom.xml b/java/pom.xml index fa2b567357..5ee5b7c73b 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -76,6 +76,19 @@ + + maven-assembly-plugin + + + jar-with-dependencies + + + + mal.stepA_mal + + + + diff --git a/js/Makefile b/js/Makefile index 603c6888e8..175e7179ea 100644 --- a/js/Makefile +++ b/js/Makefile @@ -1,12 +1,14 @@ TESTS = tests/types.js tests/reader.js -SOURCES_BASE = node_readline.js types.js reader.js printer.js +SOURCES_BASE = node_readline.js types.js reader.js printer.js interop.js SOURCES_LISP = env.js core.js stepA_mal.js SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) WEB_SOURCES = $(SOURCES:node_readline.js=jq_readline.js) -all: node_modules mal.js web/mal.js +all: node_modules + +dist: mal.js web/mal.js node_modules: npm install diff --git a/kotlin/Makefile b/kotlin/Makefile index 841698b7fd..8ab4903786 100644 --- a/kotlin/Makefile +++ b/kotlin/Makefile @@ -7,8 +7,13 @@ JARS = $(SOURCES_LISP:%.kt=%.jar) all: $(JARS) +dist: mal.jar + +mal.jar: stepA_mal.jar + cp $< $@ + clean: - rm -vf $(JARS) + rm -vf $(JARS) mal.jar $(JARS): %.jar: src/mal/%.kt $(SOURCES_BASE:%.kt=src/mal/%.kt) kotlinc src/mal/$(@:%.jar=%.kt) $(SOURCES_BASE:%.kt=src/mal/%.kt) -include-runtime -d $@ diff --git a/lua/Makefile b/lua/Makefile index 494f3f4c00..ec48fc9fc0 100644 --- a/lua/Makefile +++ b/lua/Makefile @@ -6,12 +6,27 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: libs -.PHONY: stats tests $(TESTS) +dist: mal.lua + +SOURCE_NAMES = $(patsubst %.lua,%,$(SOURCES)) +mal.lua: $(SOURCES) + echo "#!/usr/bin/env lua" > $@ + echo "local $(foreach n,$(SOURCE_NAMES),$(n),) M" >> $@ + echo "M={} $(foreach n,$(SOURCE_NAMES),$(n)=M);" >> $@ + cat $+ | grep -v -e "return M$$" \ + -e "return Env" \ + -e "local M =" \ + -e "^#!" \ + $(foreach n,$(SOURCE_NAMES),-e "require('$(n)')") >> $@ + chmod +x $@ + clean: - rm -f linenoise.so + rm -f linenoise.so mal.lua rm -rf lib/lua/5.1 +.PHONY: stats tests $(TESTS) + stats: $(SOURCES) @wc $^ @printf "%5s %5s %5s %s\n" `grep -E "^[[:space:]]*--|^[[:space:]]*$$" $^ | wc` "[comments/blanks]" diff --git a/make/Makefile b/make/Makefile index 6dec57dd81..2270cacd20 100644 --- a/make/Makefile +++ b/make/Makefile @@ -6,6 +6,11 @@ SOURCES_BASE = util.mk numbers.mk readline.mk gmsl.mk types.mk \ SOURCES_LISP = env.mk core.mk stepA_mal.mk SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) +all: + true + +dist: mal.mk + mal.mk: $(SOURCES) echo "#!/usr/bin/make -f" > $@ cat $+ | grep -v "^include " >> $@ diff --git a/nim/Makefile b/nim/Makefile index 6183cc3921..9b145d653f 100644 --- a/nim/Makefile +++ b/nim/Makefile @@ -14,7 +14,9 @@ BINS = $(SRCS:%.nim=%) ##################### -all: $(BINS) mal +all: $(BINS) + +dist: mal mal: $(word $(words $(BINS)),$(BINS)) cp $< $@ diff --git a/ocaml/Makefile b/ocaml/Makefile index 3b98b937e6..6a2bb69ae1 100644 --- a/ocaml/Makefile +++ b/ocaml/Makefile @@ -8,7 +8,9 @@ MAL_LIB = mal_lib.cmxa STEP_BINS = $(STEPS:%.ml=%) LAST_STEP_BIN = $(word $(words $(STEP_BINS)),$(STEP_BINS)) -all: $(STEP_BINS) mal +all: $(STEP_BINS) + +dist: mal mal: $(LAST_STEP_BIN) cp $< $@ diff --git a/perl/Dockerfile b/perl/Dockerfile index 85bdfe4c72..b36833e072 100644 --- a/perl/Dockerfile +++ b/perl/Dockerfile @@ -21,4 +21,4 @@ WORKDIR /mal # Specific implementation requirements ########################################################## -RUN apt-get -y install perl +RUN apt-get -y install perl libapp-fatpacker-perl diff --git a/perl/Makefile b/perl/Makefile index 512c17ce4b..3774919734 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -5,7 +5,16 @@ SOURCES_BASE = readline.pm types.pm reader.pm printer.pm \ SOURCES_LISP = env.pm core.pm stepA_mal.pl SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) -#all: mal.pl +all: + +dist: mal.pl + +mal.pl: $(SOURCES) + echo "#!/usr/bin/env perl" > $@ + fatpack pack stepA_mal.pl >> $@ + +clean: + rm -f mal.pl .PHONY: stats tests $(TESTS) diff --git a/php/Makefile b/php/Makefile index e31bb8f848..bea654cd98 100644 --- a/php/Makefile +++ b/php/Makefile @@ -7,6 +7,16 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: +dist: mal.php + +mal.php: $(SOURCES) + echo "#!/usr/bin/env php" > $@ + cat $+ | grep -v "^require_once" >> $@ + chmod +x $@ + +clean: + rm mal.php + .PHONY: stats tests $(TESTS) stats: $(SOURCES) diff --git a/ps/Makefile b/ps/Makefile index 7a708096a7..39f7a09f34 100644 --- a/ps/Makefile +++ b/ps/Makefile @@ -5,6 +5,21 @@ SOURCES_BASE = types.ps reader.ps printer.ps SOURCES_LISP = env.ps core.ps stepA_mal.ps SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) +all: + true + +dist: mal.ps + +mal.ps: $(SOURCES) + echo "#!/bin/sh" > $@ + echo "\":\" pop pop pop pop %#; exec gs -d'#!'=null -d'\":\"'=null -q -dNODISPLAY -- \"\$$0\" \"\$$@\"" >> $@ + cat $+ | grep -v "runlibfile$$" >> $@ + chmod +x $@ + +clean: + rm -f mal.ps + + .PHONY: stats tests $(TESTS) stats: $(SOURCES) diff --git a/python/Makefile b/python/Makefile index 944e14dca7..592a7ca4b0 100644 --- a/python/Makefile +++ b/python/Makefile @@ -6,16 +6,20 @@ SOURCES_BASE = mal_readline.py mal_types.py reader.py printer.py SOURCES_LISP = env.py core.py stepA_mal.py SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) -all: mal.py +all: true -mal.py: stepA_mal.py - echo "#!/usr/bin/env python" > $@ - cat $+ >> $@ +dist: mal.pyz + +SHELL := bash +mal.pyz: $(SOURCES) + cp stepA_mal.py __main__.py + cat <(echo '#!/usr/bin/env python') <(zip -q - __main__.py $+) > $@ + rm __main__.py chmod +x $@ clean: - rm -f mal.py + rm -f mal.pyz .PHONY: stats tests $(TESTS) diff --git a/r/Makefile b/r/Makefile index c1eec79976..c1caebf7e5 100644 --- a/r/Makefile +++ b/r/Makefile @@ -6,6 +6,16 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: libs +dist: mal.r + +mal.r: $(SOURCES) + echo "#!/usr/bin/env Rscript" > $@ + cat $+ | grep -v " source(" >> $@ + chmod +x $@ + +clean: + rm -f mal.r + .PHONY: stats tests $(TESTS) stats: $(SOURCES) diff --git a/racket/Makefile b/racket/Makefile index e2da5565d7..3d55efe430 100644 --- a/racket/Makefile +++ b/racket/Makefile @@ -4,6 +4,15 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: +dist: mal + +mal: $(SOURCES) + raco exe stepA_mal.rkt + mv stepA_mal $@ + +clean: + mal + .PHONY: stats stats: $(SOURCES) diff --git a/rpython/Makefile b/rpython/Makefile index 837ca80794..a86b4dd499 100644 --- a/rpython/Makefile +++ b/rpython/Makefile @@ -10,6 +10,11 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: $(STEPS) +dist: mal + +mal: stepA_mal + cp $< $@ + %: %.py $(RPYTHON) --output=$@ $< @@ -26,7 +31,7 @@ $(UPPER_STEPS): $(STEP4_DEPS) .PHONY: clean stats stats-lisp clean: - rm -f $(STEPS) *.pyc + rm -f mal $(STEPS) *.pyc rm -rf __pycache__ stats: $(SOURCES) diff --git a/ruby/Makefile b/ruby/Makefile index f59681df83..f43de1c86f 100644 --- a/ruby/Makefile +++ b/ruby/Makefile @@ -4,7 +4,18 @@ SOURCES_BASE = mal_readline.rb types.rb reader.rb printer.rb SOURCES_LISP = env.rb core.rb stepA_mal.rb SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) -#all: mal.rb +all: + true + +dist: mal.rb + +mal.rb: $(SOURCES) + echo "#!/usr/bin/env ruby" > $@ + cat $+ | grep -v "^require_relative" >> $@ + chmod +x $@ + +clean: + rm -f mal.rb .PHONY: stats tests $(TESTS) diff --git a/rust/Makefile b/rust/Makefile index ae5f2eea20..e51072b2d0 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -17,9 +17,10 @@ BINS = $(SRCS:%.rs=target/release/%) all: mal -mal: ${SOURCES_BASE} $(word $(words ${SOURCES_LISP}),${SOURCES_LISP}) - cargo build --release - cp $(word $(words ${BINS}),${BINS}) $@ +dist: mal + +mal: target/release/stepA_mal + cp $< $@ # TODO: would be nice to build just the step requested $(BINS): target/release/%: src/bin/%.rs $(wildcard src/*.rs) diff --git a/scala/Makefile b/scala/Makefile index e4f2a82cf6..b98922b8dd 100644 --- a/scala/Makefile +++ b/scala/Makefile @@ -4,9 +4,20 @@ SOURCES_BASE = types.scala reader.scala printer.scala SOURCES_LISP = env.scala core.scala stepA_mal.scala SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) -all: +all: build + +build: sbt 'run-main stepA_mal ../tests/incA.mal' +dist: mal.jar + +mal.jar: $(SOURCES) + sbt assembly + cp target/scala-*/mal-assembly*.jar $@ + +clean: + rm -f mal.jar + .PHONY: stats tests $(TESTS) stats: $(SOURCES) diff --git a/scala/assembly.sbt b/scala/assembly.sbt new file mode 100644 index 0000000000..d7a8cdfb27 --- /dev/null +++ b/scala/assembly.sbt @@ -0,0 +1,3 @@ +import AssemblyKeys._ // put this at the top of the file + +assemblySettings diff --git a/scala/build.sbt b/scala/build.sbt index d2a2802e6c..a48150acaa 100644 --- a/scala/build.sbt +++ b/scala/build.sbt @@ -13,3 +13,4 @@ showSuccess := false logLevel in runMain := Level.Warn +mainClass in Compile := Some("stepA_mal") diff --git a/scala/project/assembly.sbt b/scala/project/assembly.sbt new file mode 100644 index 0000000000..54c32528e9 --- /dev/null +++ b/scala/project/assembly.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.11.2") diff --git a/tcl/Makefile b/tcl/Makefile index d030e1ae72..0e5396dbff 100644 --- a/tcl/Makefile +++ b/tcl/Makefile @@ -4,6 +4,20 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) .PHONY: stats stats-lisp +all: + true + +dist: mal.tcl + +mal.tcl: $(SOURCES) + echo "#!/usr/bin/env tclsh" > $@ + cat $+ | grep -v "^source " >> $@ + chmod +x $@ + +clean: + rm -f mal.tcl + + stats: $(SOURCES) @wc $^ @printf "%5s %5s %5s %s\n" `grep -E "^[[:space:]]*\"|^[[:space:]]*$$" $^ | wc` "[comments/blanks]" diff --git a/vb/Makefile b/vb/Makefile index 43d71d9c2e..ce5145a08f 100644 --- a/vb/Makefile +++ b/vb/Makefile @@ -21,7 +21,9 @@ FLAGS = $(if $(strip $(DEBUG)),-debug:full,) ##################### -all: mal.exe $(patsubst %.vb,%.exe,$(SRCS)) +all: $(patsubst %.vb,%.exe,$(SRCS)) + +dist: mal.exe mal.exe: $(patsubst %.vb,%.exe,$(word $(words $(SOURCES)),$(SOURCES))) cp $< $@ diff --git a/vimscript/Makefile b/vimscript/Makefile index 69cdf2b457..dfb12715dc 100644 --- a/vimscript/Makefile +++ b/vimscript/Makefile @@ -4,6 +4,17 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: libvimreadline.so +dist: mal.vim + +mal.vim: $(SOURCES) + echo "#!/bin/sh" > $@ + echo "\":\" ; rundir=\`dirname \$$0\`" >> $@ + echo "\":\" ; export LD_LIBRARY_PATH=\`readlink -f \$$rundir\`" >> $@ + echo "\":\" ; exec vim -i NONE -V1 -nNesS \"\$$0\" -- \"\$$@\"" >> $@ + cat $+ | grep -v "^source " >> $@ + chmod +x $@ + + libvimreadline.so: vimreadline.o $(CC) -g -shared -o $@ $< -lreadline @@ -11,7 +22,7 @@ vimreadline.o: vimreadline.c $(CC) -g -fPIC -c $< -o $@ clean: - rm -f vimreadline.o libvimreadline.so + rm -f vimreadline.o libvimreadline.so mal.vim stats: $(SOURCES) @wc $^ From 8e2d4a4ccb08a5baf8e169f7b20e4b7abb0752fc Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Wed, 24 Feb 2016 00:45:40 -0600 Subject: [PATCH 07/14] Dist/packaging for most impls. erlang, racket *ARGV* fixes. Also in this commit: - fix *ARGV* setup in erlang and racket. - print startup message in fsharp Dist/packaging support for most implementations and also generate a */mal standalone app for most languages. The following implementations still have ability to generate a single */mal standalone application: - guile - julia - matlab (mkoctfile doesn't actually package up source files) - swift - vb (mkbundle error) Also, the following are mostly packaged into a single file but need some module dependencies - coffee: requires node_modules/ffi - es6: requires node_modules/ffi - js: requires node_modules/ffi - lua: module 'readline' not found - miniMAL: cannot find module '/mal/node_readline.js' - r: needs lib directory --- .gitignore | 17 +---- awk/Makefile | 11 ++- bash/Makefile | 9 ++- clojure/Makefile | 11 ++- coffee/Makefile | 9 ++- cs/Dockerfile | 2 +- cs/Makefile | 10 ++- erlang/src/step6_file.erl | 2 +- erlang/src/step7_quote.erl | 2 +- erlang/src/step8_macros.erl | 2 +- erlang/src/step9_try.erl | 2 +- erlang/src/stepA_mal.erl | 2 +- es6/Makefile | 10 ++- factor/Makefile | 32 +++++++- factor/{mal => lib}/core/core-tests.factor | 2 +- factor/{mal => lib}/core/core.factor | 6 +- factor/{mal => lib}/env/env-tests.factor | 4 +- factor/{mal => lib}/env/env.factor | 2 +- .../{mal => lib}/printer/printer-tests.factor | 4 +- factor/{mal => lib}/printer/printer.factor | 4 +- .../{mal => lib}/reader/reader-tests.factor | 4 +- factor/{mal => lib}/reader/reader.factor | 4 +- factor/{mal => lib}/types/types.factor | 4 +- .../step1_read_print/step1_read_print.factor | 2 +- factor/step2_eval/step2_eval.factor | 2 +- factor/step3_env/step3_env.factor | 4 +- factor/step4_if_fn_do/step4_if_fn_do.factor | 4 +- factor/step5_tco/step5_tco.factor | 4 +- factor/step6_file/step6_file.factor | 2 +- factor/step7_quote/step7_quote.factor | 4 +- factor/step8_macros/step8_macros.factor | 4 +- factor/step9_try/step9_try.factor | 4 +- factor/stepA_mal/stepA_mal.factor | 4 +- forth/Makefile | 9 ++- fsharp/Dockerfile | 2 +- fsharp/Makefile | 10 ++- fsharp/stepA_mal.fs | 1 + groovy/Dockerfile | 3 +- groovy/GroovyWrapper.groovy | 76 +++++++++++++++++++ groovy/Makefile | 22 ++++-- guile/Makefile | 14 +++- haxe/Makefile | 39 +++++++++- java/Makefile | 9 ++- js/Makefile | 7 +- kotlin/Makefile | 9 ++- lua/Makefile | 11 ++- make/Makefile | 9 ++- mal/Makefile | 3 + miniMAL/Makefile | 16 ++++ perl/Makefile | 16 +++- php/Makefile | 9 ++- ps/Makefile | 9 ++- python/Dockerfile | 3 + python/Makefile | 10 ++- r/Makefile | 9 ++- racket/Makefile | 2 +- racket/stepA_mal.rkt | 4 +- ruby/Makefile | 9 ++- scala/Makefile | 10 ++- tcl/Makefile | 9 ++- vb/Dockerfile | 2 +- vimscript/Makefile | 11 ++- 62 files changed, 400 insertions(+), 132 deletions(-) rename factor/{mal => lib}/core/core-tests.factor (93%) rename factor/{mal => lib}/core/core.factor (95%) rename factor/{mal => lib}/env/env-tests.factor (92%) rename factor/{mal => lib}/env/env.factor (98%) rename factor/{mal => lib}/printer/printer-tests.factor (91%) rename factor/{mal => lib}/printer/printer.factor (92%) rename factor/{mal => lib}/reader/reader-tests.factor (88%) rename factor/{mal => lib}/reader/reader.factor (96%) rename factor/{mal => lib}/types/types.factor (95%) create mode 100644 groovy/GroovyWrapper.groovy diff --git a/.gitignore b/.gitignore index 379714fd42..d1a11b3048 100644 --- a/.gitignore +++ b/.gitignore @@ -21,39 +21,34 @@ */step8_macros */step9_try */stepA_mal +*/mal awk/mal.awk bash/mal.sh -c/mal -cpp/mal clojure/mal.jar clojure/target clojure/.lein-repl-history coffee/mal.coffee -crystal/mal cs/*.exe cs/*.dll cs/*.mdb d/*.o -d/mal elixir/_build elixir/deps elixir/erl_crash.dump -elixir/mal elixir/*.ez -erlang/mal erlang/ebin erlang/.rebar erlang/src/*.beam es6/mal.js es6/build +factor/mal.factor forth/mal.fs fsharp/*.exe fsharp/*.dll fsharp/*.mdb go/step* -go/mal groovy/*.class -haskell/mal +groovy/mal.jar haskell/*.hi haskell/*.o haxe/*.n @@ -73,7 +68,7 @@ lua/linenoise.so lua/mal.lua make/mal.mk mal/mal.mal -nim/mal +miniMAL/mal.json nim/nimcache* ocaml/*.cmi ocaml/*.cmo @@ -81,17 +76,13 @@ ocaml/*.swp ocaml/*.cmx ocaml/*.o ocaml/mal_lib.* -ocaml/mal perl/mal.pl php/mal.php ps/mal.ps python/mal.pyz r/mal.r -racket/mal -rpython/mal ruby/mal.rb rust/target/ -rust/mal rust/Cargo.lock rust/.cargo r/lib diff --git a/awk/Makefile b/awk/Makefile index 1842efa3bd..1136bc0bf6 100644 --- a/awk/Makefile +++ b/awk/Makefile @@ -9,16 +9,19 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: true -dist: mal.awk +dist: mal.awk mal mal.awk: $(SOURCES) - echo '#!/bin/sh' > $@ - echo 'arbitrary_long_name==0 "exec" "/usr/bin/gawk" "-O" "-f" "$$0" "$$@"' >> $@ + echo 'arbitrary_long_name==0 "exec" "/usr/bin/gawk" "-O" "-f" "$$0" "$$@"' > $@ cat $+ | grep -v "^@include " >> $@ + +mal: mal.awk + echo '#!/bin/sh' > $@ + cat $< >> $@ chmod +x $@ clean: - rm -f mal.awk + rm -f mal.awk mal .PHONY: stats tests $(TESTS) diff --git a/bash/Makefile b/bash/Makefile index 0bbdc9a774..488a4ffe4e 100644 --- a/bash/Makefile +++ b/bash/Makefile @@ -5,15 +5,18 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: true -dist: mal.sh +dist: mal.sh mal mal.sh: $(SOURCES) + cat $+ | grep -v "^source " > $@ + +mal: mal.sh echo "#!/usr/bin/env bash" > $@ - cat $+ | grep -v "^source " >> $@ + cat $< >> $@ chmod +x $@ clean: - rm -f mal.sh + rm -f mal.sh mal .PHONY: stats diff --git a/clojure/Makefile b/clojure/Makefile index 10c0abf873..5405497fae 100644 --- a/clojure/Makefile +++ b/clojure/Makefile @@ -4,7 +4,7 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: deps -dist: mal.jar +dist: mal.jar mal deps: lein deps @@ -13,8 +13,13 @@ mal.jar: $(SOURCES) lein with-profile +jar uberjar cp target/mal-0.0.1-SNAPSHOT-standalone.jar $@ -clear: - rm -rf target/ mal.jar +SHELL := bash +mal: mal.jar + cat <(echo -e '#!/bin/sh\nexec java -jar "$$0" "$$@"') mal.jar > $@ + chmod +x mal + +clean: + rm -rf target/ mal.jar mal .PHONY: stats diff --git a/coffee/Makefile b/coffee/Makefile index 3397bb9461..0c2b36737a 100644 --- a/coffee/Makefile +++ b/coffee/Makefile @@ -10,15 +10,18 @@ all: node_modules dist node_modules: npm install -dist: mal.coffee +dist: mal.coffee mal mal.coffee: $(SOURCES) + cat $+ | grep -v "= *require('./" > $@ + +mal: mal.coffee echo "#!/usr/bin/env coffee" > $@ - cat $+ | grep -v "= *require('./" >> $@ + cat $< >> $@ chmod +x $@ clean: - rm -f mal.coffee + rm -f mal.coffee mal .PHONY: stats tests $(TESTS) diff --git a/cs/Dockerfile b/cs/Dockerfile index 138d19a2c9..f5f133484d 100644 --- a/cs/Dockerfile +++ b/cs/Dockerfile @@ -22,4 +22,4 @@ WORKDIR /mal ########################################################## # Deps for Mono-based languages (C#, VB.Net) -RUN apt-get -y install mono-runtime mono-mcs mono-vbnc +RUN apt-get -y install mono-runtime mono-mcs mono-vbnc mono-devel diff --git a/cs/Makefile b/cs/Makefile index eecc5f61fe..8431f704c1 100644 --- a/cs/Makefile +++ b/cs/Makefile @@ -24,11 +24,17 @@ FLAGS = $(if $(strip $(DEBUG)),-debug+,) all: $(patsubst %.cs,%.exe,$(SRCS)) -dist: mal.exe +dist: mal.exe mal mal.exe: $(patsubst %.cs,%.exe,$(word $(words $(SOURCES)),$(SOURCES))) cp $< $@ +# NOTE/WARNING: static linking triggers mono libraries LGPL +# distribution requirements. +# http://www.mono-project.com/archived/guiderunning_mono_applications/ +mal: $(patsubst %.cs,%.exe,$(word $(words $(SOURCES)),$(SOURCES))) mal.dll + mkbundle --static -o $@ $+ --deps + mal.dll: $(LIB_SRCS) mcs $(FLAGS) -target:library $+ -out:$@ @@ -36,7 +42,7 @@ mal.dll: $(LIB_SRCS) mcs $(FLAGS) -r:mal.dll $< clean: - rm -f *.dll *.exe *.mdb + rm -f mal *.dll *.exe *.mdb .PHONY: stats tests $(TESTS) diff --git a/erlang/src/step6_file.erl b/erlang/src/step6_file.erl index cc84144b6c..f4677b254d 100644 --- a/erlang/src/step6_file.erl +++ b/erlang/src/step6_file.erl @@ -8,7 +8,7 @@ main([File|Args]) -> Env = init(), - env:set(Env, {symbol, "*ARGV*"}, {list, Args, nil}), + env:set(Env, {symbol, "*ARGV*"}, {list, [{string,Arg} || Arg <- Args], nil}), rep("(load-file \"" ++ File ++ "\")", Env); main([]) -> Env = init(), diff --git a/erlang/src/step7_quote.erl b/erlang/src/step7_quote.erl index bcea524b38..6ac3363e5b 100644 --- a/erlang/src/step7_quote.erl +++ b/erlang/src/step7_quote.erl @@ -8,7 +8,7 @@ main([File|Args]) -> Env = init(), - env:set(Env, {symbol, "*ARGV*"}, {list, Args, nil}), + env:set(Env, {symbol, "*ARGV*"}, {list, [{string,Arg} || Arg <- Args], nil}), rep("(load-file \"" ++ File ++ "\")", Env); main([]) -> Env = init(), diff --git a/erlang/src/step8_macros.erl b/erlang/src/step8_macros.erl index afe1472fc6..e9dcadacc6 100644 --- a/erlang/src/step8_macros.erl +++ b/erlang/src/step8_macros.erl @@ -8,7 +8,7 @@ main([File|Args]) -> Env = init(), - env:set(Env, {symbol, "*ARGV*"}, {list, Args, nil}), + env:set(Env, {symbol, "*ARGV*"}, {list, [{string,Arg} || Arg <- Args], nil}), rep("(load-file \"" ++ File ++ "\")", Env); main([]) -> Env = init(), diff --git a/erlang/src/step9_try.erl b/erlang/src/step9_try.erl index 5a0c4fd2d2..8310358eda 100644 --- a/erlang/src/step9_try.erl +++ b/erlang/src/step9_try.erl @@ -8,7 +8,7 @@ main([File|Args]) -> Env = init(), - env:set(Env, {symbol, "*ARGV*"}, {list, Args, nil}), + env:set(Env, {symbol, "*ARGV*"}, {list, [{string,Arg} || Arg <- Args], nil}), rep("(load-file \"" ++ File ++ "\")", Env); main([]) -> Env = init(), diff --git a/erlang/src/stepA_mal.erl b/erlang/src/stepA_mal.erl index 4aee0242e0..24061c980d 100644 --- a/erlang/src/stepA_mal.erl +++ b/erlang/src/stepA_mal.erl @@ -8,7 +8,7 @@ main([File|Args]) -> Env = init(), - env:set(Env, {symbol, "*ARGV*"}, {list, Args, nil}), + env:set(Env, {symbol, "*ARGV*"}, {list, [{string,Arg} || Arg <- Args], nil}), rep("(load-file \"" ++ File ++ "\")", Env); main([]) -> Env = init(), diff --git a/es6/Makefile b/es6/Makefile index 593a0ec7b2..d576e5b51e 100644 --- a/es6/Makefile +++ b/es6/Makefile @@ -9,7 +9,7 @@ STEPS = step0_repl step1_read_print step2_eval step3_env \ all: node_modules $(foreach s,$(STEPS),build/$(s).js) -dist: mal.js +dist: mal.js mal build/%.js: %.js @mkdir -p $(dir $@) @@ -17,8 +17,12 @@ build/%.js: %.js @echo >> $@ # workaround node-uglifier bug mal.js: $(foreach s,$(SOURCES),build/$(s)) - node -e 'nu = new (require("node-uglifier"))("./build/stepA_mal.js"); nu.merge().exportToFile("./mal.js")' + node -e 'nu = new (require("node-uglifier"))("./build/stepA_mal.js"); nu.merge().exportToFile("$@")' +mal: mal.js + echo "#!/usr/bin/env node" > $@ + cat $< >> $@ + chmod +x $@ build/step0_repl.js: step0_repl.js build/node_readline.js build/step1_read_print.js: step1_read_print.js build/node_readline.js build/types.js build/reader.js build/printer.js @@ -37,7 +41,7 @@ node_modules: npm install clean: - rm -f build/* mal.js + rm -f build/* mal.js mal .PHONY: stats tests $(TESTS) diff --git a/factor/Makefile b/factor/Makefile index e7518af2cb..b11d591f32 100644 --- a/factor/Makefile +++ b/factor/Makefile @@ -1,9 +1,37 @@ TESTS = -SOURCES_BASE = mal/types/types.factor mal/reader/reader.factor mal/printer/printer.factor -SOURCES_LISP = mal/env/env.factor mal/core/core.factor stepA_mal/stepA_mal.factor +SOURCES_BASE = lib/types/types.factor lib/reader/reader.factor lib/printer/printer.factor +SOURCES_LISP = lib/env/env.factor lib/core/core.factor stepA_mal/stepA_mal.factor SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) +all: + true + +dist: mal.factor mal + +# dependency order (env must come before types) +ORDERED_SOURCES = $(filter %env.factor,$(SOURCES)) $(filter-out %env.factor,$(SOURCES)) +mal.factor: $(ORDERED_SOURCES) + cat $+ | sed '/^USING:/,/;/ s/ *lib.[a-z]*//g' > $@ + +mal: mal.factor + echo '#!/usr/bin/env factor' > $@ + cat $< >> $@ + chmod +x $@ + +# TODO: standalone compiled app +#mal.factor: $(SOURCES) +# mkdir -p dist_tmp; \ +# FDIR=$$(dirname $$(readlink -f $$(which factor))); \ +# for f in $${FDIR}/*; do ln -sf $$f dist_tmp/; done; \ +# rm dist_tmp/factor; \ +# cp $${FDIR}/factor dist_tmp/factor; \ +# HOME=/mal FACTOR_ROOTS=. dist_tmp/factor dist.factor +# #cat $+ | sed 's///' >> $@ + +clean: + rm -f mal.factor + .PHONY: stats stats-lisp stats: $(SOURCES) diff --git a/factor/mal/core/core-tests.factor b/factor/lib/core/core-tests.factor similarity index 93% rename from factor/mal/core/core-tests.factor rename to factor/lib/core/core-tests.factor index b120b9af27..0e603c1faf 100644 --- a/factor/mal/core/core-tests.factor +++ b/factor/lib/core/core-tests.factor @@ -1,5 +1,5 @@ USING: assocs effects kernel sequences stack-checker tools.test ; -IN: mal.core +IN: lib.core { t } [ ns values [ diff --git a/factor/mal/core/core.factor b/factor/lib/core/core.factor similarity index 95% rename from factor/mal/core/core.factor rename to factor/lib/core/core.factor index 0a23a1696f..9bdf68651a 100644 --- a/factor/mal/core/core.factor +++ b/factor/lib/core/core.factor @@ -2,10 +2,10 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs combinators combinators.short-circuit fry grouping hash-sets hashtables io -io.encodings.utf8 io.files kernel lists mal.env mal.printer -mal.reader mal.types math namespaces readline sequences sets +io.encodings.utf8 io.files kernel lists lib.env lib.printer +lib.reader lib.types math namespaces readline sequences sets system vectors ; -IN: mal.core +IN: lib.core SYMBOL: mal-apply diff --git a/factor/mal/env/env-tests.factor b/factor/lib/env/env-tests.factor similarity index 92% rename from factor/mal/env/env-tests.factor rename to factor/lib/env/env-tests.factor index 382516ac8e..937c98ae82 100644 --- a/factor/mal/env/env-tests.factor +++ b/factor/lib/env/env-tests.factor @@ -1,5 +1,5 @@ -USING: assocs kernel mal.types tools.test ; -IN: mal.env +USING: assocs kernel lib.types tools.test ; +IN: lib.env { "1" } [ T{ malsymbol { name "foo" } } diff --git a/factor/mal/env/env.factor b/factor/lib/env/env.factor similarity index 98% rename from factor/mal/env/env.factor rename to factor/lib/env/env.factor index 06edb9e201..b1ca0e96c7 100644 --- a/factor/mal/env/env.factor +++ b/factor/lib/env/env.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors assocs formatting hashtables kernel math sequences typed ; -IN: mal.env +IN: lib.env TUPLE: malenv { outer read-only } diff --git a/factor/mal/printer/printer-tests.factor b/factor/lib/printer/printer-tests.factor similarity index 91% rename from factor/mal/printer/printer-tests.factor rename to factor/lib/printer/printer-tests.factor index fd6df76664..3ab2ce1ce8 100644 --- a/factor/mal/printer/printer-tests.factor +++ b/factor/lib/printer/printer-tests.factor @@ -1,5 +1,5 @@ -USING: lists mal.types tools.test ; -IN: mal.printer +USING: lists lib.types tools.test ; +IN: lib.printer { "(atom \"foo\")" } [ T{ malatom { val "foo" } } pr-str ] unit-test { "#" } [ T{ malfn } pr-str ] unit-test diff --git a/factor/mal/printer/printer.factor b/factor/lib/printer/printer.factor similarity index 92% rename from factor/mal/printer/printer.factor rename to factor/lib/printer/printer.factor index 0235dc2b9e..8ff4266afe 100644 --- a/factor/mal/printer/printer.factor +++ b/factor/lib/printer/printer.factor @@ -1,9 +1,9 @@ ! Copyright (C) 2015 Jordan Lewis. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs fry hashtables kernel lists -mal.types math math.parser sequences splitting strings summary +lib.types math math.parser sequences splitting strings summary vectors ; -IN: mal.printer +IN: lib.printer GENERIC# (pr-str) 1 ( maltype readably? -- str ) M: object (pr-str) drop summary ; diff --git a/factor/mal/reader/reader-tests.factor b/factor/lib/reader/reader-tests.factor similarity index 88% rename from factor/mal/reader/reader-tests.factor rename to factor/lib/reader/reader-tests.factor index 04080e7b9f..993a4c7789 100644 --- a/factor/mal/reader/reader-tests.factor +++ b/factor/lib/reader/reader-tests.factor @@ -1,5 +1,5 @@ -USING: lists mal.types tools.test ; -IN: mal.reader +USING: lists lib.types tools.test ; +IN: lib.reader { "foo" } [ "\"foo\"" read-atom ] unit-test { T{ malkeyword { name "foo" } } } [ ":foo" read-atom ] unit-test diff --git a/factor/mal/reader/reader.factor b/factor/lib/reader/reader.factor similarity index 96% rename from factor/mal/reader/reader.factor rename to factor/lib/reader/reader.factor index cd2fe8bd1b..587ed90ab7 100644 --- a/factor/mal/reader/reader.factor +++ b/factor/lib/reader/reader.factor @@ -1,8 +1,8 @@ ! Copyright (C) 2015 Jordan Lewis. ! See http://factorcode.org/license.txt for BSD license. USING: arrays combinators grouping hashtables kernel lists -locals make mal.types math.parser regexp sequences splitting ; -IN: mal.reader +locals make lib.types math.parser regexp sequences splitting ; +IN: lib.reader CONSTANT: token-regex R/ (~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)~^@]+)/ diff --git a/factor/mal/types/types.factor b/factor/lib/types/types.factor similarity index 95% rename from factor/mal/types/types.factor rename to factor/lib/types/types.factor index a99dfd1822..d018042320 100644 --- a/factor/mal/types/types.factor +++ b/factor/lib/types/types.factor @@ -1,8 +1,8 @@ ! Copyright (C) 2015 Jordan Lewis. ! See http://factorcode.org/license.txt for BSD license. USING: accessors assocs combinators.short-circuit hashtables -kernel locals mal.env sequences strings ; -IN: mal.types +kernel locals lib.env sequences strings ; +IN: lib.types TUPLE: malsymbol { name string read-only } ; diff --git a/factor/step1_read_print/step1_read_print.factor b/factor/step1_read_print/step1_read_print.factor index 79a357df76..fe42cad03d 100755 --- a/factor/step1_read_print/step1_read_print.factor +++ b/factor/step1_read_print/step1_read_print.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2015 Jordan Lewis. ! See http://factorcode.org/license.txt for BSD license. -USING: continuations io kernel mal.printer mal.reader readline +USING: continuations io kernel lib.printer lib.reader readline sequences ; IN: step1_read_print diff --git a/factor/step2_eval/step2_eval.factor b/factor/step2_eval/step2_eval.factor index eed373328b..ca11c1a706 100755 --- a/factor/step2_eval/step2_eval.factor +++ b/factor/step2_eval/step2_eval.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2015 Jordan Lewis. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs combinators continuations fry io -kernel math mal.printer mal.reader mal.types quotations readline +kernel math lib.printer lib.reader lib.types quotations readline sequences ; IN: step2_eval diff --git a/factor/step3_env/step3_env.factor b/factor/step3_env/step3_env.factor index 22b87a8724..9883c3f297 100755 --- a/factor/step3_env/step3_env.factor +++ b/factor/step3_env/step3_env.factor @@ -1,8 +1,8 @@ ! Copyright (C) 2015 Jordan Lewis. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs combinators continuations fry -grouping hashtables io kernel locals mal.env mal.printer -mal.reader mal.types math namespaces quotations readline +grouping hashtables io kernel locals lib.env lib.printer +lib.reader lib.types math namespaces quotations readline sequences ; IN: step3_env diff --git a/factor/step4_if_fn_do/step4_if_fn_do.factor b/factor/step4_if_fn_do/step4_if_fn_do.factor index 3c3ef555bf..18f79f42a2 100755 --- a/factor/step4_if_fn_do/step4_if_fn_do.factor +++ b/factor/step4_if_fn_do/step4_if_fn_do.factor @@ -1,8 +1,8 @@ ! Copyright (C) 2015 Jordan Lewis. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs combinators continuations fry -grouping hashtables io kernel lists locals mal.core mal.env -mal.printer mal.reader mal.types math namespaces quotations +grouping hashtables io kernel lists locals lib.core lib.env +lib.printer lib.reader lib.types math namespaces quotations readline sequences splitting ; IN: step4_if_fn_do diff --git a/factor/step5_tco/step5_tco.factor b/factor/step5_tco/step5_tco.factor index 5bbad0fa1e..964abc655e 100755 --- a/factor/step5_tco/step5_tco.factor +++ b/factor/step5_tco/step5_tco.factor @@ -1,8 +1,8 @@ ! Copyright (C) 2015 Jordan Lewis. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs combinators continuations fry -grouping hashtables io kernel lists locals mal.core mal.env -mal.printer mal.reader mal.types math namespaces quotations +grouping hashtables io kernel lists locals lib.core lib.env +lib.printer lib.reader lib.types math namespaces quotations readline sequences splitting ; IN: step5_tco diff --git a/factor/step6_file/step6_file.factor b/factor/step6_file/step6_file.factor index 665420aa47..a63469de9b 100755 --- a/factor/step6_file/step6_file.factor +++ b/factor/step6_file/step6_file.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs combinators command-line continuations fry grouping hashtables io kernel lists locals -mal.core mal.env mal.printer mal.reader mal.types math +lib.core lib.env lib.printer lib.reader lib.types math namespaces quotations readline sequences splitting ; IN: step6_file diff --git a/factor/step7_quote/step7_quote.factor b/factor/step7_quote/step7_quote.factor index a6aaac72f1..1c539baca6 100755 --- a/factor/step7_quote/step7_quote.factor +++ b/factor/step7_quote/step7_quote.factor @@ -2,8 +2,8 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs combinators combinators.short-circuit command-line continuations fry -grouping hashtables io kernel lists locals mal.core mal.env -mal.printer mal.reader mal.types math namespaces quotations +grouping hashtables io kernel lists locals lib.core lib.env +lib.printer lib.reader lib.types math namespaces quotations readline sequences splitting ; IN: step7_quote diff --git a/factor/step8_macros/step8_macros.factor b/factor/step8_macros/step8_macros.factor index ef81c8ec7b..280307a718 100755 --- a/factor/step8_macros/step8_macros.factor +++ b/factor/step8_macros/step8_macros.factor @@ -2,8 +2,8 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs combinators combinators.short-circuit command-line continuations fry -grouping hashtables io kernel lists locals mal.core mal.env -mal.printer mal.reader mal.types math namespaces quotations +grouping hashtables io kernel lists locals lib.core lib.env +lib.printer lib.reader lib.types math namespaces quotations readline sequences splitting ; IN: step8_macros diff --git a/factor/step9_try/step9_try.factor b/factor/step9_try/step9_try.factor index 3e5c293bc7..af2eb02ac6 100755 --- a/factor/step9_try/step9_try.factor +++ b/factor/step9_try/step9_try.factor @@ -2,8 +2,8 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs combinators combinators.short-circuit command-line continuations fry -grouping hashtables io kernel lists locals mal.core mal.env -mal.printer mal.reader mal.types math namespaces quotations +grouping hashtables io kernel lists locals lib.core lib.env +lib.printer lib.reader lib.types math namespaces quotations readline sequences splitting ; IN: step9_try diff --git a/factor/stepA_mal/stepA_mal.factor b/factor/stepA_mal/stepA_mal.factor index bf2e0cbee7..97ba79785b 100755 --- a/factor/stepA_mal/stepA_mal.factor +++ b/factor/stepA_mal/stepA_mal.factor @@ -2,8 +2,8 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs combinators combinators.short-circuit command-line continuations fry -grouping hashtables io kernel lists locals mal.core mal.env -mal.printer mal.reader mal.types math namespaces quotations +grouping hashtables io kernel lists locals lib.core lib.env +lib.printer lib.reader lib.types math namespaces quotations readline sequences splitting strings ; IN: stepA_mal diff --git a/forth/Makefile b/forth/Makefile index 1dee2ae7c7..c619d19684 100644 --- a/forth/Makefile +++ b/forth/Makefile @@ -5,15 +5,18 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: true -dist: mal.fs +dist: mal.fs mal mal.fs: $(SOURCES) + cat $+ | egrep -v "^require |^droprequire " > $@ + +mal: mal.fs echo "#! /usr/bin/env gforth" > $@ - cat $+ | egrep -v "^require |^droprequire " >> $@ + cat $< >> $@ chmod +x $@ clean: - rm -f mal.fs + rm -f mal.fs mal .PHONY: stats tests $(TESTS) diff --git a/fsharp/Dockerfile b/fsharp/Dockerfile index 454eccf658..01cf8044c7 100644 --- a/fsharp/Dockerfile +++ b/fsharp/Dockerfile @@ -22,6 +22,6 @@ WORKDIR /mal ########################################################## # Deps for Mono-based languages (C#, VB.Net) -RUN apt-get -y install mono-runtime mono-mcs mono-vbnc +RUN apt-get -y install mono-runtime mono-mcs mono-vbnc mono-devel RUN apt-get -y install fsharp diff --git a/fsharp/Makefile b/fsharp/Makefile index 9a9c41b3db..9c56a1e021 100644 --- a/fsharp/Makefile +++ b/fsharp/Makefile @@ -24,11 +24,17 @@ CSFLAGS = $(if $(strip $(DEBUG)),-debug+,) all: $(patsubst %.fs,%.exe,$(SRCS)) -dist: mal.exe +dist: mal.exe mal mal.exe: stepA_mal.exe cp $< $@ +# NOTE/WARNING: static linking triggers mono libraries LGPL +# distribution requirements. +# http://www.mono-project.com/archived/guiderunning_mono_applications/ +mal: $(patsubst %.fs,%.exe,$(word $(words $(SOURCES)),$(SOURCES))) Mono.Terminal.dll mal.dll + mkbundle --static -o $@ $+ --deps + Mono.Terminal.dll: $(TERMINAL_SOURCES) mcs $(CSFLAGS) -target:library $+ -out:$@ @@ -39,7 +45,7 @@ mal.dll: $(DLL_SOURCES) Mono.Terminal.dll fsharpc $(FSFLAGS) -o $@ -r mal.dll $< clean: - rm -f *.dll *.exe *.mdb + rm -f mal *.dll *.exe *.mdb .PHONY: stats tests $(TESTS) diff --git a/fsharp/stepA_mal.fs b/fsharp/stepA_mal.fs index 6bcae091fb..f8a53683f3 100644 --- a/fsharp/stepA_mal.fs +++ b/fsharp/stepA_mal.fs @@ -243,6 +243,7 @@ module REPL |> REP env 0 | _ -> + RE env "(println (str \"Mal [\" *host-language* \"]\"))" |> Seq.iter ignore let rec loop () = match Readline.read "user> " mode with | null -> 0 diff --git a/groovy/Dockerfile b/groovy/Dockerfile index c2657615fb..196698ab78 100644 --- a/groovy/Dockerfile +++ b/groovy/Dockerfile @@ -25,5 +25,6 @@ WORKDIR /mal RUN apt-get -y install openjdk-7-jdk #RUN apt-get -y install maven2 #ENV MAVEN_OPTS -Duser.home=/mal -RUN apt-get -y install groovy +RUN apt-get -y install ant +RUN apt-get -y install groovy diff --git a/groovy/GroovyWrapper.groovy b/groovy/GroovyWrapper.groovy new file mode 100644 index 0000000000..b375dd7a24 --- /dev/null +++ b/groovy/GroovyWrapper.groovy @@ -0,0 +1,76 @@ +/* From: + * http://groovy.jmiguel.eu/groovy.codehaus.org/WrappingGroovyScript.html + */ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Wrap a script and groovy jars to an executable jar + */ +def cli = new CliBuilder() +cli.h( longOpt: 'help', required: false, 'show usage information' ) +cli.d( longOpt: 'destfile', argName: 'destfile', required: false, args: 1, 'jar destintation filename, defaults to {mainclass}.jar' ) +cli.m( longOpt: 'mainclass', argName: 'mainclass', required: true, args: 1, 'fully qualified main class, eg. HelloWorld' ) +cli.c( longOpt: 'groovyc', required: false, 'Run groovyc' ) + +//-------------------------------------------------------------------------- +def opt = cli.parse(args) +if (!opt) { return } +if (opt.h) { + cli.usage(); + return +} + +def mainClass = opt.m +def scriptBase = mainClass.replace( '.', '/' ) +def scriptFile = new File( scriptBase + '.groovy' ) +if (!scriptFile.canRead()) { + println "Cannot read script file: '${scriptFile}'" + return +} +def destFile = scriptBase + '.jar' +if (opt.d) { + destFile = opt.d +} + +//-------------------------------------------------------------------------- +def ant = new AntBuilder() + +if (opt.c) { + ant.echo( "Compiling ${scriptFile}" ) + org.codehaus.groovy.tools.FileSystemCompiler.main( [ scriptFile ] as String[] ) +} + +def GROOVY_HOME = new File( System.getenv('GROOVY_HOME') ) +if (!GROOVY_HOME.canRead()) { + ant.echo( "Missing environment variable GROOVY_HOME: '${GROOVY_HOME}'" ) + return +} + +ant.jar( destfile: destFile, compress: true, index: true ) { + //fileset( dir: '.', includes: scriptBase + '*.class' ) + fileset( dir: '.', includes: '*.class' ) + + zipgroupfileset( dir: GROOVY_HOME, includes: 'embeddable/groovy-all-*.jar' ) + zipgroupfileset( dir: GROOVY_HOME, includes: 'lib/commons*.jar' ) + // add more jars here + + manifest { + attribute( name: 'Main-Class', value: mainClass ) + } +} + +ant.echo( "Run script using: \'java -jar ${destFile} ...\'" ) diff --git a/groovy/Makefile b/groovy/Makefile index 3dc35416b6..ff0b0d6a32 100644 --- a/groovy/Makefile +++ b/groovy/Makefile @@ -6,10 +6,12 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: ${CLASSES} -step1_read_print.groovy: types.class reader.class printer.class -step2_eval.groovy: types.class reader.class printer.class -step3_env.groovy: types.class reader.class printer.class env.class -step4_if_fn_do.groovy step6_file.groovy step7_quote.groovy step8_macros.groovy step9_try.groovy stepA_mal.groovy: ${CLASSES} +dist: mal.jar + +step1_read_print.class: types.class reader.class printer.class +step2_eval.class: types.class reader.class printer.class +step3_env.class: types.class reader.class printer.class env.class +step4_if_fn_do.class step6_file.class step7_quote.class step8_macros.class step9_try.class stepA_mal.class: ${CLASSES} types.class: types.groovy groovyc $< @@ -26,8 +28,18 @@ printer.class: printer.groovy core.class: core.groovy types.class reader.class printer.class groovyc $< +mal.jar: ${CLASSES} + groovyc stepA_mal.groovy + GROOVY_HOME=/usr/share/groovy groovy GroovyWrapper -d $@ -m stepA_mal + +SHELL := bash +mal: mal.jar + cat <(echo -e '#!/bin/sh\nexec java -jar "$$0" "$$@"') mal.jar > $@ + chmod +x mal + clean: - rm -f *.class + rm -f *.class classes/* mal.jar mal + rmdir classes || true .PHONY: stats tests diff --git a/guile/Makefile b/guile/Makefile index 8695474aab..e7e6f345a7 100644 --- a/guile/Makefile +++ b/guile/Makefile @@ -1,8 +1,20 @@ -SOURCES_BASE = types.scm reader.scm printer.scm +SOURCES_BASE = readline.scm types.scm reader.scm printer.scm SOURCES_LISP = env.scm core.scm stepA_mal.scm SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: + true + +dist: mal.scm + +mal.scm: $(SOURCES) + echo "#! /usr/bin/env guile" > $@ + echo "!#" >> $@ + cat $+ | sed $(foreach f,$(+),-e 's/(readline)//') >> $@ + chmod +x $@ + +clean: + rm -f mal.scm .PHONY: stats diff --git a/haxe/Makefile b/haxe/Makefile index 3257734684..30ad30088e 100644 --- a/haxe/Makefile +++ b/haxe/Makefile @@ -1,11 +1,18 @@ STEP1_DEPS = Compat.hx types/Types.hx reader/Reader.hx printer/Printer.hx STEP3_DEPS = $(STEP1_DEPS) env/Env.hx STEP4_DEPS = $(STEP3_DEPS) core/Core.hx +SOURCES = $(STEP4_DEPS) StepA_mal.hx +SOURCES_LISP = env/Env.hx core/Core.hx StepA_mal.hx STEPS = step0_repl step1_read_print step2_eval step3_env \ step4_if_fn_do step5_tco step6_file step7_quote \ step8_macros step9_try stepA_mal +HAXE_DIST_MODE = neko +dist_neko = mal.n +dist_python = mal.py +dist_cpp = cpp/mal + all: all-neko all-python all-cpp all-js all-neko: $(foreach x,$(STEPS),$(x).n) @@ -16,7 +23,7 @@ all-cpp: $(foreach x,$(STEPS),cpp/$(x)) all-js: $(foreach x,$(STEPS),$(x).js) -dist: mal.n mal.py cpp/mal mal.js +dist: mal.n mal.py cpp/mal mal.js mal mal.n: stepA_mal.n cp $< $@ @@ -31,6 +38,21 @@ mal.js: stepA_mal.js cp $< $@ +mal: $(dist_$(HAXE_DIST_MODE)) + $(if $(filter cpp,$(HAXE_DIST_MODE)),\ + cp $< $@;,\ + $(if $(filter neko,$(HAXE_DIST_MODE)),\ + nekotools boot $<;,\ + $(if $(filter js,$(HAXE_DIST_MODE)),\ + echo "#!/usr/bin/env node" > $@;\ + cat $< >> $@;,\ + $(if $(filter python,$(HAXE_DIST_MODE)),\ + echo "#!/usr/bin/env python3" > $@;\ + cat $< >> $@;,\ + $(error Invalid HAXE_DIST_MODE: $(HAXE_DIST_MODE)))))) + chmod +x $@ + + # Neko target (neko) s%.n: S%.hx @@ -79,5 +101,16 @@ node_modules: ### clean: - rm -f mal.n mal.py cpp/mal mal.js - rm -r step*.py cpp/ step*.js step*.n + rm -f mal.n mal.py cpp/mal mal.js mal + rm -f step*.py step*.js step*.n + [ -e cpp/ ] && rm -r cpp/ || true + +.PHONY: stats tests $(TESTS) + +stats: $(SOURCES) + @wc $^ + @printf "%5s %5s %5s %s\n" `grep -E "^[[:space:]]*//|^[[:space:]]*$$" $^ | wc` "[comments/blanks]" +stats-lisp: $(SOURCES_LISP) + @wc $^ + @printf "%5s %5s %5s %s\n" `grep -E "^[[:space:]]*//|^[[:space:]]*$$" $^ | wc` "[comments/blanks]" + diff --git a/java/Makefile b/java/Makefile index f5e28fe05c..b1fdb4ef94 100644 --- a/java/Makefile +++ b/java/Makefile @@ -11,12 +11,17 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: mvn install -dist: mal.jar +dist: mal.jar mal mal.jar: target/classes/mal/stepA_mal.class mvn assembly:assembly cp target/mal-0.0.1.jar $@ +SHELL := bash +mal: mal.jar + cat <(echo -e '#!/bin/sh\nexec java -jar "$$0" "$$@"') mal.jar > $@ + chmod +x mal + src/main/mal/%.java: mvn install @@ -25,7 +30,7 @@ target/classes/mal/step%.class: src/main/mal/step%.java ${SOURCES} clean: mvn clean - rm -f mal.jar + rm -f mal.jar mal #.PHONY: stats tests $(TESTS) .PHONY: stats diff --git a/js/Makefile b/js/Makefile index 175e7179ea..72e71348e4 100644 --- a/js/Makefile +++ b/js/Makefile @@ -8,14 +8,17 @@ WEB_SOURCES = $(SOURCES:node_readline.js=jq_readline.js) all: node_modules -dist: mal.js web/mal.js +dist: mal.js mal web/mal.js node_modules: npm install mal.js: $(SOURCES) - echo "#!/usr/bin/env node" > $@ cat $+ | grep -v "= *require('./" >> $@ + +mal: mal.js + echo "#!/usr/bin/env node" > $@ + cat $< >> $@ chmod +x $@ web/mal.js: $(WEB_SOURCES) diff --git a/kotlin/Makefile b/kotlin/Makefile index 8ab4903786..8e729689cc 100644 --- a/kotlin/Makefile +++ b/kotlin/Makefile @@ -7,13 +7,18 @@ JARS = $(SOURCES_LISP:%.kt=%.jar) all: $(JARS) -dist: mal.jar +dist: mal.jar mal mal.jar: stepA_mal.jar cp $< $@ +SHELL := bash +mal: mal.jar + cat <(echo -e '#!/bin/sh\nexec java -jar "$$0" "$$@"') mal.jar > $@ + chmod +x mal + clean: - rm -vf $(JARS) mal.jar + rm -vf $(JARS) mal.jar mal $(JARS): %.jar: src/mal/%.kt $(SOURCES_BASE:%.kt=src/mal/%.kt) kotlinc src/mal/$(@:%.jar=%.kt) $(SOURCES_BASE:%.kt=src/mal/%.kt) -include-runtime -d $@ diff --git a/lua/Makefile b/lua/Makefile index ec48fc9fc0..042e3b0cde 100644 --- a/lua/Makefile +++ b/lua/Makefile @@ -6,23 +6,26 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: libs -dist: mal.lua +dist: mal.lua mal SOURCE_NAMES = $(patsubst %.lua,%,$(SOURCES)) mal.lua: $(SOURCES) - echo "#!/usr/bin/env lua" > $@ - echo "local $(foreach n,$(SOURCE_NAMES),$(n),) M" >> $@ + echo "local $(foreach n,$(SOURCE_NAMES),$(n),) M" > $@ echo "M={} $(foreach n,$(SOURCE_NAMES),$(n)=M);" >> $@ cat $+ | grep -v -e "return M$$" \ -e "return Env" \ -e "local M =" \ -e "^#!" \ $(foreach n,$(SOURCE_NAMES),-e "require('$(n)')") >> $@ + +mal: mal.lua + echo "#!/usr/bin/env lua" > $@ + cat $< >> $@ chmod +x $@ clean: - rm -f linenoise.so mal.lua + rm -f linenoise.so mal.lua mal rm -rf lib/lua/5.1 .PHONY: stats tests $(TESTS) diff --git a/make/Makefile b/make/Makefile index 2270cacd20..913ae19dd1 100644 --- a/make/Makefile +++ b/make/Makefile @@ -9,15 +9,18 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: true -dist: mal.mk +dist: mal.mk mal mal.mk: $(SOURCES) + cat $+ | grep -v "^include " > $@ + +mal: mal.mk echo "#!/usr/bin/make -f" > $@ - cat $+ | grep -v "^include " >> $@ + cat $< >> $@ chmod +x $@ clean: - rm -f mal.mk + rm -f mal.mk mal .PHONY: stats tests $(TESTS) diff --git a/mal/Makefile b/mal/Makefile index 6390d18bcf..322c9cad5c 100644 --- a/mal/Makefile +++ b/mal/Makefile @@ -10,6 +10,9 @@ all: mal.mal mal.mal: stepA_mal.mal cp $< $@ +clean: + rm -f mal.mal + #.PHONY: stats tests $(TESTS) .PHONY: stats diff --git a/miniMAL/Makefile b/miniMAL/Makefile index c5751f0b8c..82e7f6e32f 100644 --- a/miniMAL/Makefile +++ b/miniMAL/Makefile @@ -9,6 +9,22 @@ all: node_modules node_modules: npm install +dist: mal.json mal + +mal.json: $(filter-out %.js,$(SOURCES)) + echo '["do",' >> $@ + $(foreach f,$+,\ + cat $(f) | egrep -v '^ *[[]"load-file"' >> $@; \ + echo "," >> $@;) + echo 'null]' >> $@ + +mal: mal.json + echo '#!/usr/bin/env miniMAL' > $@ + cat $< >> $@ + chmod +x $@ + +clean: + .PHONY: stats tests $(TESTS) stats: $(SOURCES) diff --git a/perl/Makefile b/perl/Makefile index 3774919734..63bbadd7ef 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -7,14 +7,24 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: -dist: mal.pl +dist: mal.pl mal mal.pl: $(SOURCES) + #fatpack pack ./stepA_mal.pl > $@ + fatpack trace ./stepA_mal.pl + fatpack packlists-for `cat fatpacker.trace` > packlists + fatpack tree `cat packlists` + cp $+ fatlib/ + (fatpack file; cat ./stepA_mal.pl) > mal.pl + +mal: mal.pl echo "#!/usr/bin/env perl" > $@ - fatpack pack stepA_mal.pl >> $@ + cat $< >> $@ + chmod +x $@ clean: - rm -f mal.pl + rm -f mal.pl mal fatpacker.trace packlists fatlib/* + rmdir fatlib .PHONY: stats tests $(TESTS) diff --git a/php/Makefile b/php/Makefile index bea654cd98..35f585458e 100644 --- a/php/Makefile +++ b/php/Makefile @@ -7,15 +7,18 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: -dist: mal.php +dist: mal.php mal mal.php: $(SOURCES) + cat $+ | grep -v "^require_once" > $@ + +mal: mal.php echo "#!/usr/bin/env php" > $@ - cat $+ | grep -v "^require_once" >> $@ + cat $< >> $@ chmod +x $@ clean: - rm mal.php + rm -f mal.php mal .PHONY: stats tests $(TESTS) diff --git a/ps/Makefile b/ps/Makefile index 39f7a09f34..67741380c3 100644 --- a/ps/Makefile +++ b/ps/Makefile @@ -8,16 +8,19 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: true -dist: mal.ps +dist: mal.ps mal mal.ps: $(SOURCES) + cat $+ | grep -v "runlibfile$$" > $@ + +mal: mal.ps echo "#!/bin/sh" > $@ echo "\":\" pop pop pop pop %#; exec gs -d'#!'=null -d'\":\"'=null -q -dNODISPLAY -- \"\$$0\" \"\$$@\"" >> $@ - cat $+ | grep -v "runlibfile$$" >> $@ + cat $< >> $@ chmod +x $@ clean: - rm -f mal.ps + rm -f mal.ps mal .PHONY: stats tests $(TESTS) diff --git a/python/Dockerfile b/python/Dockerfile index 65ada903c0..3e64cc116c 100644 --- a/python/Dockerfile +++ b/python/Dockerfile @@ -23,3 +23,6 @@ WORKDIR /mal # Nothing additional needed for python RUN apt-get -y install python3 + +# For dist packaging +RUN apt-get -y install zip diff --git a/python/Makefile b/python/Makefile index 592a7ca4b0..c16b83ffe9 100644 --- a/python/Makefile +++ b/python/Makefile @@ -9,17 +9,21 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: true -dist: mal.pyz +dist: mal.pyz mal SHELL := bash mal.pyz: $(SOURCES) cp stepA_mal.py __main__.py - cat <(echo '#!/usr/bin/env python') <(zip -q - __main__.py $+) > $@ + zip -q - __main__.py $+ > $@ rm __main__.py + +mal: mal.pyz + echo '#!/usr/bin/env python' > $@ + cat $< >> $@ chmod +x $@ clean: - rm -f mal.pyz + rm -f mal.pyz mal .PHONY: stats tests $(TESTS) diff --git a/r/Makefile b/r/Makefile index c1caebf7e5..85e3247fac 100644 --- a/r/Makefile +++ b/r/Makefile @@ -6,15 +6,18 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: libs -dist: mal.r +dist: mal.r mal mal.r: $(SOURCES) + cat $+ | grep -v " source(" > $@ + +mal: mal.r echo "#!/usr/bin/env Rscript" > $@ - cat $+ | grep -v " source(" >> $@ + cat $< >> $@ chmod +x $@ clean: - rm -f mal.r + rm -f mal.r mal .PHONY: stats tests $(TESTS) diff --git a/racket/Makefile b/racket/Makefile index 3d55efe430..17b07dcd28 100644 --- a/racket/Makefile +++ b/racket/Makefile @@ -11,7 +11,7 @@ mal: $(SOURCES) mv stepA_mal $@ clean: - mal + rm -f mal .PHONY: stats diff --git a/racket/stepA_mal.rkt b/racket/stepA_mal.rkt index f7b0f54b9b..1c39b00beb 100755 --- a/racket/stepA_mal.rkt +++ b/racket/stepA_mal.rkt @@ -159,7 +159,9 @@ (repl-loop)))) (let ([args (current-command-line-arguments)]) (if (> (vector-length args) 0) - (for () (rep (string-append "(load-file \"" (vector-ref args 0) "\")"))) + (begin + (send repl-env set '*ARGV* (vector->list (vector-drop args 1))) + (for () (rep (string-append "(load-file \"" (vector-ref args 0) "\")")))) (begin (rep "(println (str \"Mal [\" *host-language* \"]\"))") (repl-loop)))) diff --git a/ruby/Makefile b/ruby/Makefile index f43de1c86f..c677e1a237 100644 --- a/ruby/Makefile +++ b/ruby/Makefile @@ -7,15 +7,18 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: true -dist: mal.rb +dist: mal.rb mal mal.rb: $(SOURCES) + cat $+ | grep -v "^require_relative" > $@ + +mal: mal.rb echo "#!/usr/bin/env ruby" > $@ - cat $+ | grep -v "^require_relative" >> $@ + cat $< >> $@ chmod +x $@ clean: - rm -f mal.rb + rm -f mal.rb mal .PHONY: stats tests $(TESTS) diff --git a/scala/Makefile b/scala/Makefile index b98922b8dd..e4231fa57f 100644 --- a/scala/Makefile +++ b/scala/Makefile @@ -9,14 +9,20 @@ all: build build: sbt 'run-main stepA_mal ../tests/incA.mal' -dist: mal.jar +dist: mal.jar mal mal.jar: $(SOURCES) sbt assembly cp target/scala-*/mal-assembly*.jar $@ +SHELL := bash +mal: mal.jar + cat <(echo -e '#!/bin/sh\nexec java -jar "$$0" "$$@"') mal.jar > $@ + chmod +x mal + + clean: - rm -f mal.jar + rm -f mal.jar mal .PHONY: stats tests $(TESTS) diff --git a/tcl/Makefile b/tcl/Makefile index 0e5396dbff..5105437e71 100644 --- a/tcl/Makefile +++ b/tcl/Makefile @@ -7,15 +7,18 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: true -dist: mal.tcl +dist: mal.tcl mal mal.tcl: $(SOURCES) + cat $+ | grep -v "^source " > $@ + +mal: mal.tcl echo "#!/usr/bin/env tclsh" > $@ - cat $+ | grep -v "^source " >> $@ + cat $< >> $@ chmod +x $@ clean: - rm -f mal.tcl + rm -f mal.tcl mal stats: $(SOURCES) diff --git a/vb/Dockerfile b/vb/Dockerfile index 138d19a2c9..f5f133484d 100644 --- a/vb/Dockerfile +++ b/vb/Dockerfile @@ -22,4 +22,4 @@ WORKDIR /mal ########################################################## # Deps for Mono-based languages (C#, VB.Net) -RUN apt-get -y install mono-runtime mono-mcs mono-vbnc +RUN apt-get -y install mono-runtime mono-mcs mono-vbnc mono-devel diff --git a/vimscript/Makefile b/vimscript/Makefile index dfb12715dc..0be665cfbe 100644 --- a/vimscript/Makefile +++ b/vimscript/Makefile @@ -4,14 +4,17 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: libvimreadline.so -dist: mal.vim +dist: mal.vim mal mal.vim: $(SOURCES) + cat $+ | grep -v "^source " > $@ + +mal: mal.vim echo "#!/bin/sh" > $@ echo "\":\" ; rundir=\`dirname \$$0\`" >> $@ echo "\":\" ; export LD_LIBRARY_PATH=\`readlink -f \$$rundir\`" >> $@ - echo "\":\" ; exec vim -i NONE -V1 -nNesS \"\$$0\" -- \"\$$@\"" >> $@ - cat $+ | grep -v "^source " >> $@ + echo "\":\" ; exec vim -i NONE -V1 -nNesS \"\$$0\" -- \"\$$@\" 2>/dev/null" >> $@ + cat $< >> $@ chmod +x $@ @@ -22,7 +25,7 @@ vimreadline.o: vimreadline.c $(CC) -g -fPIC -c $< -o $@ clean: - rm -f vimreadline.o libvimreadline.so mal.vim + rm -f vimreadline.o libvimreadline.so mal.vim mal stats: $(SOURCES) @wc $^ From 6fc6e971d20ca549daceb6738788dc4537127a90 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Wed, 24 Feb 2016 00:47:16 -0600 Subject: [PATCH 08/14] swift3: add missed updates to core/types --- swift3/Sources/core.swift | 284 ++++++++++++++++++++++++++++++++++++- swift3/Sources/types.swift | 92 +++++++++++- 2 files changed, 369 insertions(+), 7 deletions(-) diff --git a/swift3/Sources/core.swift b/swift3/Sources/core.swift index 93384e98aa..4d6a0db2c8 100644 --- a/swift3/Sources/core.swift +++ b/swift3/Sources/core.swift @@ -22,6 +22,54 @@ func CmpOp(op: (Int, Int) -> Bool, _ a: MalVal, _ b: MalVal) throws -> MalVal { let core_ns: Dictionary) throws -> MalVal> = [ "=": { wraptf(equal_Q($0[0], $0[1])) }, + "throw": { throw MalError.MalException(obj: $0[0]) }, + + "nil?": { + switch $0[0] { + case MV.MalNil(_): return MV.MalTrue + default: return MV.MalFalse + } + }, + "true?": { + switch $0[0] { + case MV.MalTrue(_): return MV.MalTrue + default: return MV.MalFalse + } + }, + "false?": { + switch $0[0] { + case MV.MalFalse(_): return MV.MalTrue + default: return MV.MalFalse + } + }, + "symbol": { + switch $0[0] { + case MV.MalSymbol(_): return $0[0] + case MV.MalString(let s): return MV.MalSymbol(s) + default: throw MalError.General(msg: "Invalid symbol call") + } + }, + "symbol?": { + switch $0[0] { + case MV.MalSymbol(_): return MV.MalTrue + default: return MV.MalFalse + } + }, + "keyword": { + switch $0[0] { + case MV.MalString(let s) where s.characters.count > 0: + if s[s.startIndex] == "\u{029e}" { return $0[0] } + else { return MV.MalString("\u{029e}\(s)") } + default: throw MalError.General(msg: "Invalid symbol call") + } + }, + "keyword?": { + switch $0[0] { + case MV.MalString(let s) where s.characters.count > 0: + return wraptf(s[s.startIndex] == "\u{029e}") + default: return MV.MalFalse + } + }, "pr-str": { return MV.MalString($0.map { pr_str($0,true) }.joinWithSeparator(" ")) @@ -43,6 +91,16 @@ let core_ns: Dictionary) throws -> MalVal> = [ default: throw MalError.General(msg: "Invalid read-string call") } }, + "readline": { + switch $0[0] { + case MV.MalString(let prompt): + print(prompt, terminator: "") + let line = readLine(stripNewline: true) + if line == nil { return MalVal.MalNil } + return MalVal.MalString(line!) + default: throw MalError.General(msg: "Invalid readline call") + } + }, "slurp": { switch $0[0] { case MV.MalString(let file): @@ -53,11 +111,11 @@ let core_ns: Dictionary) throws -> MalVal> = [ var pp = popen("cat " + file, "r") var buf = [CChar](count:BUFSIZE, repeatedValue:CChar(0)) var data = String() - + while fgets(&buf, Int32(BUFSIZE), pp) != nil { data = data + String.fromCString(buf)!; } - return MalVal.MalString(data) + return MV.MalString(data) default: throw MalError.General(msg: "Invalid slurp call") } }, @@ -71,6 +129,7 @@ let core_ns: Dictionary) throws -> MalVal> = [ "-": { try IntOp({ $0 - $1}, $0[0], $0[1]) }, "*": { try IntOp({ $0 * $1}, $0[0], $0[1]) }, "/": { try IntOp({ $0 / $1}, $0[0], $0[1]) }, + "time-ms": { $0; return MV.MalInt(0) }, // TODO "list": { MV.MalList($0) }, "list?": { @@ -79,11 +138,139 @@ let core_ns: Dictionary) throws -> MalVal> = [ default: return MV.MalFalse } }, + "vector": { MV.MalVector($0) }, + "vector?": { + switch $0[0] { + case MV.MalVector(_): return MV.MalTrue + default: return MV.MalFalse + } + }, + "hash-map": { try hash_map($0) }, + "map?": { + switch $0[0] { + case MV.MalHashMap(_): return MV.MalTrue + default: return MV.MalFalse + } + }, + "assoc": { + switch $0[0] { + case MV.MalHashMap(let dict): + return MV.MalHashMap(try _assoc(dict, Array($0[1..<$0.endIndex]))) + default: throw MalError.General(msg: "Invalid assoc call") + } + }, + "dissoc": { + switch $0[0] { + case MV.MalHashMap(let dict): + return MV.MalHashMap(try _dissoc(dict, Array($0[1..<$0.endIndex]))) + default: throw MalError.General(msg: "Invalid dissoc call") + } + }, + "get": { + switch ($0[0], $0[1]) { + case (MV.MalHashMap(let dict), MV.MalString(let k)): + return dict[k] ?? MV.MalNil + case (MV.MalNil, MV.MalString(let k)): + return MV.MalNil + default: throw MalError.General(msg: "Invalid get call") + } + }, + "contains?": { + switch ($0[0], $0[1]) { + case (MV.MalHashMap(let dict), MV.MalString(let k)): + return dict[k] != nil ? MV.MalTrue : MV.MalFalse + case (MV.MalNil, MV.MalString(let k)): + return MV.MalFalse + default: throw MalError.General(msg: "Invalid contains? call") + } + }, + "keys": { + switch $0[0] { + case MV.MalHashMap(let dict): + return MV.MalList(dict.keys.map { MV.MalString($0) }) + default: throw MalError.General(msg: "Invalid keys call") + } + }, + "vals": { + switch $0[0] { + case MV.MalHashMap(let dict): + return MV.MalList(dict.values.map { $0 }) + default: throw MalError.General(msg: "Invalid vals call") + } + }, + + "sequential?": { + switch $0[0] { + case MV.MalList(_): return MV.MalTrue + case MV.MalVector(_): return MV.MalTrue + default: return MV.MalFalse + } + }, + "cons": { + if $0.count != 2 { throw MalError.General(msg: "Invalid cons call") } + switch ($0[0], $0[1]) { + case (let mv, MV.MalList(let lst)): + return MV.MalList([mv] + lst) + case (let mv, MV.MalVector(let lst)): + return MV.MalList([mv] + lst) + default: throw MalError.General(msg: "Invalid cons call") + } + }, + "concat": { + var res = Array() + for seq in $0 { + switch seq { + case MV.MalList(let lst): res = res + lst + case MV.MalVector(let lst): res = res + lst + default: throw MalError.General(msg: "Invalid concat call") + } + } + return MV.MalList(res) + }, + "nth": { + if $0.count != 2 { throw MalError.General(msg: "Invalid nth call") } + switch ($0[0], $0[1]) { + case (MV.MalList(let lst), MV.MalInt(let idx)): + if idx >= lst.count { + throw MalError.General(msg: "nth: index out of range") + } + return try _nth($0[0], idx) + case (MV.MalVector(let lst), MV.MalInt(let idx)): + if idx >= lst.count { + throw MalError.General(msg: "nth: index out of range") + } + return try _nth($0[0], idx) + default: + throw MalError.General(msg: "Invalid nth call") + } + }, + "first": { + switch $0[0] { + case MV.MalList(let lst): + return lst.count > 0 ? lst[0] : MalVal.MalNil + case MV.MalVector(let lst): + return lst.count > 0 ? lst[0] : MalVal.MalNil + case MV.MalNil: return MalVal.MalNil + default: throw MalError.General(msg: "Invalid first call") + } + }, + "rest": { + switch $0[0] { + case MV.MalList(let lst): + return lst.count > 0 ? try rest($0[0]) : MalVal.MalList([]) + case MV.MalVector(let lst): + return lst.count > 0 ? try rest($0[0]) : MalVal.MalList([]) + case MV.MalNil: return MalVal.MalList([]) + default: throw MalError.General(msg: "Invalid rest call") + } + }, "empty?": { switch $0[0] { case MV.MalList(let lst): return lst.count == 0 ? MV.MalTrue : MV.MalFalse + case MV.MalVector(let lst): + return lst.count == 0 ? MV.MalTrue : MV.MalFalse case MV.MalNil: return MV.MalTrue default: throw MalError.General(msg: "Invalid empty? call") } @@ -91,8 +278,99 @@ let core_ns: Dictionary) throws -> MalVal> = [ "count": { switch $0[0] { case MV.MalList(let lst): return MV.MalInt(lst.count) + case MV.MalVector(let lst): return MV.MalInt(lst.count) case MV.MalNil: return MV.MalInt(0) default: throw MalError.General(msg: "Invalid count call") } - } + }, + "apply": { + let fn: (Array) throws -> MalVal + switch $0[0] { + case MV.MalFunc(let f, _, _, _, _, _): fn = f + default: throw MalError.General(msg: "Invalid apply call") + } + + var args = Array($0[1..<$0.endIndex-1]) + switch $0[$0.endIndex-1] { + case MV.MalList(let l): args = args + l + case MV.MalVector(let l): args = args + l + default: throw MalError.General(msg: "Invalid apply call") + } + + return try fn(args) + }, + "map": { + let fn: (Array) throws -> MalVal + switch $0[0] { + case MV.MalFunc(let f, _, _, _, _, _): fn = f + default: throw MalError.General(msg: "Invalid map call") + } + + var lst = Array() + switch $0[1] { + case MV.MalList(let l): lst = l + case MV.MalVector(let l): lst = l + default: throw MalError.General(msg: "Invalid map call") + } + + var res = Array() + for mv in lst { + res.append(try fn([mv])) + } + return MalVal.MalList(res) + }, + + "conj": { + return $0[0] + }, + + "meta": { + switch $0[0] { + case MV.MalFunc(_, _, _, _, _, let m): + return m != nil ? m![0] : MalVal.MalNil + default: throw MalError.General(msg: "meta called on non-function") + } + }, + "with-meta": { + switch $0[0] { + case MV.MalFunc(let f, let a, let e, let p, let m, _): + return MV.MalFunc(f,ast:a,env:e,params:p,macro:m,meta:[$0[1]]) + default: throw MalError.General(msg: "with-meta called on non-function") + } + }, + "atom": { + return MV.MalAtom(MutableAtom(val: $0[0])) + }, + "atom?": { + switch $0[0] { + case MV.MalAtom(_): return MV.MalTrue + default: return MV.MalFalse + } + }, + "deref": { + switch $0[0] { + case MV.MalAtom(let ma): return ma.val + default: throw MalError.General(msg: "Invalid deref call") + } + }, + "reset!": { + switch $0[0] { + case MV.MalAtom(var a): + a.val = $0[1] + return $0[1] + default: throw MalError.General(msg: "Invalid reset! call") + } + }, + "swap!": { + switch ($0[0], $0[1]) { + case (MV.MalAtom(var a), MV.MalFunc(let fn, _, _, _, _, _)): + var args = [a.val] + if $0.count > 2 { + args = args + Array($0[2..<$0.endIndex]) + } + a.val = try fn(args) + return a.val + default: throw MalError.General(msg: "Invalid swap! call") + } + }, ] diff --git a/swift3/Sources/types.swift b/swift3/Sources/types.swift index 9cdb849f57..70544506fb 100644 --- a/swift3/Sources/types.swift +++ b/swift3/Sources/types.swift @@ -2,6 +2,14 @@ enum MalError: ErrorType { case Reader(msg: String) case General(msg: String) + case MalException(obj: MalVal) +} + +class MutableAtom { + var val: MalVal + init(val: MalVal) { + self.val = val + } } enum MalVal { @@ -14,10 +22,16 @@ enum MalVal { case MalSymbol(String) case MalList(Array) case MalVector(Array) - // TODO: ast and params wrapped in arrays because otherwise + case MalHashMap(Dictionary) + // TODO: internal MalVals are wrapped in arrays because otherwise // compiler throws a fault case MalFunc((Array) throws -> MalVal, - ast: Array?, env: Env?, params: Array?) + ast: Array?, + env: Env?, + params: Array?, + macro: Bool, + meta: Array?) + case MalAtom(MutableAtom) } typealias MV = MalVal @@ -28,6 +42,8 @@ func wraptf(a: Bool) -> MalVal { return a ? MV.MalTrue : MV.MalFalse } + +// equality functions func cmp_seqs(a: Array, _ b: Array) -> Bool { if a.count != b.count { return false } var idx = a.startIndex @@ -38,6 +54,16 @@ func cmp_seqs(a: Array, _ b: Array) -> Bool { return true } +func cmp_maps(a: Dictionary, + _ b: Dictionary) -> Bool { + if a.count != b.count { return false } + for (k,v1) in a { + if b[k] == nil { return false } + if !equal_Q(v1, b[k]!) { return false } + } + return true +} + func equal_Q(a: MalVal, _ b: MalVal) -> Bool { switch (a, b) { case (MV.MalNil, MV.MalNil): return true @@ -54,17 +80,75 @@ func equal_Q(a: MalVal, _ b: MalVal) -> Bool { return cmp_seqs(l1, l2) case (MV.MalVector(let l1), MV.MalVector(let l2)): return cmp_seqs(l1, l2) + case (MV.MalHashMap(let d1), MV.MalHashMap(let d2)): + return cmp_maps(d1, d2) default: return false } } -func rest(a: MalVal) throws -> MalVal { +// hash-map functions + +func _assoc(src: Dictionary, _ mvs: Array) + throws -> Dictionary { + var d = src + if mvs.count % 2 != 0 { + throw MalError.General(msg: "Odd number of args to assoc_BANG") + } + var pos = mvs.startIndex + while pos < mvs.count { + switch (mvs[pos], mvs[pos+1]) { + case (MV.MalString(let k), let mv): + d[k] = mv + default: + throw MalError.General(msg: "Invalid _assoc call") + } + pos += 2 + } + return d +} + +func _dissoc(src: Dictionary, _ mvs: Array) + throws -> Dictionary { + var d = src + for mv in mvs { + switch mv { + case MV.MalString(let k): d.removeValueForKey(k) + default: throw MalError.General(msg: "Invalid _dissoc call") + } + } + return d +} + + +func hash_map(arr: Array) throws -> MalVal { + let d = Dictionary(); + return MV.MalHashMap(try _assoc(d, arr)) +} + +// sequence functions + +func _rest(a: MalVal) throws -> Array { switch a { case MV.MalList(let lst): let slc = lst[lst.startIndex.successor().. MalVal { + return MV.MalList(try _rest(a)) +} + +func _nth(a: MalVal, _ idx: Int) throws -> MalVal { + switch a { + case MV.MalList(let l): return l[l.startIndex.advancedBy(idx)] + case MV.MalVector(let l): return l[l.startIndex.advancedBy(idx)] + default: throw MalError.General(msg: "Invalid nth call") + } +} From d5ccbd997553ea12aaf4920d245b51869eecde1a Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Wed, 24 Feb 2016 00:47:37 -0600 Subject: [PATCH 09/14] swift3: dist rule --- swift3/Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/swift3/Makefile b/swift3/Makefile index c4e2deeeb9..f030f32f3b 100644 --- a/swift3/Makefile +++ b/swift3/Makefile @@ -10,6 +10,11 @@ STEPS = step0_repl step1_read_print step2_eval step3_env \ all: $(STEPS) +dist: mal + +mal: stepA_mal + cp $< $@ + step1_read_print step2_eval step3_env: $(STEP3_DEPS) step4_if_fn_do step5_tco step6_file step7_quote step8_macros step9_try stepA_mal: $(STEP4_DEPS) @@ -17,7 +22,7 @@ step%: Sources/step%/main.swift swiftc $+ -o $@ clean: - rm -f $(STEPS) + rm -f $(STEPS) mal .PHONY: stats tests From bcfd8b70206cefc420d9e62b0ca6320488dcb2a0 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Wed, 24 Feb 2016 01:05:44 -0600 Subject: [PATCH 10/14] Generic recursive rules for dist, stats, clean Also add missing clean rules for julia and matlab and fix perl clean rule. --- Makefile | 41 +++++++++++++++++++++++++++++++---------- julia/Makefile | 2 ++ matlab/Makefile | 2 ++ perl/Makefile | 2 +- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index cf6958a08d..801222f77a 100644 --- a/Makefile +++ b/Makefile @@ -57,18 +57,19 @@ STEP5_EXCLUDES += awk # completes at 10,000 STEP5_EXCLUDES += bash # no stack exhaustion or completion STEP5_EXCLUDES += c # segfault STEP5_EXCLUDES += cpp # completes at 10,000 +STEP5_EXCLUDES += crystal # test completes, even at 1,000,000 STEP5_EXCLUDES += cs # fatal stack overflow fault STEP5_EXCLUDES += d # completes at 10,000, fatal stack overflow at 1,000,000 STEP5_EXCLUDES += erlang # erlang is TCO, test passes STEP5_EXCLUDES += elixir # elixir is TCO, test passes STEP5_EXCLUDES += fsharp # completes at 10,000, fatal stack overflow at 100,000 +STEP5_EXCLUDES += go # test completes, even at 100,000 STEP5_EXCLUDES += haskell # test completes STEP5_EXCLUDES += make # no TCO capability/step STEP5_EXCLUDES += mal # no TCO capability/step STEP5_EXCLUDES += matlab # too slow to complete 10,000 STEP5_EXCLUDES += miniMAL # strange error with runtest.py STEP5_EXCLUDES += nim # test completes, even at 100,000 -STEP5_EXCLUDES += go # test completes, even at 100,000 STEP5_EXCLUDES += php # test completes, even at 100,000 STEP5_EXCLUDES += racket # test completes STEP5_EXCLUDES += ruby # test completes, even at 100,000 @@ -76,13 +77,12 @@ STEP5_EXCLUDES += rust # no catching stack overflows STEP5_EXCLUDES += swift3 # no catching stack overflows STEP5_EXCLUDES += ocaml # test completes, even at 1,000,000 STEP5_EXCLUDES += vb # completes at 10,000 -STEP5_EXCLUDES += crystal # test completes, even at 1,000,000 PERF_EXCLUDES = mal # TODO: fix this -DIST_EXCLUDES += mal +dist_EXCLUDES += mal # TODO: still need to implement dist -DIST_EXCLUDES += factor groovy guile io julia matlab miniMAL swift +dist_EXCLUDES += guile io julia matlab swift # # Utility functions @@ -234,12 +234,6 @@ ALL_TESTS = $(filter-out $(foreach impl,$(STEP5_EXCLUDES),test^$(impl)^step5),\ $(foreach impl,$(DO_IMPLS),\ $(foreach step,$(STEPS),test^$(impl)^$(step)))))) -IMPL_STATS = $(foreach impl,$(DO_IMPLS),stats^$(impl)) -IMPL_STATS_LISP = $(foreach impl,$(DO_IMPLS),stats-lisp^$(impl)) - -IMPL_DIST = $(filter-out $(foreach impl,$(DIST_EXCLUDES),dist^$(impl)),\ - $(foreach impl,$(DO_IMPLS),dist^$(impl))) - DOCKER_BUILD = $(foreach impl,$(DO_IMPLS),docker-build^$(impl)) IMPL_PERF = $(foreach impl,$(filter-out $(PERF_EXCLUDES),$(DO_IMPLS)),perf^$(impl)) @@ -355,3 +349,30 @@ $(ALL_REPL): $$(call $$(word 2,$$(subst ^, ,$$(@)))_STEP_TO_PROG,$$(word 3,$$(su echo 'REPL implementation $(impl), step file: $+'; \ echo 'Running: $(call $(impl)_RUNSTEP,$(step),$(+))'; \ $(call $(impl)_RUNSTEP,$(step),$(+));)) + + +# Recursive rules (call make FOO in each subdirectory) + +define recur_template +.PHONY: $(1) +$(1): $(2) +.SECONDEXPANSION: +$(2): + @echo "----------------------------------------------"; \ + $$(foreach impl,$$(word 2,$$(subst ^, ,$$(@))),\ + echo "Running: $$(MAKE) --no-print-directory -C $$(impl) $(1)"; \ + $$(MAKE) --no-print-directory -C $$(impl) $(1)) +endef + +recur_impls_ = $(filter-out $(foreach impl,$($(1)_EXCLUDES),$(1)^$(impl)),$(foreach impl,$(IMPLS),$(1)^$(impl))) + +# recursive clean +$(eval $(call recur_template,clean,$(call recur_impls_,clean))) + +# recursive stats +$(eval $(call recur_template,stats,$(call recur_impls_,stats))) +$(eval $(call recur_template,stats-lisp,$(call recur_impls_,stats-lisp))) + +# recursive dist +$(eval $(call recur_template,dist,$(call recur_impls_,dist))) + diff --git a/julia/Makefile b/julia/Makefile index fd75c7c855..21f501f230 100644 --- a/julia/Makefile +++ b/julia/Makefile @@ -5,6 +5,8 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: +clean: + .PHONY: stats tests $(TESTS) stats: $(SOURCES) diff --git a/matlab/Makefile b/matlab/Makefile index 671464bf7f..1363956831 100644 --- a/matlab/Makefile +++ b/matlab/Makefile @@ -7,6 +7,8 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) all: +clean: + .PHONY: stats tests $(TESTS) stats: $(SOURCES) diff --git a/perl/Makefile b/perl/Makefile index 63bbadd7ef..947edc46ef 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -24,7 +24,7 @@ mal: mal.pl clean: rm -f mal.pl mal fatpacker.trace packlists fatlib/* - rmdir fatlib + [ -d fatlib ] && rmdir fatlib || true .PHONY: stats tests $(TESTS) From ea1395aa6e6a18c0f460adfcc426b5c14e3d525f Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Wed, 24 Feb 2016 01:09:57 -0600 Subject: [PATCH 11/14] README.md: update with Swift 3 info --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7305978a1f..f5cb0780bd 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Mal is a Clojure inspired Lisp interpreter. -Mal is implemented in 45 different languages: +Mal is implemented in 46 languages: * GNU awk * Bash shell @@ -50,6 +50,7 @@ Mal is implemented in 45 different languages: * Rust * Scala * Swift +* Swift 3 * Tcl * Vimscript * Visual Basic.NET @@ -575,6 +576,18 @@ make ./stepX_YYY ``` +### Swift 3 + +The Swift 3 implementation of mal requires the Swift 3.0 compiler. It +has been tested with the development version of the Swift 3 from +2016-02-08. + +``` +cd swift3 +make +./stepX_YYY +``` + ### Tcl 8.6 *The Tcl implementation was created by [Dov Murik](https://github.com/dubek)* From 648fd4b304b64be8723dbcdeae279d6fd710e2c1 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Wed, 24 Feb 2016 01:12:24 -0600 Subject: [PATCH 12/14] Travis: add swift3 build. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 01217c556d..b1f1ced9c3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,6 +47,7 @@ matrix: - {env: IMPL=rust, services: [docker]} - {env: IMPL=scala, services: [docker]} - {env: IMPL=swift NO_DOCKER=1, os: osx, osx_image: xcode7} + - {env: IMPL=swift3, services: [docker]} - {env: IMPL=tcl, services: [docker]} - {env: IMPL=vb, services: [docker]} - {env: IMPL=vimscript, services: [docker]} From c07ccda22e0a995a22072a8e280d7740fed0c09f Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Wed, 24 Feb 2016 09:22:09 -0600 Subject: [PATCH 13/14] add swift3/Dockerfile --- swift3/Dockerfile | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 swift3/Dockerfile diff --git a/swift3/Dockerfile b/swift3/Dockerfile new file mode 100644 index 0000000000..cc70fb788c --- /dev/null +++ b/swift3/Dockerfile @@ -0,0 +1,50 @@ +FROM ubuntu:wily +MAINTAINER Joel Martin + +########################################################## +# General requirements for testing or common across many +# implementations +########################################################## + +RUN apt-get -y update + +# Required for running tests +RUN apt-get -y install make python + +# Some typical implementation and test requirements +RUN apt-get -y install curl libreadline-dev libedit-dev + +RUN mkdir -p /mal +WORKDIR /mal + +########################################################## +# Specific implementation requirements +########################################################## + +# Swift +RUN apt-get -y install clang-3.6 cmake pkg-config \ + git ninja-build uuid-dev libicu-dev icu-devtools \ + libbsd-dev libedit-dev libxml2-dev libsqlite3-dev \ + swig libpython-dev libncurses5-dev + +ENV SWIFT_PREFIX swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a +ENV SWIFT_RELEASE ${SWIFT_PREFIX}-ubuntu15.10 + +RUN cd /opt && \ + curl -O https://swift.org/builds/development/ubuntu1510/${SWIFT_PREFIX}/${SWIFT_RELEASE}.tar.gz && \ + tar xvzf ${SWIFT_RELEASE}.tar.gz && \ + rm ${SWIFT_RELEASE}.tar.gz + +# tar xvzf ${SWIFT_RELEASE}.tar.gz --directory / --strip-components 1 && \ +#RUN find /usr -type f | xargs -ifoo chmod go+r foo && \ +# find /usr -type d | xargs -ifoo chmod go+rx foo + +#RUN find /opt/${SWIFT_RELEASE}/ -type f | xargs -ifoo chmod go+r foo && \ +# find /opt/${SWIFT_RELEASE}/ -type d | xargs -ifoo chmod go+rx foo + +ENV PATH /opt/${SWIFT_RELEASE}/usr/bin/:$PATH + +# TODO: better way to do this? And move up. +RUN ln -sf /usr/lib/llvm-3.6/bin/clang++ /usr/bin/clang++ +RUN ln -sf /usr/lib/llvm-3.6/bin/clang /usr/bin/clang + From aebe1e8c41b359bf490395c85d1797258e7ad5ed Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Wed, 24 Feb 2016 11:59:18 -0600 Subject: [PATCH 14/14] swift3: add missing time-ms function --- swift3/Sources/core.swift | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/swift3/Sources/core.swift b/swift3/Sources/core.swift index 4d6a0db2c8..cf4f35b9fd 100644 --- a/swift3/Sources/core.swift +++ b/swift3/Sources/core.swift @@ -1,3 +1,4 @@ +// TODO: remove this once time-ms and slurp use standard library calls import Glibc func IntOp(op: (Int, Int) -> Int, _ a: MalVal, _ b: MalVal) throws -> MalVal { @@ -129,7 +130,16 @@ let core_ns: Dictionary) throws -> MalVal> = [ "-": { try IntOp({ $0 - $1}, $0[0], $0[1]) }, "*": { try IntOp({ $0 * $1}, $0[0], $0[1]) }, "/": { try IntOp({ $0 / $1}, $0[0], $0[1]) }, - "time-ms": { $0; return MV.MalInt(0) }, // TODO + "time-ms": { + $0; // no parameters + + // TODO: replace with something more like this + // return MV.MalInt(NSDate().timeIntervalSince1970 ) + + var tv:timeval = timeval(tv_sec: 0, tv_usec: 0) + gettimeofday(&tv, nil) + return MV.MalInt(tv.tv_sec * 1000 + Int(tv.tv_usec)/1000) + }, "list": { MV.MalList($0) }, "list?": {