diff options
| author | Marijn Haverbeke <marijnh@gmail.com> | 2011-12-02 13:42:51 +0100 |
|---|---|---|
| committer | Marijn Haverbeke <marijnh@gmail.com> | 2011-12-02 13:42:51 +0100 |
| commit | 64ce092c273a20cc503697c3dfebb956c9025d46 (patch) | |
| tree | d34183cdb6f2728e21a882b18370be9300f21633 /src/comp/syntax | |
| parent | 691b517fb9e18e190763a8ac83e09f1cffa6cf11 (diff) | |
| download | rust-64ce092c273a20cc503697c3dfebb956c9025d46.tar.gz rust-64ce092c273a20cc503697c3dfebb956c9025d46.zip | |
Allow literal patterns to contain arbitrary literal expressions
This removes the need for the unary minus hacks, and allows some other neat things like matching on 1 >> 4. Issue #954
Diffstat (limited to 'src/comp/syntax')
| -rw-r--r-- | src/comp/syntax/ast.rs | 4 | ||||
| -rw-r--r-- | src/comp/syntax/ast_util.rs | 101 | ||||
| -rw-r--r-- | src/comp/syntax/parse/parser.rs | 20 | ||||
| -rw-r--r-- | src/comp/syntax/print/pprust.rs | 6 |
4 files changed, 85 insertions, 46 deletions
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index 9c7b9ef422d..d9280a483b1 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -86,13 +86,13 @@ type field_pat = {ident: ident, pat: @pat}; tag pat_ { pat_wild; pat_bind(ident); - pat_lit(@lit); pat_tag(@path, [@pat]); pat_rec([field_pat], bool); pat_tup([@pat]); pat_box(@pat); pat_uniq(@pat); - pat_range(@lit, @lit); + pat_lit(@expr); + pat_range(@expr, @expr); } tag mutability { mut; imm; maybe_mut; } diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index da7b5a44953..d8b52300e91 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -225,45 +225,82 @@ fn ternary_to_if(e: @expr) -> @expr { fn ty_param_kind(tp: ty_param) -> kind { tp.kind } -fn compare_lit(a: @lit, b: @lit) -> int { - fn cmp<T>(a: T, b: T) -> int { a == b ? 0 : a < b ? -1 : 1 } - alt (a.node, b.node) { - (lit_int(a), lit_int(b)) | - (lit_mach_int(_, a), lit_mach_int(_, b)) { cmp(a, b) } - (lit_uint(a), lit_uint(b)) { cmp(a, b) } - (lit_char(a), lit_char(b)) { cmp(a, b) } - (lit_float(a), lit_float(b)) | - (lit_mach_float(_, a), lit_mach_float(_, b)) { - cmp(std::float::from_str(a), std::float::from_str(b)) +// FIXME this doesn't handle big integer/float literals correctly (nor does +// the rest of our literal handling) +tag const_val { const_float(float); const_int(i64); const_str(str); } + +fn eval_const_expr(e: @expr) -> const_val { + fn fromb(b: bool) -> const_val { const_int(b as i64) } + alt e.node { + expr_unary(neg., inner) { + alt eval_const_expr(inner) { + const_float(f) { const_float(-f) } + const_int(i) { const_int(-i) } + } + } + expr_unary(not., inner) { + alt eval_const_expr(inner) { + const_int(i) { const_int(!i) } + } } - (lit_str(a), lit_str(b)) { cmp(a, b) } - (lit_nil., lit_nil.) { 0 } - (lit_bool(a), lit_bool(b)) { cmp(a, b) } + expr_binary(op, a, b) { + alt (eval_const_expr(a), eval_const_expr(b)) { + (const_float(a), const_float(b)) { + alt op { + add. { const_float(a + b) } sub. { const_float(a - b) } + mul. { const_float(a * b) } div. { const_float(a / b) } + rem. { const_float(a % b) } eq. { fromb(a == b) } + lt. { fromb(a < b) } le. { fromb(a <= b) } ne. { fromb(a != b) } + ge. { fromb(a >= b) } gt. { fromb(a > b) } + } + } + (const_int(a), const_int(b)) { + alt op { + add. { const_int(a + b) } sub. { const_int(a - b) } + mul. { const_int(a * b) } div. { const_int(a / b) } + rem. { const_int(a % b) } and. | bitand. { const_int(a & b) } + or. | bitor. { const_int(a | b) } bitxor. { const_int(a ^ b) } + eq. { fromb(a == b) } lt. { fromb(a < b) } + le. { fromb(a <= b) } ne. { fromb(a != b) } + ge. { fromb(a >= b) } gt. { fromb(a > b) } + } + } + } + } + expr_lit(lit) { lit_to_const(lit) } } } -fn lit_eq(a: @lit, b: @lit) -> bool { compare_lit(a, b) == 0 } - -fn lit_types_match(a: @lit, b: @lit) -> bool { - alt (a.node, b.node) { - (lit_int(_), lit_int(_)) | (lit_uint(_), lit_uint(_)) | - (lit_char(_), lit_char(_)) | (lit_float(_), lit_float(_)) | - (lit_str(_), lit_str(_)) | (lit_nil., lit_nil.) | - (lit_bool(_), lit_bool(_ )) { true } - (lit_mach_int(ta, _), lit_mach_int(tb, _)) | - (lit_mach_float(ta, _), lit_mach_float(tb, _)) { ta == tb } - _ { false } +fn lit_to_const(lit: @lit) -> const_val { + alt lit.node { + lit_str(s) { const_str(s) } + lit_char(ch) { const_int(ch as i64) } + lit_int(i) | lit_mach_int(_, i) { const_int(i as i64) } + lit_uint(ui) { const_int(ui as i64) } + lit_float(s) | lit_mach_float(_, s) { + const_float(std::float::from_str(s)) + } + lit_nil. { const_int(0i64) } + lit_bool(b) { const_int(b as i64) } } } -fn lit_is_numeric(l: @ast::lit) -> bool { - alt l.node { - ast::lit_int(_) | ast::lit_char(_) | ast::lit_uint(_) | - ast::lit_mach_int(_, _) | ast::lit_float(_) | ast::lit_mach_float(_,_) { - true - } - _ { false } - } +fn compare_const_vals(a: const_val, b: const_val) -> int { + alt (a, b) { + (const_int(a), const_int(b)) { a == b ? 0 : a < b ? -1 : 1 } + (const_float(a), const_float(b)) { a == b ? 0 : a < b ? -1 : 1 } + (const_str(a), const_str(b)) { a == b ? 0 : a < b ? -1 : 1 } + } +} + +fn compare_lit_exprs(a: @expr, b: @expr) -> int { + compare_const_vals(eval_const_expr(a), eval_const_expr(b)) +} + +fn lit_expr_eq(a: @expr, b: @expr) -> bool { compare_lit_exprs(a, b) == 0 } + +fn lit_eq(a: @lit, b: @lit) -> bool { + compare_const_vals(lit_to_const(a), lit_to_const(b)) == 0 } // Local Variables: diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 6d751dff645..9baf6cf3ccf 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -9,7 +9,7 @@ import util::interner; import ast::{node_id, spanned}; import front::attr; -tag restriction { UNRESTRICTED; RESTRICT_NO_CALL_EXPRS; } +tag restriction { UNRESTRICTED; RESTRICT_NO_CALL_EXPRS; RESTRICT_NO_BAR_OP; } tag file_type { CRATE_FILE; SOURCE_FILE; } @@ -1189,6 +1189,8 @@ fn parse_more_binops(p: parser, lhs: @ast::expr, min_prec: int) -> } none. { none } }; + if peeked == token::BINOP(token::OR) && + p.get_restriction() == RESTRICT_NO_BAR_OP { ret lhs; } for cur: op_spec in *p.get_prec_table() { if cur.prec > min_prec && cur.tok == peeked { p.bump(); @@ -1462,9 +1464,9 @@ fn parse_pat(p: parser) -> @ast::pat { if p.peek() == token::RPAREN { hi = p.get_hi_pos(); p.bump(); - pat = - ast::pat_lit(@{node: ast::lit_nil, - span: ast_util::mk_sp(lo, hi)}); + let lit = @{node: ast::lit_nil, span: ast_util::mk_sp(lo, hi)}; + let expr = mk_expr(p, lo, hi, ast::expr_lit(lit)); + pat = ast::pat_lit(expr); } else { let fields = [parse_pat(p)]; while p.peek() == token::COMMA { @@ -1479,14 +1481,14 @@ fn parse_pat(p: parser) -> @ast::pat { } tok { if !is_ident(tok) || is_word(p, "true") || is_word(p, "false") { - let lit = parse_lit(p); + let val = parse_expr_res(p, RESTRICT_NO_BAR_OP); if eat_word(p, "to") { - let end = parse_lit(p); + let end = parse_expr_res(p, RESTRICT_NO_BAR_OP); hi = end.span.hi; - pat = ast::pat_range(@lit, @end); + pat = ast::pat_range(val, end); } else { - hi = lit.span.hi; - pat = ast::pat_lit(@lit); + hi = val.span.hi; + pat = ast::pat_lit(val); } } else if is_plain_ident(p) && alt p.look_ahead(1u) { diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index 9cd20cc87af..612768c4137 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -1061,7 +1061,6 @@ fn print_pat(s: ps, &&pat: @ast::pat) { alt pat.node { ast::pat_wild. { word(s.s, "_"); } ast::pat_bind(id) { word(s.s, id); } - ast::pat_lit(lit) { print_literal(s, lit); } ast::pat_tag(path, args) { print_path(s, path, true); if vec::len(args) > 0u { @@ -1094,11 +1093,12 @@ fn print_pat(s: ps, &&pat: @ast::pat) { } ast::pat_box(inner) { word(s.s, "@"); print_pat(s, inner); } ast::pat_uniq(inner) { word(s.s, "~"); print_pat(s, inner); } + ast::pat_lit(e) { print_expr(s, e); } ast::pat_range(begin, end) { - print_literal(s, begin); + print_expr(s, begin); space(s.s); word_space(s, "to"); - print_literal(s, end); + print_expr(s, end); } } s.ann.post(ann_node); |
