summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2010-09-06 00:33:03 -0400
committerJohn Wiegley <johnw@newartisans.com>2010-09-06 00:56:00 -0400
commit84780270f9bc427f6edcd295b68ffcf6b911baf6 (patch)
tree7b151bbc02ab30bad5c3636cfefd4d5cd4a419da /src
parente162455ebb545ea33580e58f52ebe424ef9e68fa (diff)
downloadfork-ledger-84780270f9bc427f6edcd295b68ffcf6b911baf6.tar.gz
fork-ledger-84780270f9bc427f6edcd295b68ffcf6b911baf6.tar.bz2
fork-ledger-84780270f9bc427f6edcd295b68ffcf6b911baf6.zip
Added initial support for lambda functions
Diffstat (limited to 'src')
-rw-r--r--src/op.cc32
-rw-r--r--src/op.h1
-rw-r--r--src/parser.cc102
-rw-r--r--src/parser.h6
-rw-r--r--src/token.cc11
-rw-r--r--src/token.h4
6 files changed, 129 insertions, 27 deletions
diff --git a/src/op.cc b/src/op.cc
index 6105e38e..86057f66 100644
--- a/src/op.cc
+++ b/src/op.cc
@@ -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());
break;
case O_CALL:
- if (left()->left()->is_ident())
- scope.define(symbol_t::FUNCTION, left()->left()->as_ident(), this);
- else
+ if (left()->left()->is_ident()) {
+ ptr_op_t node(new op_t(op_t::O_LAMBDA));
+ 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"));
+ }
break;
default:
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;
}
- case O_DEFINE: {
+ case O_LAMBDA: {
call_scope_t& call_args(downcast<call_scope_t>(scope));
- std::size_t args_count = call_args.size();
- std::size_t args_index = 0;
-
- assert(left()->kind == O_CALL);
-
- ptr_op_t sym = left()->right();
-
+ std::size_t args_count(call_args.size());
+ std::size_t args_index(0);
symbol_scope_t call_scope(call_args);
+ ptr_op_t sym(left());
for (; sym; sym = sym->has_right() ? sym->right() : NULL) {
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;
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:
if (left() && left()->print(out, context))
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_LOOKUP: out << "O_LOOKUP"; break;
+ case O_LAMBDA: out << "O_LAMBDA"; break;
case O_CALL: out << "O_CALL"; break;
case O_MATCH: out << "O_MATCH"; break;
diff --git a/src/op.h b/src/op.h
index aa591b28..63d844bf 100644
--- a/src/op.h
+++ b/src/op.h
@@ -104,6 +104,7 @@ public:
O_DEFINE,
O_LOOKUP,
+ O_LAMBDA,
O_CALL,
O_MATCH,
diff --git a/src/parser.cc b/src/parser.cc
index a5b1e6e3..e9205d16 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -232,15 +232,12 @@ expr_t::parser_t::parse_logic_expr(std::istream& in,
if (node && ! tflags.has_flags(PARSE_SINGLE)) {
while (true) {
- op_t::kind_t kind = op_t::LAST;
+ op_t::kind_t kind = op_t::LAST;
parse_flags_t _flags = tflags;
- token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
- bool negate = false;
+ token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
+ bool negate = false;
switch (tok.kind) {
- case token_t::DEFINE:
- kind = op_t::O_DEFINE;
- break;
case token_t::EQUAL:
if (tflags.has_flags(PARSE_NO_ASSIGN))
tok.rewind(in);
@@ -422,22 +419,42 @@ expr_t::parser_t::parse_querycolon_expr(std::istream& in,
}
expr_t::ptr_op_t
-expr_t::parser_t::parse_value_expr(std::istream& in,
- const parse_flags_t& tflags) const
+expr_t::parser_t::parse_lambda_expr(std::istream& in,
+ const parse_flags_t& tflags) const
{
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)) {
ptr_op_t next;
while (true) {
token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
- if (tok.kind == token_t::COMMA || tok.kind == token_t::SEMI) {
- bool comma_op = tok.kind == token_t::COMMA;
-
+ if (tok.kind == token_t::COMMA) {
if (! next) {
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);
next = node;
@@ -448,8 +465,65 @@ expr_t::parser_t::parse_value_expr(std::istream& in,
if (ntok.kind == token_t::RPAREN)
break;
- ptr_op_t chain(new op_t(comma_op ? op_t::O_CONS : op_t::O_SEQ));
- chain->set_left(parse_querycolon_expr(in, tflags));
+ ptr_op_t chain(new op_t(op_t::O_CONS));
+ 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 = chain;
diff --git a/src/parser.h b/src/parser.h
index 93ea994f..9a65765d 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -93,6 +93,12 @@ class expr_t::parser_t : public noncopyable
const parse_flags_t& flags) const;
ptr_op_t parse_querycolon_expr(std::istream& in,
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,
const parse_flags_t& flags) const;
diff --git a/src/token.cc b/src/token.cc
index be39205c..199c3b3c 100644
--- a/src/token.cc
+++ b/src/token.cc
@@ -269,6 +269,15 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
case '-':
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;
break;
case '+':
@@ -329,7 +338,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
length = 2;
break;
}
- kind = DEFINE;
+ kind = ASSIGN;
break;
case '<':
diff --git a/src/token.h b/src/token.h
index 28e29752..13a799cb 100644
--- a/src/token.h
+++ b/src/token.h
@@ -56,6 +56,8 @@ struct expr_t::token_t : public noncopyable
LPAREN, // (
RPAREN, // )
+ LBRACE, // {
+ RBRACE, // }
EQUAL, // ==
NEQUAL, // !=
@@ -64,7 +66,6 @@ struct expr_t::token_t : public noncopyable
GREATER, // >
GREATEREQ, // >=
- DEFINE, // :=
ASSIGN, // =
MATCH, // =~
NMATCH, // !~
@@ -72,6 +73,7 @@ struct expr_t::token_t : public noncopyable
PLUS, // +
STAR, // *
SLASH, // /
+ ARROW, // ->
KW_DIV, // div
EXCLAM, // !, not