Implement defining top-level variables including in REPL
This commit is contained in:
parent
6a5aad3ae9
commit
908b896d43
5 changed files with 44 additions and 0 deletions
|
@ -256,6 +256,9 @@ Result<Value> Pair::first() const {
|
|||
}
|
||||
|
||||
Result<Value> Pair::second() const { return TRY(TRY(rest()).first()); }
|
||||
Result<Value> Pair::third() const {
|
||||
return TRY(TRY(TRY(rest()).rest()).first());
|
||||
}
|
||||
|
||||
Result<Value> Pair::rest() const {
|
||||
auto val = _value->rest.get();
|
||||
|
@ -660,5 +663,6 @@ Result<Value> Object::get(const Value& key) const {
|
|||
|
||||
Result<Value> Object::first() const { return ERROR(TypeMismatch); }
|
||||
Result<Value> Object::second() const { return ERROR(TypeMismatch); }
|
||||
Result<Value> Object::third() const { return ERROR(TypeMismatch); }
|
||||
|
||||
Result<Value> Object::rest() const { return ERROR(TypeMismatch); }
|
||||
|
|
|
@ -116,6 +116,7 @@ class Object {
|
|||
virtual Result<Value> get(const Value& key) const;
|
||||
virtual Result<Value> first() const;
|
||||
virtual Result<Value> second() const;
|
||||
virtual Result<Value> third() const;
|
||||
virtual Result<Value> rest() const;
|
||||
|
||||
Object() = default;
|
||||
|
@ -685,6 +686,7 @@ class Pair : public Object {
|
|||
|
||||
Result<Value> first() const final;
|
||||
Result<Value> second() const final;
|
||||
Result<Value> third() const final;
|
||||
Result<Value> rest() const final;
|
||||
|
||||
virtual Result<Value> copy_value() const final;
|
||||
|
@ -1149,6 +1151,7 @@ class Value {
|
|||
}
|
||||
Result<Value> first() const { return ((Object*)buf)->first(); }
|
||||
Result<Value> second() const { return ((Object*)buf)->second(); }
|
||||
Result<Value> third() const { return ((Object*)buf)->third(); }
|
||||
Result<Value> rest() const { return ((Object*)buf)->rest(); }
|
||||
|
||||
// TODO: cmp() probably doesn't need arena parameter
|
||||
|
|
|
@ -557,6 +557,29 @@ Result<Expression> Compiler::compile_not(Context& context, Symbol& op,
|
|||
return std::move(ex);
|
||||
}
|
||||
|
||||
Result<Expression> Compiler::compile_def(Context& context, Symbol& op,
|
||||
const Value& expr) {
|
||||
auto varname = TRY(expr.second());
|
||||
if (!varname.is<Symbol>()) return ERROR(CompilationError);
|
||||
|
||||
auto var_expr = TRY(expr.third());
|
||||
|
||||
uint64_t maxreg = context.maxreg;
|
||||
Expression ex = TRY(Expression::create());
|
||||
|
||||
auto comp = TRY(compile_expr(context, var_expr));
|
||||
ex.add_code(comp.code);
|
||||
|
||||
int64_t gname = TRY(context.add_const(varname));
|
||||
TRY(ex.add_opcode(Oc::GlobalStore, {1, (int64_t)gname},
|
||||
{0, (int64_t)comp.reg}));
|
||||
|
||||
ex.reg = comp.reg;
|
||||
context.maxreg = maxreg + 1;
|
||||
|
||||
return std::move(ex);
|
||||
}
|
||||
|
||||
Result<Expression> Compiler::compile_fn(Context& context, Symbol& op,
|
||||
const Value& expr) {
|
||||
Context ctx = TRY(Context::create(context));
|
||||
|
@ -841,6 +864,8 @@ Result<Expression> Compiler::compile_list(Context& context, const Value& expr) {
|
|||
return compile_or(context, sym, expr);
|
||||
} else if (TRY(sym.cmp("not")) == 0) {
|
||||
return compile_not(context, sym, expr);
|
||||
} else if (TRY(sym.cmp("def")) == 0) {
|
||||
return compile_def(context, sym, expr);
|
||||
} else if (TRY(sym.cmp("fn")) == 0) {
|
||||
return compile_fn(context, sym, expr);
|
||||
} else if (TRY(sym.cmp("let")) == 0) {
|
||||
|
|
|
@ -45,6 +45,8 @@ class Compiler {
|
|||
const Value& expr);
|
||||
Result<Expression> compile_not(Context& context, Symbol& op,
|
||||
const Value& expr);
|
||||
Result<Expression> compile_def(Context& context, Symbol& op,
|
||||
const Value& expr);
|
||||
Result<Expression> compile_fn(Context& context, Symbol& op,
|
||||
const Value& expr);
|
||||
Result<Expression> compile_let(Context& context, Symbol& op,
|
||||
|
|
|
@ -28,8 +28,18 @@
|
|||
)
|
||||
|
||||
|
||||
;; Top-level functions should be able to capture the "let" scope
|
||||
;; to a closure
|
||||
(let ((x 42))
|
||||
(fn foo() x)
|
||||
)
|
||||
|
||||
(assert (= (foo) 42))
|
||||
|
||||
|
||||
;; Top-level functions should be able to access top-level variables
|
||||
|
||||
(def four 4)
|
||||
|
||||
(fn add-four (x) (+ x four))
|
||||
(assert (= (add-four 5) 9))
|
||||
|
|
Loading…
Reference in a new issue