From 09269abb3d2f1d6c402046a1a4d7e46b657cbad5 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 23 Feb 2011 23:48:01 -0500 Subject: [PATCH 01/16] Begin implementing #fmt in rustc --- src/comp/front/ast.rs | 13 +++- src/comp/front/extfmt.rs | 84 +++++++++++++++++++++++ src/comp/front/parser.rs | 35 +++++++++- src/comp/rustc.rc | 1 + src/test/run-pass/syntax-extension-fmt.rs | 12 +++- 5 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 src/comp/front/extfmt.rs diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 9b995f9ad94a3..27b1ee16681ef 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -185,7 +185,7 @@ tag expr_ { expr_field(@expr, ident, ann); expr_index(@expr, @expr, ann); expr_path(path, option.t[def], ann); - expr_ext(path, vec[@expr], option.t[@expr], ann); + expr_ext(path, vec[@expr], option.t[@expr], option.t[@expr], ann); expr_fail; expr_ret(option.t[@expr]); expr_put(option.t[@expr]); @@ -362,6 +362,17 @@ fn is_call_expr(@expr e) -> bool { } } +fn is_ext_expr(@expr e) -> bool { + alt (e.node) { + case (expr_ext(_, _, _, _, _)) { + ret true; + } + case (_) { + ret false; + } + } +} + // // Local Variables: // mode: rust diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs new file mode 100644 index 0000000000000..cb70805a335cd --- /dev/null +++ b/src/comp/front/extfmt.rs @@ -0,0 +1,84 @@ +/* The 'fmt' extension is modeled on the posix printf system. + * + * A posix conversion ostensibly looks like this: + * + * %[parameter][flags][width][.precision][length]type + * + * Given the different numeric type bestiary we have, we omit the 'length' + * parameter and support slightly different conversions for 'type': + * + * %[parameter][flags][width][.precision]type + * + * we also only support translating-to-rust a tiny subset of the possible + * combinations at the moment. + */ + +use std; + +import std.option; + +tag signedness { + signed; + unsigned; +} + +tag caseness { + case_upper; + case_lower; +} + +tag ty { + ty_bool; + ty_str; + ty_char; + ty_int(signedness); + ty_bits; + ty_hex(caseness); + // FIXME: More types +} + +tag flag { + flag_left_justify; + flag_left_zero_pad; + flag_left_space_pad; + flag_plus_if_positive; + flag_alternate; +} + +tag count { + count_is(int); + count_is_param(int); + count_is_next_param; + count_implied; +} + +// A formatted conversion from an expression to a string +tag conv { + conv_param(option.t[int]); + conv_flags(vec[flag]); + conv_width(count); + conv_precision(count); + conv_ty(ty); +} + +// A fragment of the output sequence +tag piece { + piece_string(str); + piece_conv(str); +} + +fn expand_syntax_ext(vec[@ast.expr] args, + option.t[@ast.expr] body) -> @ast.expr { + fail; +} + +// +// 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 32bcf6efe7682..d32ed4997867b 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -635,7 +635,10 @@ impure fn parse_bottom_expr(parser p) -> @ast.expr { some(token.COMMA), pf, p); hi = es.span; - ex = ast.expr_ext(pth, es.node, none[@ast.expr], ast.ann_none); + ex = ast.expr_ext(pth, es.node, none[@ast.expr], + none[@ast.expr], ast.ann_none); + // FIXME: Here is probably not the right place for this + ex = expand_syntax_ext(p, @spanned(lo, hi, ex)).node; } case (token.FAIL) { @@ -715,6 +718,36 @@ impure fn parse_bottom_expr(parser p) -> @ast.expr { ret @spanned(lo, hi, ex); } +/* + * FIXME: This is a crude approximation of the syntax-extension system, + * for purposes of prototyping and/or hard-wiring any extensions we + * wish to use while bootstrapping. The eventual aim is to permit + * loading rust crates to process extensions, but this will likely + * require a rust-based frontend, or an ocaml-FFI-based connection to + * rust crates. At the moment we have neither. + */ + +impure fn expand_syntax_ext(parser p, @ast.expr ext) -> @ast.expr { + check (ast.is_ext_expr(ext)); + alt (ext.node) { + case (ast.expr_ext(?path, ?args, ?body, _, ?ann)) { + check (_vec.len[ast.ident](path.node.idents) > 0u); + auto extname = path.node.idents.(0); + if (_str.eq(extname, "fmt")) { + auto expanded = extfmt.expand_syntax_ext(args, body); + check (ast.is_ext_expr(expanded)); + auto newexpr = ast.expr_ext(path, args, body, + some[@ast.expr](expanded), ann); + + ret @spanned(ext.span, ext.span, newexpr); + } else { + p.err("unknown syntax extension"); + } + } + } + fail; +} + impure fn extend_expr_by_ident(parser p, span lo, span hi, @ast.expr e, ast.ident i) -> @ast.expr { auto e_ = e.node; diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index bc4aaa52c1aef..16d24e9b27791 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -5,6 +5,7 @@ use std; mod front { mod ast; + mod extfmt; mod lexer; mod parser; mod token; diff --git a/src/test/run-pass/syntax-extension-fmt.rs b/src/test/run-pass/syntax-extension-fmt.rs index 65e7647ee8b50..66fe4fd7ce020 100644 --- a/src/test/run-pass/syntax-extension-fmt.rs +++ b/src/test/run-pass/syntax-extension-fmt.rs @@ -1,5 +1,13 @@ use std; +import std._str; + +fn test(str actual, str expected) { + log actual; + log expected; + check (_str.eq(actual, expected)); +} + fn main() { - auto s = #fmt("hello %d friends and %s things", 10, "formatted"); - log s; + test(#fmt("hello %d friends and %s things", 10, "formatted"), + "hello 10 friends and formatted things"); } From 74861823c1f8c290af7a7089b90dd582caf8822f Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 24 Feb 2011 23:22:36 -0500 Subject: [PATCH 02/16] Begin work on #fmt parsing --- src/comp/front/extfmt.rs | 100 +++++++++++++++++++++- src/comp/front/parser.rs | 1 - src/test/run-pass/syntax-extension-fmt.rs | 6 +- 3 files changed, 101 insertions(+), 6 deletions(-) diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index cb70805a335cd..7018ef146f0bf 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -13,8 +13,10 @@ * combinations at the moment. */ -use std; +import front.parser; +import std._str; +import std._vec; import std.option; tag signedness { @@ -64,14 +66,108 @@ tag conv { // A fragment of the output sequence tag piece { piece_string(str); - piece_conv(str); + piece_conv(conv); +} + +fn bad_fmt_call() { + log "malformed #fmt call"; + fail; } fn expand_syntax_ext(vec[@ast.expr] args, option.t[@ast.expr] body) -> @ast.expr { + + if (_vec.len[@ast.expr](args) == 0u) { + bad_fmt_call(); + } + + auto fmt = expr_to_str(args.(0)); + log fmt; + auto pieces = parse_fmt_string(fmt); + ret pieces_to_expr(pieces, args); +} + +fn expr_to_str(@ast.expr expr) -> str { + alt (expr.node) { + case (ast.expr_lit(?l, _)) { + alt (l.node) { + case (ast.lit_str(?s)) { + ret s; + } + } + } + } + bad_fmt_call(); fail; } +fn parse_fmt_string(str s) -> vec[piece] { + let vec[piece] pieces = vec(); + // FIXME: Should be counting codepoints instead of bytes + auto lim = _str.byte_len(s); + auto buf = ""; + + // TODO: This is super ugly + fn flush_buf(str buf, vec[piece] pieces) -> str { + log "flushing"; + if (_str.byte_len(buf) > 0u) { + auto piece = piece_string(buf); + pieces += piece; + } + log "buf:"; + log buf; + log "pieces:"; + for (piece p in pieces) { + alt (p) { + case (piece_string(?s)) { + log s; + } + case (piece_conv(_)) { + log "conv"; + } + } + } + ret ""; + } + + auto i = 0u; + while (i < lim) { + log "step:"; + log i; + auto curr = _str.substr(s, i, 1u); + if (_str.eq(curr, "%")) { + i += 1u; + if (i >= lim) { + log "unterminated conversion at end of string"; + fail; + } + auto curr2 = _str.substr(s, i, 1u); + if (_str.eq(curr2, "%")) { + i += 1u; + } else { + buf = flush_buf(buf, pieces); + } + } else { + buf += curr; + log "buf:"; + log buf; + i += 1u; + } + } + + ret pieces; +} + +fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr { + auto lo = args.(0).span; + auto hi = args.(0).span; + auto strlit = ast.lit_str("TODO"); + auto spstrlit = @parser.spanned[ast.lit_](lo, hi, strlit); + auto expr = ast.expr_lit(spstrlit, ast.ann_none); + auto spexpr = @parser.spanned[ast.expr_](lo, hi, expr); + ret spexpr; +} + // // Local Variables: // mode: rust diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index d32ed4997867b..cea8aa16d4994 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -735,7 +735,6 @@ impure fn expand_syntax_ext(parser p, @ast.expr ext) -> @ast.expr { auto extname = path.node.idents.(0); if (_str.eq(extname, "fmt")) { auto expanded = extfmt.expand_syntax_ext(args, body); - check (ast.is_ext_expr(expanded)); auto newexpr = ast.expr_ext(path, args, body, some[@ast.expr](expanded), ann); diff --git a/src/test/run-pass/syntax-extension-fmt.rs b/src/test/run-pass/syntax-extension-fmt.rs index 66fe4fd7ce020..a0f51c27ace32 100644 --- a/src/test/run-pass/syntax-extension-fmt.rs +++ b/src/test/run-pass/syntax-extension-fmt.rs @@ -1,10 +1,10 @@ -use std; -import std._str; +//use std; +//import std._str; fn test(str actual, str expected) { log actual; log expected; - check (_str.eq(actual, expected)); + //check (_str.eq(actual, expected)); } fn main() { From aa7abd7059df8999417b6ba2a625554613efc23c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 26 Feb 2011 20:51:02 -0500 Subject: [PATCH 03/16] Add fold, typecheck and trans for expr_ext --- src/comp/middle/fold.rs | 24 +++++++++++++++++++++++ src/comp/middle/trans.rs | 8 ++++++++ src/comp/middle/ty.rs | 1 + src/comp/middle/typeck.rs | 14 +++++++++++++ src/test/run-pass/syntax-extension-fmt.rs | 5 +++-- 5 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/comp/middle/fold.rs b/src/comp/middle/fold.rs index 65bbe602b7d68..64e5962dc5526 100644 --- a/src/comp/middle/fold.rs +++ b/src/comp/middle/fold.rs @@ -154,6 +154,12 @@ type ast_fold[ENV] = &option.t[def] d, ann a) -> @expr) fold_expr_path, + (fn(&ENV e, &span sp, + &path p, vec[@expr] args, + option.t[@expr] body, + option.t[@expr] expanded, + ann a) -> @expr) fold_expr_ext, + (fn(&ENV e, &span sp) -> @expr) fold_expr_fail, (fn(&ENV e, &span sp, @@ -643,6 +649,15 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr { ret fld.fold_expr_path(env_, e.span, p_, r, t); } + case (ast.expr_ext(?p, ?args, ?body, ?expanded, ?t)) { + // Only fold the expanded expression, not the + // expressions involved in syntax extension + auto exp = option.get[@expr](expanded); + auto exp_ = fold_expr(env_, fld, exp); + ret fld.fold_expr_ext(env_, e.span, p, args, body, + some[@ast.expr](exp_), t); + } + case (ast.expr_fail) { ret fld.fold_expr_fail(env_, e.span); } @@ -1158,6 +1173,14 @@ fn identity_fold_expr_path[ENV](&ENV env, &span sp, ret @respan(sp, ast.expr_path(p, d, a)); } +fn identity_fold_expr_ext[ENV](&ENV env, &span sp, + &path p, vec[@expr] args, + option.t[@expr] body, + option.t[@expr] expanded, + ann a) -> @expr { + ret @respan(sp, ast.expr_ext(p, args, body, expanded, a)); +} + fn identity_fold_expr_fail[ENV](&ENV env, &span sp) -> @expr { ret @respan(sp, ast.expr_fail); } @@ -1438,6 +1461,7 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] { fold_expr_field = bind identity_fold_expr_field[ENV](_,_,_,_,_), fold_expr_index = bind identity_fold_expr_index[ENV](_,_,_,_,_), fold_expr_path = bind identity_fold_expr_path[ENV](_,_,_,_,_), + fold_expr_ext = bind identity_fold_expr_ext[ENV](_,_,_,_,_,_,_), fold_expr_fail = bind identity_fold_expr_fail[ENV](_,_), fold_expr_ret = bind identity_fold_expr_ret[ENV](_,_,_), fold_expr_put = bind identity_fold_expr_put[ENV](_,_,_), diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index fb916f00848cb..58497217cd713 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -1861,6 +1861,8 @@ fn trans_lit(@crate_ctxt cx, &ast.lit lit, &ast.ann ann) -> ValueRef { ret C_nil(); } case (ast.lit_str(?s)) { + log "translating literal:"; + log s; ret C_str(cx, s); } } @@ -3362,6 +3364,7 @@ fn trans_rec(@block_ctxt cx, vec[ast.field] fields, fn trans_expr(@block_ctxt cx, @ast.expr e) -> result { alt (e.node) { case (ast.expr_lit(?lit, ?ann)) { + log "translating literal"; ret res(cx, trans_lit(cx.fcx.ccx, *lit, ann)); } @@ -3456,6 +3459,11 @@ fn trans_expr(@block_ctxt cx, @ast.expr e) -> result { ret trans_rec(cx, args, base, ann); } + case (ast.expr_ext(_, _, _, ?expanded, _)) { + log "translating extension"; + ret trans_expr(cx, option.get[@ast.expr](expanded)); + } + case (ast.expr_fail) { ret trans_fail(cx, e.span, "explicit failure"); } diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 25ef8709eccea..ed251cf3cc773 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -742,6 +742,7 @@ fn expr_ty(@ast.expr expr) -> @t { case (ast.expr_field(_, _, ?ann)) { ret ann_to_type(ann); } case (ast.expr_index(_, _, ?ann)) { ret ann_to_type(ann); } case (ast.expr_path(_, _, ?ann)) { ret ann_to_type(ann); } + case (ast.expr_ext(_, _, _, _, ?ann)) { ret ann_to_type(ann); } case (ast.expr_fail) { ret plain_ty(ty_nil); } case (ast.expr_log(_)) { ret plain_ty(ty_nil); } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index ce1c59ec01f78..5cccc4d7ef8bc 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1156,6 +1156,11 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e, ann_to_type(ann), adk); e_1 = ast.expr_path(pth, d, ast.ann_type(t)); } + case (ast.expr_ext(?p, ?args, ?body, ?expanded, ?ann)) { + auto t = demand_full(fcx, e.span, expected, + ann_to_type(ann), adk); + e_1 = ast.expr_ext(p, args, body, expanded, ast.ann_type(t)); + } case (ast.expr_fail) { e_1 = e.node; } case (ast.expr_log(_)) { e_1 = e.node; } case (ast.expr_ret(_)) { e_1 = e.node; } @@ -1508,6 +1513,15 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr { ast.ann_type(t))); } + case (ast.expr_ext(?p, ?args, ?body, ?expanded, _)) { + auto exp_ = check_expr(fcx, option.get[@ast.expr](expanded)); + auto t = expr_ty(exp_); + ret @fold.respan[ast.expr_](expr.span, + ast.expr_ext(p, args, body, + some[@ast.expr](exp_), + ast.ann_type(t))); + } + case (ast.expr_fail) { ret expr; } diff --git a/src/test/run-pass/syntax-extension-fmt.rs b/src/test/run-pass/syntax-extension-fmt.rs index a0f51c27ace32..0d1d708297f20 100644 --- a/src/test/run-pass/syntax-extension-fmt.rs +++ b/src/test/run-pass/syntax-extension-fmt.rs @@ -8,6 +8,7 @@ fn test(str actual, str expected) { } fn main() { - test(#fmt("hello %d friends and %s things", 10, "formatted"), - "hello 10 friends and formatted things"); + /*test(#fmt("hello %d friends and %s things", 10, "formatted"), + "hello 10 friends and formatted things");*/ + log #fmt("test"); } From b12a820368d4434c1a7bbc4035ef3b6ec7d8784d Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 27 Feb 2011 14:30:44 -0500 Subject: [PATCH 04/16] Parse parameter types for fmt extension --- src/comp/front/extfmt.rs | 148 ++++++++++++++++++---- src/comp/middle/trans.rs | 4 - src/rt/memory_region.cpp | 2 +- src/test/run-pass/syntax-extension-fmt.rs | 11 +- 4 files changed, 126 insertions(+), 39 deletions(-) diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index 7018ef146f0bf..998bfa4de433c 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -18,6 +18,8 @@ import front.parser; import std._str; import std._vec; import std.option; +import std.option.none; +import std.option.some; tag signedness { signed; @@ -55,13 +57,11 @@ tag count { } // A formatted conversion from an expression to a string -tag conv { - conv_param(option.t[int]); - conv_flags(vec[flag]); - conv_width(count); - conv_precision(count); - conv_ty(ty); -} +type conv = rec(option.t[int] param, + vec[flag] flags, + count width, + count precision, + ty typ); // A fragment of the output sequence tag piece { @@ -84,6 +84,18 @@ fn expand_syntax_ext(vec[@ast.expr] args, auto fmt = expr_to_str(args.(0)); log fmt; auto pieces = parse_fmt_string(fmt); + log "printing all pieces"; + for (piece p in pieces) { + alt (p) { + case (piece_string(?s)) { + log s; + } + case (piece_conv(_)) { + log "conv"; + } + } + } + log "done printing all pieces"; ret pieces_to_expr(pieces, args); } @@ -107,33 +119,16 @@ fn parse_fmt_string(str s) -> vec[piece] { auto lim = _str.byte_len(s); auto buf = ""; - // TODO: This is super ugly - fn flush_buf(str buf, vec[piece] pieces) -> str { - log "flushing"; + fn flush_buf(str buf, &vec[piece] pieces) -> str { if (_str.byte_len(buf) > 0u) { auto piece = piece_string(buf); pieces += piece; } - log "buf:"; - log buf; - log "pieces:"; - for (piece p in pieces) { - alt (p) { - case (piece_string(?s)) { - log s; - } - case (piece_conv(_)) { - log "conv"; - } - } - } ret ""; } auto i = 0u; while (i < lim) { - log "step:"; - log i; auto curr = _str.substr(s, i, 1u); if (_str.eq(curr, "%")) { i += 1u; @@ -146,18 +141,115 @@ fn parse_fmt_string(str s) -> vec[piece] { i += 1u; } else { buf = flush_buf(buf, pieces); + auto res = parse_conversion(s, i, lim); + pieces += res._0; + i = res._1; } } else { buf += curr; - log "buf:"; - log buf; i += 1u; } } - + buf = flush_buf(buf, pieces); ret pieces; } +fn peek_num(str s, uint i, uint lim) -> option.t[tup(int, int)] { + if (i >= lim) { + ret none[tup(int, int)]; + } else { + ret none[tup(int, int)]; + /*if ('0' <= c && c <= '9') { + log c; + fail; + } else { + ret option.none[tup(int, int)]; + } + */ + } +} + +fn parse_conversion(str s, uint i, uint lim) -> tup(piece, uint) { + auto parm = parse_parameter(s, i, lim); + auto flags = parse_flags(s, parm._1, lim); + auto width = parse_width(s, flags._1, lim); + auto prec = parse_precision(s, width._1, lim); + auto ty = parse_type(s, prec._1, lim); + ret tup(piece_conv(rec(param = parm._0, + flags = flags._0, + width = width._0, + precision = prec._0, + typ = ty._0)), + ty._1); +} + +fn parse_parameter(str s, uint i, uint lim) -> tup(option.t[int], uint) { + if (i >= lim) { + ret tup(none[int], i); + } + + auto num = peek_num(s, i, lim); + alt (num) { + case (none[tup(int, int)]) { + ret tup(none[int], i); + } + case (some[tup(int, int)](?t)) { + fail; + } + } +} + +fn parse_flags(str s, uint i, uint lim) -> tup(vec[flag], uint) { + let vec[flag] flags = vec(); + ret tup(flags, i); +} + +fn parse_width(str s, uint i, uint lim) -> tup(count, uint) { + ret tup(count_implied, i); +} + +fn parse_precision(str s, uint i, uint lim) -> tup(count, uint) { + ret tup(count_implied, i); +} + +fn parse_type(str s, uint i, uint lim) -> tup(ty, uint) { + if (i >= lim) { + log "missing type in conversion"; + fail; + } + + auto t; + auto tstr = _str.substr(s, i, 1u); + if (_str.eq(tstr, "b")) { + t = ty_bool; + } else if (_str.eq(tstr, "s")) { + t = ty_str; + } else if (_str.eq(tstr, "c")) { + t = ty_char; + } else if (_str.eq(tstr, "d") + || _str.eq(tstr, "i")) { + // TODO: Do we really want two signed types here? + // How important is it to be printf compatible? + t = ty_int(signed); + } else if (_str.eq(tstr, "u")) { + t = ty_int(unsigned); + } else if (_str.eq(tstr, "x")) { + t = ty_hex(case_lower); + } else if (_str.eq(tstr, "X")) { + t = ty_hex(case_upper); + } else if (_str.eq(tstr, "t")) { + t = ty_bits; + } else { + // FIXME: This is a hack to avoid 'unsatisfied precondition + // constraint' on uninitialized variable t below + t = ty_bool; + log "unknown type in conversion"; + fail; + } + + ret tup(t, i + 1u); +} + fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr { auto lo = args.(0).span; auto hi = args.(0).span; diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 58497217cd713..21884da52772d 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -1861,8 +1861,6 @@ fn trans_lit(@crate_ctxt cx, &ast.lit lit, &ast.ann ann) -> ValueRef { ret C_nil(); } case (ast.lit_str(?s)) { - log "translating literal:"; - log s; ret C_str(cx, s); } } @@ -3364,7 +3362,6 @@ fn trans_rec(@block_ctxt cx, vec[ast.field] fields, fn trans_expr(@block_ctxt cx, @ast.expr e) -> result { alt (e.node) { case (ast.expr_lit(?lit, ?ann)) { - log "translating literal"; ret res(cx, trans_lit(cx.fcx.ccx, *lit, ann)); } @@ -3460,7 +3457,6 @@ fn trans_expr(@block_ctxt cx, @ast.expr e) -> result { } case (ast.expr_ext(_, _, _, ?expanded, _)) { - log "translating extension"; ret trans_expr(cx, option.get[@ast.expr](expanded)); } diff --git a/src/rt/memory_region.cpp b/src/rt/memory_region.cpp index 7ede3761e9a3e..fb19620f8b951 100644 --- a/src/rt/memory_region.cpp +++ b/src/rt/memory_region.cpp @@ -1,7 +1,7 @@ #include "rust_internal.h" #include "memory_region.h" -// #define TRACK_ALLOCATIONS +#define TRACK_ALLOCATIONS memory_region::memory_region(rust_srv *srv, bool synchronized) : _srv(srv), _parent(NULL), _live_allocations(0), diff --git a/src/test/run-pass/syntax-extension-fmt.rs b/src/test/run-pass/syntax-extension-fmt.rs index 0d1d708297f20..b7076c8176d3c 100644 --- a/src/test/run-pass/syntax-extension-fmt.rs +++ b/src/test/run-pass/syntax-extension-fmt.rs @@ -1,14 +1,13 @@ -//use std; -//import std._str; +use std; +import std._str; fn test(str actual, str expected) { log actual; log expected; - //check (_str.eq(actual, expected)); + check (_str.eq(actual, expected)); } fn main() { - /*test(#fmt("hello %d friends and %s things", 10, "formatted"), - "hello 10 friends and formatted things");*/ - log #fmt("test"); + test(#fmt("hello %d friends and %s things", 10, "formatted"), + "hello 10 friends and formatted things"); } From 016aef09c35ef0d95d90f24f726ed4475cd3f232 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 27 Feb 2011 15:29:31 -0500 Subject: [PATCH 05/16] Rewrite expand_syntax_ext to avoid a mysterious memory leak --- src/comp/front/parser.rs | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index cea8aa16d4994..4b00050021679 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -635,10 +635,8 @@ impure fn parse_bottom_expr(parser p) -> @ast.expr { some(token.COMMA), pf, p); hi = es.span; - ex = ast.expr_ext(pth, es.node, none[@ast.expr], - none[@ast.expr], ast.ann_none); - // FIXME: Here is probably not the right place for this - ex = expand_syntax_ext(p, @spanned(lo, hi, ex)).node; + ex = expand_syntax_ext(p, es.span, pth, es.node, + none[@ast.expr]); } case (token.FAIL) { @@ -727,24 +725,23 @@ impure fn parse_bottom_expr(parser p) -> @ast.expr { * rust crates. At the moment we have neither. */ -impure fn expand_syntax_ext(parser p, @ast.expr ext) -> @ast.expr { - check (ast.is_ext_expr(ext)); - alt (ext.node) { - case (ast.expr_ext(?path, ?args, ?body, _, ?ann)) { - check (_vec.len[ast.ident](path.node.idents) > 0u); - auto extname = path.node.idents.(0); - if (_str.eq(extname, "fmt")) { - auto expanded = extfmt.expand_syntax_ext(args, body); - auto newexpr = ast.expr_ext(path, args, body, - some[@ast.expr](expanded), ann); - - ret @spanned(ext.span, ext.span, newexpr); - } else { - p.err("unknown syntax extension"); - } - } +impure fn expand_syntax_ext(parser p, ast.span sp, + &ast.path path, vec[@ast.expr] args, + option.t[@ast.expr] body) -> ast.expr_ { + + check (_vec.len[ast.ident](path.node.idents) > 0u); + auto extname = path.node.idents.(0); + if (_str.eq(extname, "fmt")) { + auto expanded = extfmt.expand_syntax_ext(args, body); + auto newexpr = ast.expr_ext(path, args, body, + some[@ast.expr](expanded), + ast.ann_none); + + ret newexpr; + } else { + p.err("unknown syntax extension"); + fail; } - fail; } impure fn extend_expr_by_ident(parser p, span lo, span hi, From e979943da7a253832864dc93663a29c3eacd03a1 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 27 Feb 2011 18:22:54 -0500 Subject: [PATCH 06/16] Begin an AST pretty-printer --- src/comp/front/pretty.rs | 51 ++++++++++++++++++++++++++++++++++++++++ src/comp/rustc.rc | 1 + 2 files changed, 52 insertions(+) create mode 100644 src/comp/front/pretty.rs diff --git a/src/comp/front/pretty.rs b/src/comp/front/pretty.rs new file mode 100644 index 0000000000000..8e5414eecbbf8 --- /dev/null +++ b/src/comp/front/pretty.rs @@ -0,0 +1,51 @@ +use std; + +fn unknown() -> str { + ret ""; +} + +fn print_expr(@ast.expr expr) -> str { + alt (expr.node) { + case (ast.expr_lit(?lit, _)) { + ret print_expr_lit(lit); + } + case (ast.expr_binary(?op, ?lhs, ?rhs, _)) { + ret print_expr_binary(op, lhs, rhs); + } + case (_) { + ret unknown(); + } + } +} + +fn print_expr_lit(@ast.lit lit) -> str { + alt (lit.node) { + case (ast.lit_str(?s)) { + ret "\"" + s + "\""; + } + case (_) { + ret unknown(); + } + } +} + +fn print_expr_binary(ast.binop op, @ast.expr lhs, @ast.expr rhs) -> str { + alt (op) { + case (ast.add) { + auto l = print_expr(lhs); + auto r = print_expr(rhs); + ret l + " + " + r; + } + } +} + +// +// 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/rustc.rc b/src/comp/rustc.rc index 16d24e9b27791..43a0411768085 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -8,6 +8,7 @@ mod front { mod extfmt; mod lexer; mod parser; + mod pretty; mod token; mod eval; } From c516b532759557cc45b6f00a0b4e452d8c909158 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 27 Feb 2011 18:23:16 -0500 Subject: [PATCH 07/16] Start generating AST nodes for #fmt --- src/comp/front/extfmt.rs | 42 ++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index 998bfa4de433c..38c2ea8cb8970 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -13,7 +13,7 @@ * combinations at the moment. */ -import front.parser; +import util.common; import std._str; import std._vec; @@ -251,13 +251,39 @@ fn parse_type(str s, uint i, uint lim) -> tup(ty, uint) { } fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr { - auto lo = args.(0).span; - auto hi = args.(0).span; - auto strlit = ast.lit_str("TODO"); - auto spstrlit = @parser.spanned[ast.lit_](lo, hi, strlit); - auto expr = ast.expr_lit(spstrlit, ast.ann_none); - auto spexpr = @parser.spanned[ast.expr_](lo, hi, expr); - ret spexpr; + + fn make_new_str(common.span sp, str s) -> @ast.expr { + auto strlit = ast.lit_str(s); + auto spstrlit = @parser.spanned[ast.lit_](sp, sp, strlit); + auto expr = ast.expr_lit(spstrlit, ast.ann_none); + ret @parser.spanned[ast.expr_](sp, sp, expr); + } + + fn make_add_expr(common.span sp, + @ast.expr lhs, @ast.expr rhs) -> @ast.expr { + auto binexpr = ast.expr_binary(ast.add, lhs, rhs, ast.ann_none); + ret @parser.spanned[ast.expr_](sp, sp, binexpr); + } + + auto sp = args.(0).span; + auto n = 0; + auto tmp_expr = make_new_str(sp, "whatever"); + + for (piece p in pieces) { + alt (p) { + case (piece_string(?s)) { + auto s_expr = make_new_str(sp, s); + tmp_expr = make_add_expr(sp, tmp_expr, s_expr); + } + case (piece_conv(?conv)) { + } + } + } + + // TODO: Remove this print and return the real expanded AST + log "dumping expanded ast:"; + log pretty.print_expr(tmp_expr); + ret make_new_str(sp, "TODO"); } // From ae7c0a0997737b2999fcd505ec6159c2099e6565 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 27 Feb 2011 19:44:57 -0500 Subject: [PATCH 08/16] Implement #fmt conversion for int and uint --- src/comp/front/extfmt.rs | 115 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 8 deletions(-) diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index 38c2ea8cb8970..bd5bab5b7ae1a 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -21,6 +21,8 @@ import std.option; import std.option.none; import std.option.some; +export expand_syntax_ext; + tag signedness { signed; unsigned; @@ -61,7 +63,7 @@ type conv = rec(option.t[int] param, vec[flag] flags, count width, count precision, - ty typ); + ty ty); // A fragment of the output sequence tag piece { @@ -74,6 +76,7 @@ fn bad_fmt_call() { fail; } +// TODO: Need to thread parser through here to handle errors correctly fn expand_syntax_ext(vec[@ast.expr] args, option.t[@ast.expr] body) -> @ast.expr { @@ -96,6 +99,8 @@ fn expand_syntax_ext(vec[@ast.expr] args, } } log "done printing all pieces"; + auto args_len = _vec.len[@ast.expr](args); + auto fmt_args = _vec.slice[@ast.expr](args, 1u, args_len - 1u); ret pieces_to_expr(pieces, args); } @@ -179,7 +184,7 @@ fn parse_conversion(str s, uint i, uint lim) -> tup(piece, uint) { flags = flags._0, width = width._0, precision = prec._0, - typ = ty._0)), + ty = ty._0)), ty._1); } @@ -252,22 +257,107 @@ fn parse_type(str s, uint i, uint lim) -> tup(ty, uint) { fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr { - fn make_new_str(common.span sp, str s) -> @ast.expr { - auto strlit = ast.lit_str(s); - auto spstrlit = @parser.spanned[ast.lit_](sp, sp, strlit); - auto expr = ast.expr_lit(spstrlit, ast.ann_none); + fn make_new_lit(common.span sp, ast.lit_ lit) -> @ast.expr { + auto sp_lit = @parser.spanned[ast.lit_](sp, sp, lit); + auto expr = ast.expr_lit(sp_lit, ast.ann_none); ret @parser.spanned[ast.expr_](sp, sp, expr); } + fn make_new_str(common.span sp, str s) -> @ast.expr { + auto lit = ast.lit_str(s); + ret make_new_lit(sp, lit); + } + + fn make_new_uint(common.span sp, uint u) -> @ast.expr { + auto lit = ast.lit_uint(u); + ret make_new_lit(sp, lit); + } + fn make_add_expr(common.span sp, @ast.expr lhs, @ast.expr rhs) -> @ast.expr { auto binexpr = ast.expr_binary(ast.add, lhs, rhs, ast.ann_none); ret @parser.spanned[ast.expr_](sp, sp, binexpr); } + fn make_call(common.span sp, vec[ast.ident] fn_path, + vec[@ast.expr] args) -> @ast.expr { + let vec[ast.ident] path_idents = fn_path; + let vec[@ast.ty] path_types = vec(); + auto path = rec(idents = path_idents, types = path_types); + auto sp_path = parser.spanned[ast.path_](sp, sp, path); + auto pathexpr = ast.expr_path(sp_path, none[ast.def], ast.ann_none); + auto sp_pathexpr = @parser.spanned[ast.expr_](sp, sp, pathexpr); + auto callexpr = ast.expr_call(sp_pathexpr, args, ast.ann_none); + auto sp_callexpr = @parser.spanned[ast.expr_](sp, sp, callexpr); + ret sp_callexpr; + } + + fn make_new_conv(conv cnv, @ast.expr arg) -> @ast.expr { + + auto unsupported = "conversion not supported in #fmt string"; + + alt (cnv.param) { + case (option.none[int]) { + } + case (_) { + log unsupported; + fail; + } + } + + if (_vec.len[flag](cnv.flags) != 0u) { + log unsupported; + fail; + } + + alt (cnv.width) { + case (count_implied) { + } + case (_) { + log unsupported; + fail; + } + } + + alt (cnv.precision) { + case (count_implied) { + } + case (_) { + log unsupported; + fail; + } + } + + alt (cnv.ty) { + case (ty_str) { + ret arg; + } + case (ty_int(?sign)) { + alt (sign) { + case (signed) { + let vec[str] path = vec("std", "_int", "to_str"); + auto radix_expr = make_new_uint(arg.span, 10u); + let vec[@ast.expr] args = vec(arg, radix_expr); + ret make_call(arg.span, path, args); + } + case (unsigned) { + let vec[str] path = vec("std", "_uint", "to_str"); + auto radix_expr = make_new_uint(arg.span, 10u); + let vec[@ast.expr] args = vec(arg, radix_expr); + ret make_call(arg.span, path, args); + } + } + } + case (_) { + log unsupported; + fail; + } + } + } + auto sp = args.(0).span; - auto n = 0; - auto tmp_expr = make_new_str(sp, "whatever"); + auto n = 0u; + auto tmp_expr = make_new_str(sp, ""); for (piece p in pieces) { alt (p) { @@ -276,6 +366,15 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr { tmp_expr = make_add_expr(sp, tmp_expr, s_expr); } case (piece_conv(?conv)) { + if (n >= _vec.len[@ast.expr](args)) { + log "too many conversions in #fmt string"; + fail; + } + + n += 1u; + auto arg_expr = args.(n); + auto c_expr = make_new_conv(conv, arg_expr); + tmp_expr = make_add_expr(sp, tmp_expr, c_expr); } } } From 58f55cdd24cc774220b51d3052d98e52d08a86b2 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 27 Feb 2011 22:17:59 -0500 Subject: [PATCH 09/16] Remove debug logging from extfmt --- src/comp/front/extfmt.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index bd5bab5b7ae1a..938704b9e51b5 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -85,20 +85,7 @@ fn expand_syntax_ext(vec[@ast.expr] args, } auto fmt = expr_to_str(args.(0)); - log fmt; auto pieces = parse_fmt_string(fmt); - log "printing all pieces"; - for (piece p in pieces) { - alt (p) { - case (piece_string(?s)) { - log s; - } - case (piece_conv(_)) { - log "conv"; - } - } - } - log "done printing all pieces"; auto args_len = _vec.len[@ast.expr](args); auto fmt_args = _vec.slice[@ast.expr](args, 1u, args_len - 1u); ret pieces_to_expr(pieces, args); From f2ce8cfa5a8f88d462684c98bb009e3172f4b483 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 27 Feb 2011 22:18:27 -0500 Subject: [PATCH 10/16] Add more #fmt tests --- src/test/run-pass/syntax-extension-fmt.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/run-pass/syntax-extension-fmt.rs b/src/test/run-pass/syntax-extension-fmt.rs index b7076c8176d3c..ebb09f96ba2c9 100644 --- a/src/test/run-pass/syntax-extension-fmt.rs +++ b/src/test/run-pass/syntax-extension-fmt.rs @@ -10,4 +10,7 @@ fn test(str actual, str expected) { fn main() { test(#fmt("hello %d friends and %s things", 10, "formatted"), "hello 10 friends and formatted things"); + test(#fmt("d: %d", 1), "d: 1"); + test(#fmt("i: %i", 2), "i: 2"); + test(#fmt("s: %s", "test"), "s: test"); } From 941d390a4fd345f0d29c44a37b244412feec9c3b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 27 Feb 2011 22:19:03 -0500 Subject: [PATCH 11/16] Add pretty printing for expr_call, expr_path, and more literals --- src/comp/front/pretty.rs | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/comp/front/pretty.rs b/src/comp/front/pretty.rs index 8e5414eecbbf8..267763e39972c 100644 --- a/src/comp/front/pretty.rs +++ b/src/comp/front/pretty.rs @@ -1,4 +1,9 @@ -use std; +import std._int; +import std._str; +import std._uint; +import std._vec; + +export print_expr; fn unknown() -> str { ret ""; @@ -7,22 +12,34 @@ fn unknown() -> str { fn print_expr(@ast.expr expr) -> str { alt (expr.node) { case (ast.expr_lit(?lit, _)) { - ret print_expr_lit(lit); + ret print_lit(lit); } case (ast.expr_binary(?op, ?lhs, ?rhs, _)) { ret print_expr_binary(op, lhs, rhs); } + case (ast.expr_call(?path, ?args, _)) { + ret print_expr_call(path, args); + } + case (ast.expr_path(?path, _, _)) { + ret print_path(path); + } case (_) { ret unknown(); } } } -fn print_expr_lit(@ast.lit lit) -> str { +fn print_lit(@ast.lit lit) -> str { alt (lit.node) { case (ast.lit_str(?s)) { ret "\"" + s + "\""; } + case (ast.lit_int(?i)) { + ret _int.to_str(i, 10u); + } + case (ast.lit_uint(?u)) { + ret _uint.to_str(u, 10u); + } case (_) { ret unknown(); } @@ -39,6 +56,23 @@ fn print_expr_binary(ast.binop op, @ast.expr lhs, @ast.expr rhs) -> str { } } +fn print_expr_call(@ast.expr path_expr, vec[@ast.expr] args) -> str { + auto s = print_expr(path_expr); + + s += "("; + fn print_expr_ref(&@ast.expr e) -> str { ret print_expr(e); } + auto mapfn = print_expr_ref; + auto argstrs = _vec.map[@ast.expr, str](mapfn, args); + s += _str.connect(argstrs, ", "); + s += ")"; + + ret s; +} + +fn print_path(ast.path path) -> str { + ret _str.connect(path.node.idents, "."); +} + // // Local Variables: // mode: rust From e2767f634ac6975c57256dec6a4ca676d198a130 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 27 Feb 2011 22:35:27 -0500 Subject: [PATCH 12/16] Make the expanded expression in expr_ext not optional --- src/comp/front/ast.rs | 2 +- src/comp/front/parser.rs | 2 +- src/comp/middle/fold.rs | 9 ++++----- src/comp/middle/trans.rs | 2 +- src/comp/middle/typeck.rs | 5 ++--- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 27b1ee16681ef..ddef5e6c5252d 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -185,7 +185,7 @@ tag expr_ { expr_field(@expr, ident, ann); expr_index(@expr, @expr, ann); expr_path(path, option.t[def], ann); - expr_ext(path, vec[@expr], option.t[@expr], option.t[@expr], ann); + expr_ext(path, vec[@expr], option.t[@expr], @expr, ann); expr_fail; expr_ret(option.t[@expr]); expr_put(option.t[@expr]); diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 4b00050021679..fd08e6ed2b4d3 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -734,7 +734,7 @@ impure fn expand_syntax_ext(parser p, ast.span sp, if (_str.eq(extname, "fmt")) { auto expanded = extfmt.expand_syntax_ext(args, body); auto newexpr = ast.expr_ext(path, args, body, - some[@ast.expr](expanded), + expanded, ast.ann_none); ret newexpr; diff --git a/src/comp/middle/fold.rs b/src/comp/middle/fold.rs index 64e5962dc5526..9cccf37912be2 100644 --- a/src/comp/middle/fold.rs +++ b/src/comp/middle/fold.rs @@ -157,7 +157,7 @@ type ast_fold[ENV] = (fn(&ENV e, &span sp, &path p, vec[@expr] args, option.t[@expr] body, - option.t[@expr] expanded, + @expr expanded, ann a) -> @expr) fold_expr_ext, (fn(&ENV e, &span sp) -> @expr) fold_expr_fail, @@ -652,10 +652,9 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr { case (ast.expr_ext(?p, ?args, ?body, ?expanded, ?t)) { // Only fold the expanded expression, not the // expressions involved in syntax extension - auto exp = option.get[@expr](expanded); - auto exp_ = fold_expr(env_, fld, exp); + auto exp = fold_expr(env_, fld, expanded); ret fld.fold_expr_ext(env_, e.span, p, args, body, - some[@ast.expr](exp_), t); + exp, t); } case (ast.expr_fail) { @@ -1176,7 +1175,7 @@ fn identity_fold_expr_path[ENV](&ENV env, &span sp, fn identity_fold_expr_ext[ENV](&ENV env, &span sp, &path p, vec[@expr] args, option.t[@expr] body, - option.t[@expr] expanded, + @expr expanded, ann a) -> @expr { ret @respan(sp, ast.expr_ext(p, args, body, expanded, a)); } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 21884da52772d..7c94955a323f8 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3457,7 +3457,7 @@ fn trans_expr(@block_ctxt cx, @ast.expr e) -> result { } case (ast.expr_ext(_, _, _, ?expanded, _)) { - ret trans_expr(cx, option.get[@ast.expr](expanded)); + ret trans_expr(cx, expanded); } case (ast.expr_fail) { diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 5cccc4d7ef8bc..f8f7fc72719c2 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1514,11 +1514,10 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr { } case (ast.expr_ext(?p, ?args, ?body, ?expanded, _)) { - auto exp_ = check_expr(fcx, option.get[@ast.expr](expanded)); + auto exp_ = check_expr(fcx, expanded); auto t = expr_ty(exp_); ret @fold.respan[ast.expr_](expr.span, - ast.expr_ext(p, args, body, - some[@ast.expr](exp_), + ast.expr_ext(p, args, body, exp_, ast.ann_type(t))); } From f8f6ea19ad9dc07e983fe7c9b27d5e962cfb34ec Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 1 Mar 2011 19:50:27 -0500 Subject: [PATCH 13/16] Remove unused is_ext_expr --- src/comp/front/ast.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index ddef5e6c5252d..4c00df5621177 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -362,17 +362,6 @@ fn is_call_expr(@expr e) -> bool { } } -fn is_ext_expr(@expr e) -> bool { - alt (e.node) { - case (expr_ext(_, _, _, _, _)) { - ret true; - } - case (_) { - ret false; - } - } -} - // // Local Variables: // mode: rust From 8a5576c970a3d98827a0be094328bba980c4a18b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 1 Mar 2011 19:51:21 -0500 Subject: [PATCH 14/16] Whitespace cleanup --- src/comp/front/extfmt.rs | 10 +++++----- src/comp/front/parser.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index 938704b9e51b5..dfeb79de03cb3 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -1,14 +1,14 @@ /* The 'fmt' extension is modeled on the posix printf system. - * + * * A posix conversion ostensibly looks like this: - * + * * %[parameter][flags][width][.precision][length]type - * + * * Given the different numeric type bestiary we have, we omit the 'length' * parameter and support slightly different conversions for 'type': - * + * * %[parameter][flags][width][.precision]type - * + * * we also only support translating-to-rust a tiny subset of the possible * combinations at the moment. */ diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 3874aaf3139cf..a9ffd1267be08 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -723,7 +723,7 @@ impure fn parse_bottom_expr(parser p) -> @ast.expr { ret @spanned(lo, hi, ex); } -/* +/* * FIXME: This is a crude approximation of the syntax-extension system, * for purposes of prototyping and/or hard-wiring any extensions we * wish to use while bootstrapping. The eventual aim is to permit From 27b8daea652eca8dd440a7b2b86c6506a8586c68 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 1 Mar 2011 21:03:44 -0500 Subject: [PATCH 15/16] Add debug logging for #fmt conv. Implement peek_num fn --- src/comp/front/extfmt.rs | 144 +++++++++++++++++++++++++++++++++------ 1 file changed, 123 insertions(+), 21 deletions(-) diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index dfeb79de03cb3..5ca50c051decf 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -71,17 +71,13 @@ tag piece { piece_conv(conv); } -fn bad_fmt_call() { - log "malformed #fmt call"; - fail; -} - // TODO: Need to thread parser through here to handle errors correctly fn expand_syntax_ext(vec[@ast.expr] args, option.t[@ast.expr] body) -> @ast.expr { if (_vec.len[@ast.expr](args) == 0u) { - bad_fmt_call(); + log "malformed #fmt call"; + fail; } auto fmt = expr_to_str(args.(0)); @@ -101,7 +97,7 @@ fn expr_to_str(@ast.expr expr) -> str { } } } - bad_fmt_call(); + log "malformed #fmt call"; fail; } @@ -146,19 +142,29 @@ fn parse_fmt_string(str s) -> vec[piece] { ret pieces; } -fn peek_num(str s, uint i, uint lim) -> option.t[tup(int, int)] { +fn peek_num(str s, uint i, uint lim) -> option.t[tup(uint, uint)] { if (i >= lim) { - ret none[tup(int, int)]; - } else { - ret none[tup(int, int)]; - /*if ('0' <= c && c <= '9') { - log c; - fail; - } else { - ret option.none[tup(int, int)]; + ret none[tup(uint, uint)]; + } + + // FIXME: Presumably s.(i) will return char eventually + auto c = s.(i); + if (!('0' as u8 <= c && c <= '9' as u8)) { + ret option.none[tup(uint, uint)]; + } + + auto n = (c - ('0' as u8)) as uint; + alt (peek_num(s, i + 1u, lim)) { + case (none[tup(uint, uint)]) { + ret some[tup(uint, uint)](tup(n, i + 1u)); + } + case (some[tup(uint, uint)](?next)) { + auto m = next._0; + auto j = next._1; + ret some[tup(uint, uint)](tup(n * 10u + m, j)); } - */ } + } fn parse_conversion(str s, uint i, uint lim) -> tup(piece, uint) { @@ -182,10 +188,10 @@ fn parse_parameter(str s, uint i, uint lim) -> tup(option.t[int], uint) { auto num = peek_num(s, i, lim); alt (num) { - case (none[tup(int, int)]) { + case (none[tup(uint, uint)]) { ret tup(none[int], i); } - case (some[tup(int, int)](?t)) { + case (some[tup(uint, uint)](?t)) { fail; } } @@ -342,6 +348,98 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr { } } + fn log_conv(conv c) { + alt (c.param) { + case (some[int](?p)) { + log "param: " + std._int.to_str(p, 10u); + } + case (_) { + log "param: none"; + } + } + for (flag f in c.flags) { + alt (f) { + case (flag_left_justify) { + log "flag: left justify"; + } + case (flag_left_zero_pad) { + log "flag: left zero pad"; + } + case (flag_left_space_pad) { + log "flag: left space pad"; + } + case (flag_plus_if_positive) { + log "flag: plus if positive"; + } + case (flag_alternate) { + log "flag: alternate"; + } + } + } + alt (c.width) { + case (count_is(?i)) { + log "width: count is " + std._int.to_str(i, 10u); + } + case (count_is_param(?i)) { + log "width: count is param " + std._int.to_str(i, 10u); + } + case (count_is_next_param) { + log "width: count is next param"; + } + case (count_implied) { + log "width: count is implied"; + } + } + alt (c.precision) { + case (count_is(?i)) { + log "prec: count is " + std._int.to_str(i, 10u); + } + case (count_is_param(?i)) { + log "prec: count is param " + std._int.to_str(i, 10u); + } + case (count_is_next_param) { + log "prec: count is next param"; + } + case (count_implied) { + log "prec: count is implied"; + } + } + alt (c.ty) { + case (ty_bool) { + log "type: bool"; + } + case (ty_str) { + log "type: str"; + } + case (ty_char) { + log "type: char"; + } + case (ty_int(?s)) { + alt (s) { + case (signed) { + log "type: signed"; + } + case (unsigned) { + log "type: unsigned"; + } + } + } + case (ty_bits) { + log "type: bits"; + } + case (ty_hex(?cs)) { + alt (cs) { + case (case_upper) { + log "type: uhex"; + } + case (case_lower) { + log "type: lhex"; + } + } + } + } + } + auto sp = args.(0).span; auto n = 0u; auto tmp_expr = make_new_str(sp, ""); @@ -358,6 +456,10 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr { fail; } + // TODO: Remove debug logging + log "Building conversion:"; + log_conv(conv); + n += 1u; auto arg_expr = args.(n); auto c_expr = make_new_conv(conv, arg_expr); @@ -366,10 +468,10 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr { } } - // TODO: Remove this print and return the real expanded AST + // TODO: Remove this debug logging log "dumping expanded ast:"; log pretty.print_expr(tmp_expr); - ret make_new_str(sp, "TODO"); + ret tmp_expr; } // From 992c1668f28378185b4615477bc968ff7a1e185a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 1 Mar 2011 22:43:19 -0500 Subject: [PATCH 16/16] Finish #fmt string parsing. Completely untested. --- src/comp/front/extfmt.rs | 96 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 7 deletions(-) diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index 5ca50c051decf..3f1e5c3039228 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -81,6 +81,10 @@ fn expand_syntax_ext(vec[@ast.expr] args, } auto fmt = expr_to_str(args.(0)); + + log "Format string:"; + log fmt; + auto pieces = parse_fmt_string(fmt); auto args_len = _vec.len[@ast.expr](args); auto fmt_args = _vec.slice[@ast.expr](args, 1u, args_len - 1u); @@ -170,7 +174,7 @@ fn peek_num(str s, uint i, uint lim) -> option.t[tup(uint, uint)] { fn parse_conversion(str s, uint i, uint lim) -> tup(piece, uint) { auto parm = parse_parameter(s, i, lim); auto flags = parse_flags(s, parm._1, lim); - auto width = parse_width(s, flags._1, lim); + auto width = parse_count(s, flags._1, lim); auto prec = parse_precision(s, width._1, lim); auto ty = parse_type(s, prec._1, lim); ret tup(piece_conv(rec(param = parm._0, @@ -192,22 +196,100 @@ fn parse_parameter(str s, uint i, uint lim) -> tup(option.t[int], uint) { ret tup(none[int], i); } case (some[tup(uint, uint)](?t)) { - fail; + auto n = t._0; + auto j = t._1; + if (j < lim && s.(j) == '$' as u8) { + ret tup(some[int](n as int), j + 1u); + } + else { + ret tup(none[int], i); + } } } } fn parse_flags(str s, uint i, uint lim) -> tup(vec[flag], uint) { - let vec[flag] flags = vec(); - ret tup(flags, i); + let vec[flag] noflags = vec(); + + if (i >= lim) { + ret tup(noflags, i); + } + + fn more_(flag f, str s, uint i, uint lim) -> tup(vec[flag], uint) { + auto next = parse_flags(s, i + 1u, lim); + auto rest = next._0; + auto j = next._1; + let vec[flag] curr = vec(f); + ret tup(curr + rest, j); + } + + auto more = bind more_(_, s, i, lim); + + auto f = s.(i); + if (f == ('-' as u8)) { + ret more(flag_left_justify); + } else if (f == ('0' as u8)) { + ret more(flag_left_zero_pad); + } else if (f == (' ' as u8)) { + ret more(flag_left_space_pad); + } else if (f == ('+' as u8)) { + ret more(flag_plus_if_positive); + } else if (f == ('#' as u8)) { + ret more(flag_alternate); + } else { + ret tup(noflags, i); + } } -fn parse_width(str s, uint i, uint lim) -> tup(count, uint) { - ret tup(count_implied, i); +fn parse_count(str s, uint i, uint lim) -> tup(count, uint) { + if (i >= lim) { + ret tup(count_implied, i); + } + + // FIXME: These inner functions are just to avoid a rustboot + // "Unsatisfied precondition constraint" bug with alts nested in ifs + fn parse_star_count(str s, uint i, uint lim) -> tup(count, uint) { + auto param = parse_parameter(s, i + 1u, lim); + auto j = param._1; + alt (param._0) { + case (none[int]) { + ret tup(count_is_next_param, j); + } + case (some[int](?n)) { + ret tup(count_is_param(n), j); + } + } + } + + fn parse_count_(str s, uint i, uint lim) -> tup(count, uint) { + auto num = peek_num(s, i, lim); + alt (num) { + case (none[tup(uint, uint)]) { + ret tup(count_implied, i); + } + case (some[tup(uint, uint)](?num)) { + ret tup(count_is(num._0 as int), num._1); + } + } + } + + if (s.(i) == ('*' as u8)) { + ret parse_star_count(s, i, lim); + } else { + ret parse_count_(s, i, lim); + } } fn parse_precision(str s, uint i, uint lim) -> tup(count, uint) { - ret tup(count_implied, i); + if (i >= lim) { + ret tup(count_implied, i); + } + + if (s.(i) == '.' as u8) { + ret parse_count(s, i + 1u, lim); + } else { + ret tup(count_implied, i); + } } fn parse_type(str s, uint i, uint lim) -> tup(ty, uint) {