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
This commit is contained in:
Marijn Haverbeke 2011-12-02 13:42:51 +01:00
parent 691b517fb9
commit 64ce092c27
10 changed files with 177 additions and 130 deletions

View file

@ -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; }

View file

@ -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) }
}
}
(lit_str(a), lit_str(b)) { cmp(a, b) }
(lit_nil., lit_nil.) { 0 }
(lit_bool(a), lit_bool(b)) { cmp(a, b) }
expr_unary(not., inner) {
alt eval_const_expr(inner) {
const_int(i) { const_int(!i) }
}
}
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:

View file

@ -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) {

View file

@ -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);