Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fantom: merge eval_ast and macroexpand into EVAL, implement DEBUG-EVAL #704

Merged
merged 1 commit into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions impls/fantom/src/mallib/fan/env.fan
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,8 @@ class MalEnv
return value
}

MalEnv? find(MalSymbol key)
MalVal? get(Str key)
{
return data.containsKey(key.value) ? this : outer?.find(key)
}

MalVal get(MalSymbol key)
{
foundEnv := find(key) ?: throw Err("'$key.value' not found")
return (MalVal)foundEnv.data[key.value]
return data.containsKey(key) ? data[key] : outer?.get(key)
}
}
58 changes: 27 additions & 31 deletions impls/fantom/src/step2_eval/fan/main.fan
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,47 @@ class Main
return Reader.read_str(s)
}

static MalVal eval_ast(MalVal ast, Str:MalFunc env)
static MalVal EVAL(MalVal ast, Str:MalVal env)
{
switch (ast.typeof)
{
case MalSymbol#:
varName := (ast as MalSymbol).value
varVal := env[varName] ?: throw Err("'$varName' not found")
return (MalVal)varVal
case MalList#:
newElements := (ast as MalList).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalList(newElements)
case MalVector#:
newElements := (ast as MalVector).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalVector(newElements)
case MalHashMap#:
newElements := (ast as MalHashMap).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalHashMap.fromMap(newElements)
default:
return ast
}
}
switch (ast.typeof)
{
case MalSymbol#:
varName := (ast as MalSymbol).value
return env[varName] ?: throw Err("'$varName' not found")
case MalVector#:
newElements := (ast as MalVector).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalVector(newElements)
case MalHashMap#:
newElements := (ast as MalHashMap).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalHashMap.fromMap(newElements)
case MalList#:
astList := ast as MalList
if (astList.isEmpty) return ast

static MalVal EVAL(MalVal ast, Str:MalFunc env)
{
if (!(ast is MalList)) return eval_ast(ast, env)
astList := ast as MalList
if (astList.isEmpty) return ast
evaled_ast := eval_ast(ast, env) as MalList
f := evaled_ast[0] as MalFunc
return f.call(evaled_ast[1..-1])
f := EVAL(astList[0], env)
args := astList.value[1..-1].map |MalVal v -> MalVal| { EVAL(v, env) }

malfunc := f as MalFunc
return malfunc.call(args)

default:
return ast
}
}

static Str PRINT(MalVal exp)
{
return exp.toString(true)
}

static Str REP(Str s, Str:MalFunc env)
static Str REP(Str s, Str:MalVal env)
{
return PRINT(EVAL(READ(s), env))
}

static Void main()
{
env := [
repl_env := [
"+": MalFunc { MalInteger((it[0] as MalInteger).value + (it[1] as MalInteger).value) },
"-": MalFunc { MalInteger((it[0] as MalInteger).value - (it[1] as MalInteger).value) },
"*": MalFunc { MalInteger((it[0] as MalInteger).value * (it[1] as MalInteger).value) },
Expand All @@ -62,7 +58,7 @@ class Main
if (line == null) break
if (line.isSpace) continue
try
echo(REP(line, env))
echo(REP(line, repl_env))
catch (Err e)
echo("Error: $e.msg")
}
Expand Down
76 changes: 41 additions & 35 deletions impls/fantom/src/step3_env/fan/main.fan
Original file line number Diff line number Diff line change
Expand Up @@ -7,46 +7,52 @@ class Main
return Reader.read_str(s)
}

static MalVal eval_ast(MalVal ast, MalEnv env)
static Void debug_eval(MalVal ast, MalEnv env)
{
switch (ast.typeof)
{
case MalSymbol#:
return env.get(ast)
case MalList#:
newElements := (ast as MalList).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalList(newElements)
case MalVector#:
newElements := (ast as MalVector).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalVector(newElements)
case MalHashMap#:
newElements := (ast as MalHashMap).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalHashMap.fromMap(newElements)
default:
return ast
}
value := env.get("DEBUG-EVAL")
if ((value != null) && !(value is MalFalseyVal))
echo("EVAL: ${PRINT(ast)}")
}

static MalVal EVAL(MalVal ast, MalEnv env)
{
if (!(ast is MalList)) return eval_ast(ast, env)
astList := ast as MalList
if (astList.isEmpty) return ast
switch ((astList[0] as MalSymbol).value)
{
case "def!":
return env.set(astList[1], EVAL(astList[2], env))
case "let*":
let_env := MalEnv(env)
varList := (astList[1] as MalSeq)
for (i := 0; i < varList.count; i += 2)
let_env.set(varList[i], EVAL(varList[i + 1], let_env))
return EVAL(astList[2], let_env)
default:
evaled_ast := eval_ast(ast, env) as MalList
f := evaled_ast[0] as MalFunc
return f.call(evaled_ast[1..-1])
}
debug_eval(ast, env)
switch (ast.typeof)
{
case MalSymbol#:
varName := (ast as MalSymbol).value
return env.get(varName) ?: throw Err("'$varName' not found")
case MalVector#:
newElements := (ast as MalVector).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalVector(newElements)
case MalHashMap#:
newElements := (ast as MalHashMap).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalHashMap.fromMap(newElements)
case MalList#:
astList := ast as MalList
if (astList.isEmpty) return ast
switch ((astList[0] as MalSymbol)?.value)
{
case "def!":
value := EVAL(astList[2], env)
return env.set(astList[1], value)
case "let*":
let_env := MalEnv(env)
varList := astList[1] as MalSeq
for (i := 0; i < varList.count; i += 2)
let_env.set(varList[i], EVAL(varList[i + 1], let_env))
return EVAL(astList[2], let_env)
default:
f := EVAL(astList[0], env)
args := astList.value[1..-1].map |MalVal v -> MalVal| { EVAL(v, env) }

malfunc := f as MalFunc
return malfunc.call(args)

}
default:
return ast
}
}

static Str PRINT(MalVal exp)
Expand Down
101 changes: 56 additions & 45 deletions impls/fantom/src/step4_if_fn_do/fan/main.fan
Original file line number Diff line number Diff line change
Expand Up @@ -7,56 +7,67 @@ class Main
return Reader.read_str(s)
}

static MalVal eval_ast(MalVal ast, MalEnv env)
static Void debug_eval(MalVal ast, MalEnv env)
{
switch (ast.typeof)
{
case MalSymbol#:
return env.get(ast)
case MalList#:
newElements := (ast as MalList).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalList(newElements)
case MalVector#:
newElements := (ast as MalVector).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalVector(newElements)
case MalHashMap#:
newElements := (ast as MalHashMap).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalHashMap.fromMap(newElements)
default:
return ast
}
value := env.get("DEBUG-EVAL")
if ((value != null) && !(value is MalFalseyVal))
echo("EVAL: ${PRINT(ast)}")
}

static MalVal EVAL(MalVal ast, MalEnv env)
{
if (!(ast is MalList)) return eval_ast(ast, env)
astList := ast as MalList
if (astList.isEmpty) return ast
switch ((astList[0] as MalSymbol)?.value)
{
case "def!":
return env.set(astList[1], EVAL(astList[2], env))
case "let*":
let_env := MalEnv(env)
varList := astList[1] as MalSeq
for (i := 0; i < varList.count; i += 2)
let_env.set(varList[i], EVAL(varList[i + 1], let_env))
return EVAL(astList[2], let_env)
case "do":
eval_ast(MalList(astList[1..-2]), env)
return EVAL(astList[-1], env)
case "if":
if (EVAL(astList[1], env) is MalFalseyVal)
return astList.count > 3 ? EVAL(astList[3], env) : MalNil.INSTANCE
else
return EVAL(astList[2], env)
case "fn*":
return MalFunc { EVAL(astList[2], MalEnv(env, (astList[1] as MalSeq), MalList(it))) }
default:
evaled_ast := eval_ast(ast, env) as MalList
f := evaled_ast[0] as MalFunc
return f.call(evaled_ast[1..-1])
}
debug_eval(ast, env)
switch (ast.typeof)
{
case MalSymbol#:
varName := (ast as MalSymbol).value
return env.get(varName) ?: throw Err("'$varName' not found")
case MalVector#:
newElements := (ast as MalVector).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalVector(newElements)
case MalHashMap#:
newElements := (ast as MalHashMap).value.map |MalVal v -> MalVal| { EVAL(v, env) }
return MalHashMap.fromMap(newElements)
case MalList#:
astList := ast as MalList
if (astList.isEmpty) return ast
switch ((astList[0] as MalSymbol)?.value)
{
case "def!":
value := EVAL(astList[2], env)
return env.set(astList[1], value)
case "let*":
let_env := MalEnv(env)
varList := astList[1] as MalSeq
for (i := 0; i < varList.count; i += 2)
let_env.set(varList[i], EVAL(varList[i + 1], let_env))
return EVAL(astList[2], let_env)
case "do":
for (i:=1; i<astList.count-1; i+=1)
EVAL(astList[i], env);
return EVAL(astList[-1], env)
case "if":
if (EVAL(astList[1], env) is MalFalseyVal)
return astList.count > 3 ? EVAL(astList[3], env) : MalNil.INSTANCE
else
return EVAL(astList[2], env)
case "fn*":
return MalFunc { EVAL(astList[2], MalEnv(env, (astList[1] as MalSeq), MalList(it))) }
default:
f := EVAL(astList[0], env)
args := astList.value[1..-1].map |MalVal v -> MalVal| { EVAL(v, env) }
switch (f.typeof)
{
case MalFunc#:
malfunc := f as MalFunc
return malfunc.call(args)
default:
throw Err("Unknown type")
}
}
default:
return ast
}
}

static Str PRINT(MalVal exp)
Expand Down
Loading