///|
pub fn eval(
source : String,
environment~ : @eval.Environment,
filename? : String = "",
) -> Map[String, @value.Value] raise Error {
let tokens = @lexer.tokenize(source, file=filename)
let stmts = @parser.parse(tokens, file=filename)
let scope = @eval.Scope::new(env=environment)
// Populate scope with predeclared builtins
for name, val in environment.predeclared {
scope.set(name, val)
}
@eval.exec_module(scope, stmts)
// Extract all non-predeclared, non-underscore bindings as exports
let result : Map[String, @value.Value] = {}
for name, val in scope.bindings {
if not(environment.predeclared.contains(name)) && not(name.has_prefix("_")) {
result[name] = val
}
}
result
}
///|
pub fn eval_expr(
source : String,
environment~ : @eval.Environment,
filename? : String = "",
) -> @value.Value raise Error {
let tokens = @lexer.tokenize(source, file=filename)
let expr = @parser.parse_expression(tokens, file=filename)
let scope = @eval.Scope::new(env=environment)
for name, val in environment.predeclared {
scope.set(name, val)
}
@eval.eval_expr(scope, expr)
}
///|
pub fn new_environment(
loader? : ((String) -> String raise Error)? = None,
) -> @eval.Environment {
@eval.Environment::new(loader~)
}
///|
pub fn set_builtin(
env : @eval.Environment,
name : String,
func : (Array[@value.Value], Map[String, @value.Value]) -> @value.Value raise Error,
) -> Unit {
env.predeclared[name] = @value.Value::BuiltinFunction(name, func)
}