1
1
mirror of https://github.com/kanaka/mal.git synced 2024-10-27 14:52:16 +03:00
mal/impls/skew/step3_env.sk
Joel Martin 8a19f60386 Move implementations into impls/ dir
- Reorder README to have implementation list after "learning tool"
  bullet.

- This also moves tests/ and libs/ into impls. It would be preferrable
  to have these directories at the top level.  However, this causes
  difficulties with the wasm implementations which need pre-open
  directories and have trouble with paths starting with "../../". So
  in lieu of that, symlink those directories to the top-level.

- Move the run_argv_test.sh script into the tests directory for
  general hygiene.
2020-02-10 23:50:16 -06:00

73 lines
2.4 KiB
Plaintext

def READ(str string) MalVal {
return read_str(str)
}
def eval_ast(ast MalVal, env Env) MalVal {
if ast is MalSymbol {
return env.get(ast as MalSymbol)
} else if ast is MalList {
return MalList.new((ast as MalList).val.map<MalVal>(e => EVAL(e, env)))
} else if ast is MalVector {
return MalVector.new((ast as MalVector).val.map<MalVal>(e => EVAL(e, env)))
} else if ast is MalHashMap {
var result List<MalVal> = []
(ast as MalHashMap).val.each((k string, v MalVal) => {
result.append(EVAL(MalVal.fromHashKey(k), env))
result.append(EVAL(v, env))
})
return MalHashMap.fromList(result)
} else {
return ast
}
}
def EVAL(ast MalVal, env Env) MalVal {
if !(ast is MalList) { return eval_ast(ast, env) }
const astList = ast as MalList
if astList.isEmpty { return ast }
const a0sym = astList[0] as MalSymbol
if a0sym.val == "def!" {
return env.set(astList[1] as MalSymbol, EVAL(astList[2], env))
} else if a0sym.val == "let*" {
var letenv = Env.new(env)
const assigns = astList[1] as MalSequential
for i = 0; i < assigns.count; i += 2 {
letenv.set(assigns[i] as MalSymbol, EVAL(assigns[i + 1], letenv))
}
return EVAL(astList[2], letenv)
} else {
const evaledList = eval_ast(ast, env) as MalList
const fn = evaledList[0] as MalNativeFunc
return fn.call(evaledList.val.slice(1))
}
}
def PRINT(exp MalVal) string {
return exp?.print(true)
}
var repl_env = Env.new(null)
def REP(str string) string {
return PRINT(EVAL(READ(str), repl_env))
}
@entry
def main {
repl_env.set(MalSymbol.new("+"), MalNativeFunc.new((args List<MalVal>) MalVal => MalNumber.new((args[0] as MalNumber).val + (args[1] as MalNumber).val)))
repl_env.set(MalSymbol.new("-"), MalNativeFunc.new((args List<MalVal>) MalVal => MalNumber.new((args[0] as MalNumber).val - (args[1] as MalNumber).val)))
repl_env.set(MalSymbol.new("*"), MalNativeFunc.new((args List<MalVal>) MalVal => MalNumber.new((args[0] as MalNumber).val * (args[1] as MalNumber).val)))
repl_env.set(MalSymbol.new("/"), MalNativeFunc.new((args List<MalVal>) MalVal => MalNumber.new((args[0] as MalNumber).val / (args[1] as MalNumber).val)))
var line string
while (line = readLine("user> ")) != null {
if line == "" { continue }
try {
printLn(REP(line))
}
catch e MalError {
printLn("Error: \(e.message)")
}
}
}