diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 4ed513a3e06..18add3bdfbd 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]); @@ -363,6 +363,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 00000000000..cb70805a335 --- /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 f747c084b5b..8f6db17d88d 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -656,7 +656,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) { @@ -736,6 +739,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 bc4aaa52c1a..16d24e9b277 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 65e7647ee8b..66fe4fd7ce0 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; -fn main() { - auto s = #fmt("hello %d friends and %s things", 10, "formatted"); - log s; +import std._str; + +fn test(str actual, str expected) { + log actual; + log expected; + check (_str.eq(actual, expected)); +} + +fn main() { + test(#fmt("hello %d friends and %s things", 10, "formatted"), + "hello 10 friends and formatted things"); }