From b2a09562a6c0683ca528c866abc1ecc99b4bdcf0 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Thu, 24 Feb 2011 15:54:55 -0800 Subject: [PATCH] Factor crate expr evaluator out of parser, expand to simple scalars and ops, if, alt. --- src/comp/front/ast.rs | 8 +- src/comp/front/eval.rs | 443 +++++++++++++++++++++++++++++++++++++++ src/comp/front/parser.rs | 82 +------- src/comp/rustc.rc | 2 +- 4 files changed, 453 insertions(+), 82 deletions(-) create mode 100644 src/comp/front/eval.rs diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 088ef4ed920..f5c03bd7e74 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -46,7 +46,10 @@ type crate_ = rec(_mod module); tag crate_directive_ { cdir_expr(@expr); - cdir_const(@item); + // FIXME: cdir_let should be eliminated + // and redirected to the use of const stmt_decls inside + // crate directive blocks. + cdir_let(ident, @expr, vec[@crate_directive]); cdir_src_mod(ident, option.t[filename]); cdir_dir_mod(ident, option.t[filename], vec[@crate_directive]); cdir_view_item(@view_item); @@ -137,6 +140,8 @@ type stmt = spanned[stmt_]; tag stmt_ { stmt_decl(@decl); stmt_expr(@expr); + // These only exist in crate-level blocks. + stmt_crate_directive(@crate_directive); } type local = rec(option.t[@ty] ty, @@ -175,7 +180,6 @@ tag expr_ { expr_do_while(block, @expr, ann); expr_alt(@expr, vec[arm], ann); expr_block(block, ann); - expr_crate_directive_block(vec[crate_directive_]); expr_assign(@expr /* TODO: @expr|is_lval */, @expr, ann); expr_assign_op(binop, @expr /* TODO: @expr|is_lval */, @expr, ann); expr_field(@expr, ident, ann); diff --git a/src/comp/front/eval.rs b/src/comp/front/eval.rs new file mode 100644 index 00000000000..7275e55711e --- /dev/null +++ b/src/comp/front/eval.rs @@ -0,0 +1,443 @@ +import std._vec; +import std._str; +import std.option; +import std.option.some; +import std.option.none; +import std.map.hashmap; + +import driver.session; +import ast.ident; +import front.parser.parser; +import front.parser.spanned; +import front.parser.new_parser; +import front.parser.parse_mod_items; +import util.common; +import util.common.filename; +import util.common.append; +import util.common.span; +import util.common.new_str_hash; + + +// Simple dynamic-typed value type for eval_expr. +tag val { + val_bool(bool); + val_int(int); + val_str(str); +} + +type env = vec[tup(ident, val)]; + +fn mk_env() -> env { + let env e = vec(); + ret e; +} + +fn val_is_bool(val v) -> bool { + alt (v) { + case (val_bool(_)) { ret true; } + case (_) { } + } + ret false; +} + +fn val_is_int(val v) -> bool { + alt (v) { + case (val_bool(_)) { ret true; } + case (_) { } + } + ret false; +} + +fn val_is_str(val v) -> bool { + alt (v) { + case (val_str(_)) { ret true; } + case (_) { } + } + ret false; +} + +fn val_as_bool(val v) -> bool { + alt (v) { + case (val_bool(?b)) { ret b; } + case (_) { } + } + fail; +} + +fn val_as_int(val v) -> int { + alt (v) { + case (val_int(?i)) { ret i; } + case (_) { } + } + fail; +} + +fn val_as_str(val v) -> str { + alt (v) { + case (val_str(?s)) { ret s; } + case (_) { } + } + fail; +} + +fn lookup(session.session sess, env e, span sp, ident i) -> val { + for (tup(ident, val) pair in e) { + if (_str.eq(i, pair._0)) { + ret pair._1; + } + } + sess.span_err(sp, "unknown variable: " + i); + fail; +} + +fn eval_lit(session.session sess, env e, span sp, @ast.lit lit) -> val { + alt (lit.node) { + case (ast.lit_bool(?b)) { ret val_bool(b); } + case (ast.lit_int(?i)) { ret val_int(i); } + case (ast.lit_str(?s)) { ret val_str(s); } + case (_) { + sess.span_err(sp, "evaluating unsupported literal"); + } + } + fail; +} + +fn eval_expr(session.session sess, env e, @ast.expr x) -> val { + alt (x.node) { + case (ast.expr_path(?pth, _, _)) { + if (_vec.len[ident](pth.node.idents) == 1u && + _vec.len[@ast.ty](pth.node.types) == 0u) { + ret lookup(sess, e, x.span, pth.node.idents.(0)); + } + sess.span_err(x.span, "evaluating structured path-name"); + } + + case (ast.expr_lit(?lit, _)) { + ret eval_lit(sess, e, x.span, lit); + } + + case (ast.expr_unary(?op, ?a, _)) { + auto av = eval_expr(sess, e, a); + alt (op) { + case (ast.not) { + if (val_is_bool(av)) { + ret val_bool(!val_as_bool(av)); + } + sess.span_err(x.span, "bad types in '!' expression"); + } + case (_) { + sess.span_err(x.span, "evaluating unsupported unop"); + } + } + } + + case (ast.expr_binary(?op, ?a, ?b, _)) { + auto av = eval_expr(sess, e, a); + auto bv = eval_expr(sess, e, b); + alt (op) { + case (ast.add) { + if (val_is_int(av) && val_is_int(bv)) { + ret val_int(val_as_int(av) + val_as_int(bv)); + } + if (val_is_str(av) && val_is_str(bv)) { + ret val_str(val_as_str(av) + val_as_str(bv)); + } + sess.span_err(x.span, "bad types in '+' expression"); + } + + case (ast.sub) { + if (val_is_int(av) && val_is_int(bv)) { + ret val_int(val_as_int(av) - val_as_int(bv)); + } + sess.span_err(x.span, "bad types in '-' expression"); + } + + case (ast.mul) { + if (val_is_int(av) && val_is_int(bv)) { + ret val_int(val_as_int(av) * val_as_int(bv)); + } + sess.span_err(x.span, "bad types in '*' expression"); + } + + case (ast.div) { + if (val_is_int(av) && val_is_int(bv)) { + ret val_int(val_as_int(av) / val_as_int(bv)); + } + sess.span_err(x.span, "bad types in '/' expression"); + } + + case (ast.rem) { + if (val_is_int(av) && val_is_int(bv)) { + ret val_int(val_as_int(av) % val_as_int(bv)); + } + sess.span_err(x.span, "bad types in '%' expression"); + } + + case (ast.and) { + if (val_is_bool(av) && val_is_bool(bv)) { + ret val_bool(val_as_bool(av) && val_as_bool(bv)); + } + sess.span_err(x.span, "bad types in '&&' expression"); + } + + case (ast.or) { + if (val_is_bool(av) && val_is_bool(bv)) { + ret val_bool(val_as_bool(av) || val_as_bool(bv)); + } + sess.span_err(x.span, "bad types in '||' expression"); + } + + case (ast.eq) { + ret val_bool(val_eq(sess, x.span, av, bv)); + } + + case (ast.ne) { + ret val_bool(! val_eq(sess, x.span, av, bv)); + } + + case (_) { + sess.span_err(x.span, "evaluating unsupported binop"); + } + } + } + case (_) { + sess.span_err(x.span, "evaluating unsupported expression"); + } + } + fail; +} + +fn val_eq(session.session sess, span sp, val av, val bv) -> bool { + if (val_is_bool(av) && val_is_bool(bv)) { + ret val_as_bool(av) == val_as_bool(bv); + } + if (val_is_int(av) && val_is_int(bv)) { + ret val_as_int(av) == val_as_int(bv); + } + if (val_is_str(av) && val_is_str(bv)) { + ret _str.eq(val_as_str(av), + val_as_str(bv)); + } + sess.span_err(sp, "bad types in comparison"); + fail; +} + +impure fn eval_crate_directives(parser p, + env e, + vec[@ast.crate_directive] cdirs, + str prefix, + &mutable vec[@ast.view_item] view_items, + &mutable vec[@ast.item] items, + hashmap[ast.ident, + ast.mod_index_entry] index) { + + for (@ast.crate_directive sub_cdir in cdirs) { + eval_crate_directive(p, e, sub_cdir, prefix, + view_items, items, index); + } +} + + +impure fn eval_crate_directives_to_mod(parser p, + env e, + vec[@ast.crate_directive] cdirs, + str prefix) -> ast._mod { + let vec[@ast.view_item] view_items = vec(); + let vec[@ast.item] items = vec(); + auto index = new_str_hash[ast.mod_index_entry](); + + eval_crate_directives(p, e, cdirs, prefix, + view_items, items, index); + + ret rec(view_items=view_items, items=items, index=index); +} + + +impure fn eval_crate_directive_block(parser p, + env e, + &ast.block blk, + str prefix, + &mutable vec[@ast.view_item] view_items, + &mutable vec[@ast.item] items, + hashmap[ast.ident, + ast.mod_index_entry] index) { + + for (@ast.stmt s in blk.node.stmts) { + alt (s.node) { + case (ast.stmt_crate_directive(?cdir)) { + eval_crate_directive(p, e, cdir, prefix, + view_items, items, index); + } + case (_) { + auto sess = p.get_session(); + sess.span_err(s.span, + "unsupported stmt in crate-directive block"); + } + } + } +} + +impure fn eval_crate_directive_expr(parser p, + env e, + @ast.expr x, + str prefix, + &mutable vec[@ast.view_item] view_items, + &mutable vec[@ast.item] items, + hashmap[ast.ident, + ast.mod_index_entry] index) { + auto sess = p.get_session(); + + alt (x.node) { + + case (ast.expr_if(?cond, ?thn, ?elifs, ?elopt, _)) { + auto cv = eval_expr(sess, e, cond); + if (!val_is_bool(cv)) { + sess.span_err(x.span, "bad cond type in 'if'"); + } + + if (val_as_bool(cv)) { + ret eval_crate_directive_block(p, e, thn, prefix, + view_items, items, + index); + } + + for (tup(@ast.expr, ast.block) elif in elifs) { + auto cv = eval_expr(sess, e, elif._0); + if (!val_is_bool(cv)) { + sess.span_err(x.span, "bad cond type in 'else if'"); + } + + if (val_as_bool(cv)) { + ret eval_crate_directive_block(p, e, elif._1, prefix, + view_items, items, + index); + } + } + + alt (elopt) { + case (some[ast.block](?els)) { + ret eval_crate_directive_block(p, e, els, prefix, + view_items, items, + index); + } + case (_) { + // Absent-else is ok. + } + } + } + + case (ast.expr_alt(?v, ?arms, _)) { + auto vv = eval_expr(sess, e, v); + for (ast.arm arm in arms) { + alt (arm.pat.node) { + case (ast.pat_lit(?lit, _)) { + auto pv = eval_lit(sess, e, + arm.pat.span, lit); + if (val_eq(sess, arm.pat.span, vv, pv)) { + ret eval_crate_directive_block + (p, e, arm.block, prefix, + view_items, items, index); + } + } + case (ast.pat_wild(_)) { + ret eval_crate_directive_block + (p, e, arm.block, prefix, + view_items, items, index); + } + case (_) { + sess.span_err(arm.pat.span, + "bad pattern type in 'alt'"); + } + } + } + sess.span_err(x.span, "no cases matched in 'alt'"); + } + + case (_) { + sess.span_err(x.span, "unsupported expr type"); + } + } +} + +impure fn eval_crate_directive(parser p, + env e, + @ast.crate_directive cdir, + str prefix, + &mutable vec[@ast.view_item] view_items, + &mutable vec[@ast.item] items, + hashmap[ast.ident, + ast.mod_index_entry] index) { + alt (cdir.node) { + + case (ast.cdir_let(?id, ?x, ?cdirs)) { + auto v = eval_expr(p.get_session(), e, x); + auto e0 = vec(tup(id, v)) + e; + eval_crate_directives(p, e0, cdirs, prefix, + view_items, items, index); + } + + case (ast.cdir_expr(?x)) { + eval_crate_directive_expr(p, e, x, prefix, + view_items, items, index); + } + + case (ast.cdir_src_mod(?id, ?file_opt)) { + + auto file_path = id + ".rs"; + alt (file_opt) { + case (some[filename](?f)) { + file_path = f; + } + case (none[filename]) {} + } + + auto full_path = prefix + std.os.path_sep() + file_path; + + auto p0 = new_parser(p.get_session(), 0, full_path); + auto m0 = parse_mod_items(p0, token.EOF); + auto im = ast.item_mod(id, m0, p.next_def_id()); + auto i = @spanned(cdir.span, cdir.span, im); + ast.index_item(index, i); + append[@ast.item](items, i); + } + + case (ast.cdir_dir_mod(?id, ?dir_opt, ?cdirs)) { + + auto path = id; + alt (dir_opt) { + case (some[filename](?d)) { + path = d; + } + case (none[filename]) {} + } + + auto full_path = prefix + std.os.path_sep() + path; + auto m0 = eval_crate_directives_to_mod(p, e, cdirs, path); + auto im = ast.item_mod(id, m0, p.next_def_id()); + auto i = @spanned(cdir.span, cdir.span, im); + ast.index_item(index, i); + append[@ast.item](items, i); + } + + case (ast.cdir_view_item(?vi)) { + append[@ast.view_item](view_items, vi); + ast.index_view_item(index, vi); + } + + case (ast.cdir_meta(?mi)) {} + case (ast.cdir_syntax(?pth)) {} + case (ast.cdir_auth(?pth, ?eff)) {} + } +} + + +// +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: +// diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 944e14240ba..3579a3a087f 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -2111,80 +2111,6 @@ impure fn parse_crate_from_source_file(parser p) -> @ast.crate { // // Each directive imperatively extends its environment with 0 or more items. -impure fn eval_crate_directives(parser p, - vec[@ast.crate_directive] cdirs, - str prefix) -> ast._mod { - let vec[@ast.item] items = vec(); - auto index = new_str_hash[ast.mod_index_entry](); - auto view_items = parse_view(p, index); - - for (@ast.crate_directive sub_cdir in cdirs) { - eval_crate_directive(p, sub_cdir, prefix, - view_items, items, index); - } - - ret rec(view_items=view_items, items=items, index=index); -} - -impure fn eval_crate_directive(parser p, - @ast.crate_directive cdir, - str prefix, - &mutable vec[@ast.view_item] view_items, - &mutable vec[@ast.item] items, - hashmap[ast.ident,ast.mod_index_entry] index) { - alt (cdir.node) { - case (ast.cdir_expr(?e)) {} - case (ast.cdir_const(?i)) {} - - case (ast.cdir_src_mod(?id, ?file_opt)) { - - auto file_path = id + ".rs"; - alt (file_opt) { - case (some[filename](?f)) { - file_path = f; - } - case (none[filename]) {} - } - - auto full_path = prefix + std.os.path_sep() + file_path; - - auto p0 = new_parser(p.get_session(), 0, full_path); - auto m0 = parse_mod_items(p0, token.EOF); - auto im = ast.item_mod(id, m0, p.next_def_id()); - auto i = @spanned(cdir.span, cdir.span, im); - ast.index_item(index, i); - append[@ast.item](items, i); - } - - case (ast.cdir_dir_mod(?id, ?dir_opt, ?cdirs)) { - - auto path = id; - alt (dir_opt) { - case (some[filename](?d)) { - path = d; - } - case (none[filename]) {} - } - - auto full_path = prefix + std.os.path_sep() + path; - auto m0 = eval_crate_directives(p, cdirs, path); - auto im = ast.item_mod(id, m0, p.next_def_id()); - auto i = @spanned(cdir.span, cdir.span, im); - ast.index_item(index, i); - append[@ast.item](items, i); - } - - case (ast.cdir_view_item(?vi)) { - append[@ast.view_item](view_items, vi); - ast.index_view_item(index, vi); - } - - case (ast.cdir_meta(?mi)) {} - case (ast.cdir_syntax(?pth)) {} - case (ast.cdir_auth(?pth, ?eff)) {} - } -} - impure fn parse_crate_directive(parser p) -> ast.crate_directive { auto lo = p.get_span(); @@ -2201,10 +2127,7 @@ impure fn parse_crate_directive(parser p) -> ast.crate_directive expect(p, token.SEMI); ret spanned(lo, hi, ast.cdir_auth(n, e)); } - case (token.CONST) { - auto c = parse_item_const(p); - ret spanned(c.span, c.span, ast.cdir_const(c)); - } + case (token.MOD) { p.bump(); auto id = parse_ident(p); @@ -2267,7 +2190,8 @@ impure fn parse_crate_from_crate_file(parser p) -> @ast.crate { auto hi = lo; auto prefix = std.path.dirname(lo.filename); auto cdirs = parse_crate_directives(p, token.EOF); - auto m = eval_crate_directives(p, cdirs, prefix); + auto m = eval.eval_crate_directives_to_mod(p, eval.mk_env(), + cdirs, prefix); hi = p.get_span(); expect(p, token.EOF); ret @spanned(lo, hi, rec(module=m)); diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index b439632cfbc..bc4aaa52c1a 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -8,6 +8,7 @@ mod front { mod lexer; mod parser; mod token; + mod eval; } mod middle { @@ -38,7 +39,6 @@ auth middle.trans.copy_args_to_allocas = impure; auth middle.trans.trans_block = impure; auth lib.llvm = unsafe; - mod lib { alt (target_os) { case ("win32") {