Skip to content

Commit ce0f054

Browse files
jdmmarijnh
authored andcommitted
Implement pattern ranges for all numeric types.
1 parent e6a84f2 commit ce0f054

File tree

14 files changed

+451
-25
lines changed

14 files changed

+451
-25
lines changed

src/comp/middle/alias.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ fn pattern_roots(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat)
645645
fn walk(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat,
646646
&set: [pattern_root]) {
647647
alt pat.node {
648-
ast::pat_wild. | ast::pat_lit(_) {}
648+
ast::pat_wild. | ast::pat_lit(_) | ast::pat_range(_, _) {}
649649
ast::pat_bind(nm) {
650650
set += [{id: pat.id, name: nm, mut: mut, span: pat.span}];
651651
}

src/comp/middle/check_alt.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,15 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
6262
ret true;
6363
}
6464

65-
6665
alt a.node {
6766
pat_wild. | pat_bind(_) { ret true; }
6867
pat_lit(la) {
6968
alt b.node {
7069
pat_lit(lb) { ret util::common::lit_eq(la, lb); }
70+
pat_range(beginb, endb) {
71+
ret util::common::lit_type_eq(la, beginb) &&
72+
util::common::lit_in_range(la, beginb, endb);
73+
}
7174
_ { ret false; }
7275
}
7376
}
@@ -98,6 +101,19 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
98101
_ { ret pattern_supersedes(tcx, suba, b); }
99102
}
100103
}
104+
pat_range(begina, enda) {
105+
alt b.node {
106+
pat_lit(lb) {
107+
ret util::common::lit_type_eq(lb, begina) &&
108+
util::common::lit_in_range(lb, begina, enda);
109+
}
110+
pat_range(beginb, endb) {
111+
ret util::common::lit_type_eq(begina, beginb) &&
112+
util::common::lit_ranges_overlap(begina, enda, beginb, endb);
113+
}
114+
_ { ret false; }
115+
}
116+
}
101117
}
102118
}
103119

src/comp/middle/trans_alt.rs

Lines changed: 78 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import std::{str, vec, option};
1+
import std::{str, vec, option, int};
22
import option::{some, none};
33
import std::map::hashmap;
44

@@ -16,25 +16,42 @@ import util::common::lit_eq;
1616

1717
import trans_common::*;
1818

19-
// An option identifying a branch (either a literal or a tag variant)
19+
// An option identifying a branch (either a literal, a tag variant or a range)
2020
tag opt {
2121
lit(@ast::lit);
2222
var(/* variant id */uint, /* variant dids */{tg: def_id, var: def_id});
23+
range(@ast::lit, @ast::lit);
2324
}
2425
fn opt_eq(a: opt, b: opt) -> bool {
2526
alt a {
2627
lit(la) {
27-
ret alt b { lit(lb) { lit_eq(la, lb) } var(_, _) { false } };
28+
ret alt b { lit(lb) { lit_eq(la, lb) } _ { false } };
2829
}
2930
var(ida, _) {
30-
ret alt b { lit(_) { false } var(idb, _) { ida == idb } };
31+
ret alt b { var(idb, _) { ida == idb } _ { false } };
32+
}
33+
range(la1, la2) {
34+
ret alt b {
35+
range(lb1, lb2) { lit_eq(la1, lb1) && lit_eq(la2, lb2) }
36+
_ { false }
37+
};
3138
}
3239
}
3340
}
34-
fn trans_opt(bcx: @block_ctxt, o: opt) -> result {
41+
42+
tag opt_result {
43+
single_result(result);
44+
range_result(result, result);
45+
}
46+
fn trans_opt(bcx: @block_ctxt, o: opt) -> opt_result {
3547
alt o {
36-
lit(l) { ret trans::trans_lit(bcx, *l); }
37-
var(id, _) { ret rslt(bcx, C_int(id as int)); }
48+
lit(l) { ret single_result(trans::trans_lit(bcx, *l)); }
49+
var(id, _) { ret single_result(rslt(bcx, C_int(id as int))); }
50+
range(l1, l2) {
51+
let r1 = trans::trans_lit(bcx, *l1);
52+
let r2 = trans::trans_lit(r1.bcx, *l2);
53+
ret range_result(r1, r2);
54+
}
3855
}
3956
}
4057

@@ -124,6 +141,9 @@ fn enter_opt(ccx: @crate_ctxt, m: match, opt: opt, col: uint, tag_size: uint,
124141
ast::pat_lit(l) {
125142
ret if opt_eq(lit(l), opt) { some([]) } else { none };
126143
}
144+
ast::pat_range(l1, l2) {
145+
ret if opt_eq(range(l1, l2), opt) { some([]) } else { none };
146+
}
127147
_ { ret some(vec::init_elt(dummy, size)); }
128148
}
129149
}
@@ -186,6 +206,9 @@ fn get_options(ccx: @crate_ctxt, m: match, col: uint) -> [opt] {
186206
for br: match_branch in m {
187207
alt br.pats[col].node {
188208
ast::pat_lit(l) { add_to_set(found, lit(l)); }
209+
ast::pat_range(l1, l2) {
210+
add_to_set(found, range(l1, l2));
211+
}
189212
ast::pat_tag(_, _) {
190213
add_to_set(found, variant_opt(ccx, br.pats[col].id));
191214
}
@@ -265,7 +288,9 @@ fn pick_col(m: match) -> uint {
265288
let i = 0u;
266289
for p: @ast::pat in br.pats {
267290
alt p.node {
268-
ast::pat_lit(_) | ast::pat_tag(_, _) { scores[i] += 1u; }
291+
ast::pat_lit(_) | ast::pat_tag(_, _) | ast::pat_range(_, _) {
292+
scores[i] += 1u;
293+
}
269294
_ { }
270295
}
271296
i += 1u;
@@ -410,6 +435,16 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail,
410435
_ { test_val = Load(bcx, val); switch }
411436
};
412437
}
438+
range(_, _) {
439+
test_val = Load(bcx, val);
440+
kind = compare;
441+
}
442+
}
443+
}
444+
for o: opt in opts {
445+
alt o {
446+
range(_, _) { kind = compare; break; }
447+
_ { }
413448
}
414449
}
415450
let else_cx =
@@ -428,22 +463,44 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail,
428463
alt kind {
429464
single. { Br(bcx, opt_cx.llbb); }
430465
switch. {
431-
let r = trans_opt(bcx, opt);
432-
bcx = r.bcx;
433-
llvm::LLVMAddCase(sw, r.val, opt_cx.llbb);
466+
let res = trans_opt(bcx, opt);
467+
alt res {
468+
single_result(r) {
469+
llvm::LLVMAddCase(sw, r.val, opt_cx.llbb);
470+
bcx = r.bcx;
471+
}
472+
}
434473
}
435474
compare. {
436475
let compare_cx = new_scope_block_ctxt(bcx, "compare_scope");
437476
Br(bcx, compare_cx.llbb);
438477
bcx = compare_cx;
439-
let r = trans_opt(bcx, opt);
440-
bcx = r.bcx;
441478
let t = ty::node_id_to_type(ccx.tcx, pat_id);
442-
let eq =
443-
trans::trans_compare(bcx, ast::eq, test_val, t, r.val, t);
444-
let cleanup_cx = trans::trans_block_cleanups(bcx, compare_cx);
445-
bcx = new_sub_block_ctxt(bcx, "compare_next");
446-
CondBr(cleanup_cx, eq.val, opt_cx.llbb, bcx.llbb);
479+
let res = trans_opt(bcx, opt);
480+
alt res {
481+
single_result(r) {
482+
bcx = r.bcx;
483+
let eq =
484+
trans::trans_compare(bcx, ast::eq, test_val, t, r.val, t);
485+
/*let*/ bcx = eq.bcx; //XXX uncomment for assertion
486+
let cleanup_cx = trans::trans_block_cleanups(bcx, compare_cx);
487+
bcx = new_sub_block_ctxt(bcx, "compare_next");
488+
CondBr(cleanup_cx, eq.val, opt_cx.llbb, bcx.llbb);
489+
}
490+
range_result(rbegin, rend) {
491+
bcx = rend.bcx;
492+
let ge = trans::trans_compare(bcx, ast::ge, test_val, t,
493+
rbegin.val, t);
494+
let le = trans::trans_compare(ge.bcx, ast::le, test_val, t,
495+
rend.val, t);
496+
let in_range = rslt(le.bcx, And(le.bcx, ge.val, le.val));
497+
/*let*/ bcx = in_range.bcx; //XXX uncomment for assertion
498+
let cleanup_cx =
499+
trans::trans_block_cleanups(bcx, compare_cx);
500+
bcx = new_sub_block_ctxt(bcx, "compare_next");
501+
CondBr(cleanup_cx, in_range.val, opt_cx.llbb, bcx.llbb);
502+
}
503+
}
447504
}
448505
_ { }
449506
}
@@ -456,7 +513,7 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail,
456513
unpacked = args.vals;
457514
opt_cx = args.bcx;
458515
}
459-
lit(_) { }
516+
lit(_) | range(_, _) { }
460517
}
461518
compile_submatch(opt_cx, enter_opt(ccx, m, opt, col, size, val),
462519
unpacked + vals_left, f, exits);
@@ -631,12 +688,13 @@ fn bind_irrefutable_pat(bcx: @block_ctxt, pat: @ast::pat, val: ValueRef,
631688
[C_int(0), C_int(back::abi::box_rc_field_body)]);
632689
bcx = bind_irrefutable_pat(bcx, inner, unboxed, table, true);
633690
}
634-
ast::pat_wild. | ast::pat_lit(_) { }
691+
ast::pat_wild. | ast::pat_lit(_) | ast::pat_range(_, _) { }
635692
}
636693
ret bcx;
637694
}
638695

639696
// Local Variables:
697+
// mode: rust
640698
// fill-column: 78;
641699
// indent-tabs-mode: nil
642700
// c-basic-offset: 4

src/comp/middle/typeck.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,44 @@ fn check_lit(ccx: @crate_ctxt, lit: @ast::lit) -> ty::t {
12661266
}
12671267
}
12681268

1269+
fn lit_as_uint(l: @ast::lit) -> uint {
1270+
alt l.node {
1271+
ast::lit_uint(u) { u }
1272+
ast::lit_char(c) { c as uint }
1273+
}
1274+
}
1275+
fn lit_as_int(l: @ast::lit) -> int {
1276+
alt l.node {
1277+
ast::lit_int(i) | ast::lit_mach_int(_, i) { i }
1278+
}
1279+
}
1280+
fn lit_as_float(l: @ast::lit) -> str {
1281+
alt l.node {
1282+
ast::lit_float(f) | ast::lit_mach_float(_, f) { f }
1283+
}
1284+
}
1285+
1286+
fn valid_range_bounds(l1: @ast::lit, l2: @ast::lit) -> bool {
1287+
alt l1.node {
1288+
ast::lit_float(s1) | ast::lit_mach_float(_, s1) {
1289+
let s2 = lit_as_float(l2);
1290+
let f1 = util::common::str_to_float(s1);
1291+
let f2 = util::common::str_to_float(s2);
1292+
ret *util::common::min(f1, f2) == f1
1293+
}
1294+
ast::lit_uint(_) | ast::lit_char(_) {
1295+
let u1 = lit_as_uint(l1);
1296+
let u2 = lit_as_uint(l2);
1297+
ret *util::common::min(u1, u2) == u1
1298+
}
1299+
_ {
1300+
let i1 = lit_as_int(l1);
1301+
let i2 = lit_as_int(l2);
1302+
ret *util::common::min(i1, i2) == i1
1303+
}
1304+
}
1305+
}
1306+
12691307
// Pattern checking is top-down rather than bottom-up so that bindings get
12701308
// their types immediately.
12711309
fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat,
@@ -1277,6 +1315,23 @@ fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat,
12771315
typ = demand::simple(fcx, pat.span, expected, typ);
12781316
write::ty_only_fixup(fcx, pat.id, typ);
12791317
}
1318+
ast::pat_range(begin, end) {
1319+
if !util::common::lit_is_numeric(begin) ||
1320+
!util::common::lit_is_numeric(end) {
1321+
fcx.ccx.tcx.sess.span_err(pat.span,
1322+
"non-numeric type used in range");
1323+
} else if !valid_range_bounds(begin, end) {
1324+
fcx.ccx.tcx.sess.span_err(begin.span,
1325+
"lower range bound must be less \
1326+
than upper");
1327+
}
1328+
let typ1 = check_lit(fcx.ccx, begin);
1329+
typ1 = demand::simple(fcx, pat.span, expected, typ1);
1330+
write::ty_only_fixup(fcx, pat.id, typ1);
1331+
let typ2 = check_lit(fcx.ccx, end);
1332+
typ2 = demand::simple(fcx, pat.span, typ1, typ2);
1333+
write::ty_only_fixup(fcx, pat.id, typ2);
1334+
}
12801335
ast::pat_bind(name) {
12811336
let vid = lookup_local(fcx, pat.span, pat.id);
12821337
let typ = ty::mk_var(fcx.ccx.tcx, vid);

src/comp/syntax/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ tag pat_ {
9292
pat_rec([field_pat], bool);
9393
pat_tup([@pat]);
9494
pat_box(@pat);
95+
pat_range(@lit, @lit);
9596
}
9697

9798
tag mutability { mut; imm; maybe_mut; }

src/comp/syntax/ast_util.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ iter pat_bindings(pat: @pat) -> @pat {
6969
for elt in elts { for each b in pat_bindings(elt) { put b; } }
7070
}
7171
pat_box(sub) { for each b in pat_bindings(sub) { put b; } }
72-
pat_wild. | pat_lit(_) { }
72+
pat_wild. | pat_lit(_) | pat_range(_, _) { }
7373
}
7474
}
7575

@@ -229,3 +229,4 @@ fn ret_by_ref(style: ret_style) -> bool {
229229
// buffer-file-coding-system: utf-8-unix
230230
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
231231
// End:
232+

src/comp/syntax/fold.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ fn noop_fold_pat(p: pat_, fld: ast_fold) -> pat_ {
291291
}
292292
pat_tup(elts) { pat_tup(vec::map(fld.fold_pat, elts)) }
293293
pat_box(inner) { pat_box(fld.fold_pat(inner)) }
294+
pat_range(_, _) { p }
294295
};
295296
}
296297

src/comp/syntax/parse/parser.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,8 +1494,14 @@ fn parse_pat(p: parser) -> @ast::pat {
14941494
tok {
14951495
if !is_ident(tok) || is_word(p, "true") || is_word(p, "false") {
14961496
let lit = parse_lit(p);
1497-
hi = lit.span.hi;
1498-
pat = ast::pat_lit(@lit);
1497+
if eat_word(p, "to") {
1498+
let end = parse_lit(p);
1499+
hi = end.span.hi;
1500+
pat = ast::pat_range(@lit, @end);
1501+
} else {
1502+
hi = lit.span.hi;
1503+
pat = ast::pat_lit(@lit);
1504+
}
14991505
} else if is_plain_ident(p) &&
15001506
alt p.look_ahead(1u) {
15011507
token::DOT. | token::LPAREN. | token::LBRACKET. {

src/comp/syntax/print/pprust.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,12 @@ fn print_pat(s: ps, pat: @ast::pat) {
11131113
pclose(s);
11141114
}
11151115
ast::pat_box(inner) { word(s.s, "@"); print_pat(s, inner); }
1116+
ast::pat_range(begin, end) {
1117+
print_literal(s, begin);
1118+
space(s.s);
1119+
word_space(s, "to");
1120+
print_literal(s, end);
1121+
}
11161122
}
11171123
s.ann.post(ann_node);
11181124
}

0 commit comments

Comments
 (0)