Added initial support for lambda functions

This commit is contained in:
John Wiegley 2010-09-06 00:33:03 -04:00
parent e162455ebb
commit 84780270f9
6 changed files with 129 additions and 27 deletions

View file

@ -108,10 +108,15 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
scope.define(symbol_t::FUNCTION, left()->as_ident(), right()); scope.define(symbol_t::FUNCTION, left()->as_ident(), right());
break; break;
case O_CALL: case O_CALL:
if (left()->left()->is_ident()) if (left()->left()->is_ident()) {
scope.define(symbol_t::FUNCTION, left()->left()->as_ident(), this); ptr_op_t node(new op_t(op_t::O_LAMBDA));
else node->set_left(left()->right());
node->set_right(right());
scope.define(symbol_t::FUNCTION, left()->left()->as_ident(), node);
} else {
throw_(compile_error, _("Invalid function definition")); throw_(compile_error, _("Invalid function definition"));
}
break; break;
default: default:
throw_(compile_error, _("Invalid function definition")); throw_(compile_error, _("Invalid function definition"));
@ -183,16 +188,12 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
break; break;
} }
case O_DEFINE: { case O_LAMBDA: {
call_scope_t& call_args(downcast<call_scope_t>(scope)); call_scope_t& call_args(downcast<call_scope_t>(scope));
std::size_t args_count = call_args.size(); std::size_t args_count(call_args.size());
std::size_t args_index = 0; std::size_t args_index(0);
assert(left()->kind == O_CALL);
ptr_op_t sym = left()->right();
symbol_scope_t call_scope(call_args); symbol_scope_t call_scope(call_args);
ptr_op_t sym(left());
for (; sym; sym = sym->has_right() ? sym->right() : NULL) { for (; sym; sym = sym->has_right() ? sym->right() : NULL) {
ptr_op_t varname = sym; ptr_op_t varname = sym;
@ -618,6 +619,14 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const
found = true; found = true;
break; break;
case O_LAMBDA:
if (left() && left()->print(out, context))
found = true;
out << " -> ";
if (has_right() && right()->print(out, context))
found = true;
break;
case O_CALL: case O_CALL:
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
@ -692,6 +701,7 @@ void expr_t::op_t::dump(std::ostream& out, const int depth) const
case O_DEFINE: out << "O_DEFINE"; break; case O_DEFINE: out << "O_DEFINE"; break;
case O_LOOKUP: out << "O_LOOKUP"; break; case O_LOOKUP: out << "O_LOOKUP"; break;
case O_LAMBDA: out << "O_LAMBDA"; break;
case O_CALL: out << "O_CALL"; break; case O_CALL: out << "O_CALL"; break;
case O_MATCH: out << "O_MATCH"; break; case O_MATCH: out << "O_MATCH"; break;

View file

@ -104,6 +104,7 @@ public:
O_DEFINE, O_DEFINE,
O_LOOKUP, O_LOOKUP,
O_LAMBDA,
O_CALL, O_CALL,
O_MATCH, O_MATCH,

View file

@ -232,15 +232,12 @@ expr_t::parser_t::parse_logic_expr(std::istream& in,
if (node && ! tflags.has_flags(PARSE_SINGLE)) { if (node && ! tflags.has_flags(PARSE_SINGLE)) {
while (true) { while (true) {
op_t::kind_t kind = op_t::LAST; op_t::kind_t kind = op_t::LAST;
parse_flags_t _flags = tflags; parse_flags_t _flags = tflags;
token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT)); token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
bool negate = false; bool negate = false;
switch (tok.kind) { switch (tok.kind) {
case token_t::DEFINE:
kind = op_t::O_DEFINE;
break;
case token_t::EQUAL: case token_t::EQUAL:
if (tflags.has_flags(PARSE_NO_ASSIGN)) if (tflags.has_flags(PARSE_NO_ASSIGN))
tok.rewind(in); tok.rewind(in);
@ -422,22 +419,42 @@ expr_t::parser_t::parse_querycolon_expr(std::istream& in,
} }
expr_t::ptr_op_t expr_t::ptr_op_t
expr_t::parser_t::parse_value_expr(std::istream& in, expr_t::parser_t::parse_lambda_expr(std::istream& in,
const parse_flags_t& tflags) const const parse_flags_t& tflags) const
{ {
ptr_op_t node(parse_querycolon_expr(in, tflags)); ptr_op_t node(parse_querycolon_expr(in, tflags));
if (node && ! tflags.has_flags(PARSE_SINGLE)) {
token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
if (tok.kind == token_t::ARROW) {
ptr_op_t prev(node);
node = new op_t(op_t::O_LAMBDA);
node->set_left(prev);
node->set_right(parse_querycolon_expr(in, tflags));
} else {
push_token(tok);
}
}
return node;
}
expr_t::ptr_op_t
expr_t::parser_t::parse_comma_expr(std::istream& in,
const parse_flags_t& tflags) const
{
ptr_op_t node(parse_lambda_expr(in, tflags));
if (node && ! tflags.has_flags(PARSE_SINGLE)) { if (node && ! tflags.has_flags(PARSE_SINGLE)) {
ptr_op_t next; ptr_op_t next;
while (true) { while (true) {
token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT)); token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
if (tok.kind == token_t::COMMA || tok.kind == token_t::SEMI) { if (tok.kind == token_t::COMMA) {
bool comma_op = tok.kind == token_t::COMMA;
if (! next) { if (! next) {
ptr_op_t prev(node); ptr_op_t prev(node);
node = new op_t(comma_op ? op_t::O_CONS : op_t::O_SEQ); node = new op_t(op_t::O_CONS);
node->set_left(prev); node->set_left(prev);
next = node; next = node;
@ -448,8 +465,65 @@ expr_t::parser_t::parse_value_expr(std::istream& in,
if (ntok.kind == token_t::RPAREN) if (ntok.kind == token_t::RPAREN)
break; break;
ptr_op_t chain(new op_t(comma_op ? op_t::O_CONS : op_t::O_SEQ)); ptr_op_t chain(new op_t(op_t::O_CONS));
chain->set_left(parse_querycolon_expr(in, tflags)); chain->set_left(parse_lambda_expr(in, tflags));
next->set_right(chain);
next = chain;
} else {
push_token(tok);
break;
}
}
}
return node;
}
expr_t::ptr_op_t
expr_t::parser_t::parse_assign_expr(std::istream& in,
const parse_flags_t& tflags) const
{
ptr_op_t node(parse_comma_expr(in, tflags));
if (node && ! tflags.has_flags(PARSE_SINGLE)) {
token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
if (tok.kind == token_t::ASSIGN) {
ptr_op_t prev(node);
node = new op_t(op_t::O_DEFINE);
node->set_left(prev);
node->set_right(parse_comma_expr(in, tflags));
} else {
push_token(tok);
}
}
return node;
}
expr_t::ptr_op_t
expr_t::parser_t::parse_value_expr(std::istream& in,
const parse_flags_t& tflags) const
{
ptr_op_t node(parse_assign_expr(in, tflags));
if (node && ! tflags.has_flags(PARSE_SINGLE)) {
ptr_op_t next;
while (true) {
token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
if (tok.kind == token_t::SEMI) {
if (! next) {
ptr_op_t prev(node);
node = new op_t(op_t::O_SEQ);
node->set_left(prev);
next = node;
}
ptr_op_t chain(new op_t(op_t::O_SEQ));
chain->set_left(parse_assign_expr(in, tflags));
next->set_right(chain); next->set_right(chain);
next = chain; next = chain;

View file

@ -93,6 +93,12 @@ class expr_t::parser_t : public noncopyable
const parse_flags_t& flags) const; const parse_flags_t& flags) const;
ptr_op_t parse_querycolon_expr(std::istream& in, ptr_op_t parse_querycolon_expr(std::istream& in,
const parse_flags_t& flags) const; const parse_flags_t& flags) const;
ptr_op_t parse_comma_expr(std::istream& in,
const parse_flags_t& flags) const;
ptr_op_t parse_lambda_expr(std::istream& in,
const parse_flags_t& flags) const;
ptr_op_t parse_assign_expr(std::istream& in,
const parse_flags_t& flags) const;
ptr_op_t parse_value_expr(std::istream& in, ptr_op_t parse_value_expr(std::istream& in,
const parse_flags_t& flags) const; const parse_flags_t& flags) const;

View file

@ -269,6 +269,15 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
case '-': case '-':
in.get(c); in.get(c);
c = static_cast<char>(in.peek());
if (c == '>') {
in.get(c);
symbol[1] = c;
symbol[2] = '\0';
kind = ARROW;
length = 2;
break;
}
kind = MINUS; kind = MINUS;
break; break;
case '+': case '+':
@ -329,7 +338,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
length = 2; length = 2;
break; break;
} }
kind = DEFINE; kind = ASSIGN;
break; break;
case '<': case '<':

View file

@ -56,6 +56,8 @@ struct expr_t::token_t : public noncopyable
LPAREN, // ( LPAREN, // (
RPAREN, // ) RPAREN, // )
LBRACE, // {
RBRACE, // }
EQUAL, // == EQUAL, // ==
NEQUAL, // != NEQUAL, // !=
@ -64,7 +66,6 @@ struct expr_t::token_t : public noncopyable
GREATER, // > GREATER, // >
GREATEREQ, // >= GREATEREQ, // >=
DEFINE, // :=
ASSIGN, // = ASSIGN, // =
MATCH, // =~ MATCH, // =~
NMATCH, // !~ NMATCH, // !~
@ -72,6 +73,7 @@ struct expr_t::token_t : public noncopyable
PLUS, // + PLUS, // +
STAR, // * STAR, // *
SLASH, // / SLASH, // /
ARROW, // ->
KW_DIV, // div KW_DIV, // div
EXCLAM, // !, not EXCLAM, // !, not