diff --git a/examples/church.mq b/examples/church.mq new file mode 100644 index 0000000..69d860d --- /dev/null +++ b/examples/church.mq @@ -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]); diff --git a/src/interpreter.cc b/src/interpreter.cc index 8c23e3a..de8e499 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -151,6 +151,8 @@ Result 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"); lambda.parameters.push_back(std::string(std::move(param).token.source)); } + + lambda.context = env; lambda.body = std::move(ast.arguments.back()); return Value::lambda(std::move(lambda)); } diff --git a/src/musique.hh b/src/musique.hh index 89d6973..d1c1782 100644 --- a/src/musique.hh +++ b/src/musique.hh @@ -427,8 +427,9 @@ struct Number std::ostream& operator<<(std::ostream& os, Number const& num); -struct Value; +struct Env; struct Interpreter; +struct Value; using Function = std::function(Interpreter &i, std::vector)>; @@ -437,6 +438,7 @@ struct Lambda Location location; std::vector parameters; Ast body; + std::shared_ptr context; Result operator()(Interpreter &i, std::vector params); }; diff --git a/src/value.cc b/src/value.cc index a6ce1ec..410a1db 100644 --- a/src/value.cc +++ b/src/value.cc @@ -129,8 +129,9 @@ std::string_view type_name(Value::Type t) Result Lambda::operator()(Interpreter &i, std::vector arguments) { - // TODO Add some kind of scope guard + auto old_scope = std::exchange(i.env, context); i.enter_scope(); + assert(parameters.size() == arguments.size(), "wrong number of arguments"); for (usize j = 0; j < parameters.size(); ++j) { @@ -140,6 +141,6 @@ Result Lambda::operator()(Interpreter &i, std::vector arguments) Ast body_copy = body; auto result = i.eval(std::move(body_copy)); - i.leave_scope(); + i.env = old_scope; return result; }