Context aware clojures

Moved from dynamic scoping to static scoping.
This commit is contained in:
Robert Bendun 2022-05-22 00:34:02 +02:00
parent 8ac9fc5929
commit 6bc2a1cd38
4 changed files with 46 additions and 3 deletions

38
examples/church.mq Normal file
View File

@ -0,0 +1,38 @@
-- PAIR definition
var pair = [x y | [z | z x y]];
var car = [p | p [x y | x]];
var cdr = [p | p [x y | y]];
var x = pair 100 200;
say (car x);
say (cdr x);
-- This two values should be builtin, but currently is not
var true = (1 == 1);
var false = (1 != 1);
-- LIST definition
var null = pair true true;
var is_empty = car;
var head = [list | car (cdr list)];
var tail = [list | cdr (cdr list)];
var cons = [head tail | pair false (pair head tail)];
var for_each = [list iterator |
if (is_empty list) [| nil ] [|
iterator (head list);
for_each (tail list) iterator ]];
var map = [list iterator |
if (is_empty list) [| null ] [|
cons (iterator (head list)) (map (tail list) iterator) ]];
var foldr = [list init folder |
if (is_empty list)
[| init ]
[| foldr (tail list) (folder (head list) init) folder ]];
var range = [start stop | if (start >= stop) [|cons start null] [|cons start (range (start+1) stop)]];
var xs = range 1 5;
say (foldr xs 1 [x y|x*y]);

View File

@ -151,6 +151,8 @@ Result<Value> Interpreter::eval(Ast &&ast)
assert(param.type == Ast::Type::Literal && param.token.type == Token::Type::Symbol, "Not a name in parameter section of Ast::lambda"); assert(param.type == Ast::Type::Literal && param.token.type == Token::Type::Symbol, "Not a name in parameter section of Ast::lambda");
lambda.parameters.push_back(std::string(std::move(param).token.source)); lambda.parameters.push_back(std::string(std::move(param).token.source));
} }
lambda.context = env;
lambda.body = std::move(ast.arguments.back()); lambda.body = std::move(ast.arguments.back());
return Value::lambda(std::move(lambda)); return Value::lambda(std::move(lambda));
} }

View File

@ -427,8 +427,9 @@ struct Number
std::ostream& operator<<(std::ostream& os, Number const& num); std::ostream& operator<<(std::ostream& os, Number const& num);
struct Value; struct Env;
struct Interpreter; struct Interpreter;
struct Value;
using Function = std::function<Result<Value>(Interpreter &i, std::vector<Value>)>; using Function = std::function<Result<Value>(Interpreter &i, std::vector<Value>)>;
@ -437,6 +438,7 @@ struct Lambda
Location location; Location location;
std::vector<std::string> parameters; std::vector<std::string> parameters;
Ast body; Ast body;
std::shared_ptr<Env> context;
Result<Value> operator()(Interpreter &i, std::vector<Value> params); Result<Value> operator()(Interpreter &i, std::vector<Value> params);
}; };

View File

@ -129,8 +129,9 @@ std::string_view type_name(Value::Type t)
Result<Value> Lambda::operator()(Interpreter &i, std::vector<Value> arguments) Result<Value> Lambda::operator()(Interpreter &i, std::vector<Value> arguments)
{ {
// TODO Add some kind of scope guard auto old_scope = std::exchange(i.env, context);
i.enter_scope(); i.enter_scope();
assert(parameters.size() == arguments.size(), "wrong number of arguments"); assert(parameters.size() == arguments.size(), "wrong number of arguments");
for (usize j = 0; j < parameters.size(); ++j) { for (usize j = 0; j < parameters.size(); ++j) {
@ -140,6 +141,6 @@ Result<Value> Lambda::operator()(Interpreter &i, std::vector<Value> arguments)
Ast body_copy = body; Ast body_copy = body;
auto result = i.eval(std::move(body_copy)); auto result = i.eval(std::move(body_copy));
i.leave_scope(); i.env = old_scope;
return result; return result;
} }