From cbba665f3c536b90bc346fb93373184d27cb7d77 Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Tue, 26 Apr 2011 19:34:57 -0700 Subject: [PATCH 1/3] Beginnings of support for pseudomethods. So far, all this does is handle desugaring of pseudomethod calls into one-argument functions. Started sketching out how to desugar into multi-argument functions in the comments; that's not done yet. The '::' syntax was suggested by pcwalton. If we want to use ordinary method call syntax (dot), then this becomes rather harder, because we have to treat the pseudomethod call as a field expression and then expect arbitrary expressions as the base of that field expression, which breaks a lot of existing places in the compiler. --- src/comp/front/lexer.rs | 11 ++++++++++- src/comp/front/parser.rs | 29 +++++++++++++++++++++++++++++ src/comp/front/token.rs | 2 ++ src/test/run-pass/pseudomethod.rs | 28 ++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/pseudomethod.rs diff --git a/src/comp/front/lexer.rs b/src/comp/front/lexer.rs index 3659af1c655e2..cbc8314bd7d22 100644 --- a/src/comp/front/lexer.rs +++ b/src/comp/front/lexer.rs @@ -611,7 +611,6 @@ fn next_token(reader rdr) -> token.token { alt (c) { // One-byte tokens. - case (':') { rdr.bump(); ret token.COLON; } case ('?') { rdr.bump(); ret token.QUES; } case (';') { rdr.bump(); ret token.SEMI; } case (',') { rdr.bump(); ret token.COMMA; } @@ -628,6 +627,16 @@ fn next_token(reader rdr) -> token.token { // Multi-byte tokens. + case (':') { + rdr.bump(); + if (rdr.curr() == ':') { + rdr.bump(); + ret token.COLONCOLON; + } else { + ret token.COLON; + } + } + case ('=') { rdr.bump(); if (rdr.curr() == '=') { diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index fdd41cf0ff702..e064dca5c46a4 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -1007,6 +1007,35 @@ fn parse_dot_or_call_expr(parser p) -> @ast.expr { } } + case (token.COLONCOLON) { + // Pseudomethod calls: e::pm() is sugar for pm(e). + p.bump(); + + auto pm = parse_bottom_expr(p); + + // Throw out the parens. + expect(p, token.LPAREN); + expect(p, token.RPAREN); + + + // // The rest of the arguments. + // auto pf = parse_expr; + // auto lo = p.get_lo_pos(); + // auto hi = p.get_hi_pos(); + // expect(p, token.LPAREN); + // auto result = parse_seq_to_end[@ast.expr](token.RPAREN, + // some(token.COMMA), + // pf, hi, p); + // // Get all the arguments together. + // vec[@ast.expr] args = vec(e) + result; + // spanned(lo, hi, args); + + auto e_ = ast.expr_call(pm, vec(@spanned(lo, hi, e.node)), + ast.ann_none); + + e = @spanned(lo, hi, e_); + } + case (token.DOT) { p.bump(); alt (p.peek()) { diff --git a/src/comp/front/token.rs b/src/comp/front/token.rs index f367bcc6835a2..34bd85436b130 100644 --- a/src/comp/front/token.rs +++ b/src/comp/front/token.rs @@ -45,6 +45,7 @@ tag token { COMMA; SEMI; COLON; + COLONCOLON; QUES; RARROW; SEND; @@ -214,6 +215,7 @@ fn to_str(token t) -> str { case (COMMA) { ret ","; } case (SEMI) { ret ";"; } case (COLON) { ret ":"; } + case (COLONCOLON) { ret ":"; } case (QUES) { ret "?"; } case (RARROW) { ret "->"; } case (SEND) { ret "<|"; } diff --git a/src/test/run-pass/pseudomethod.rs b/src/test/run-pass/pseudomethod.rs new file mode 100644 index 0000000000000..aa5931c0acc7e --- /dev/null +++ b/src/test/run-pass/pseudomethod.rs @@ -0,0 +1,28 @@ +// xfail-boot +use std; +import std._vec.len; +fn main() { + + // Sanity check + let uint a = len[int](vec(1, 2, 3, 4)); + log a; + let vec[int] v = vec(1, 2, 3, 4); + let uint b = len[int](v); + log b; + check (a == b); + + // Pseudomethod + let uint c = vec(1, 2, 3, 4)::len[int](); + log c; + let uint d = v::len[int](); + log d; + check (c == d); + + // User-defined pseudomethod + fn exclaim(str s) -> str { ret s + "!"; } + let str e = exclaim("hello"); + log e; + let str f = "hello"::exclaim(); + log f; + check (e == f); +} From a54c78c82bb5885613157ccad659c54a7cb40a1d Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Tue, 26 Apr 2011 20:49:31 -0700 Subject: [PATCH 2/3] More support for pseudomethods: multi-argument pseudomethods work now. --- src/comp/front/parser.rs | 28 +++++++++------------- src/test/run-pass/pseudomethod.rs | 39 ++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index e064dca5c46a4..ebb7ff1c5972c 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -1013,26 +1013,20 @@ fn parse_dot_or_call_expr(parser p) -> @ast.expr { auto pm = parse_bottom_expr(p); - // Throw out the parens. + // Parse the rest of the arguments. + auto pf = parse_expr; + auto lo = p.get_lo_pos(); + auto hi = p.get_hi_pos(); expect(p, token.LPAREN); - expect(p, token.RPAREN); - - - // // The rest of the arguments. - // auto pf = parse_expr; - // auto lo = p.get_lo_pos(); - // auto hi = p.get_hi_pos(); - // expect(p, token.LPAREN); - // auto result = parse_seq_to_end[@ast.expr](token.RPAREN, - // some(token.COMMA), - // pf, hi, p); - // // Get all the arguments together. - // vec[@ast.expr] args = vec(e) + result; - // spanned(lo, hi, args); + auto result = parse_seq_to_end[@ast.expr](token.RPAREN, + some(token.COMMA), + pf, hi, p); - auto e_ = ast.expr_call(pm, vec(@spanned(lo, hi, e.node)), - ast.ann_none); + // Get all the arguments together. + let vec[@ast.expr] args = vec(e) + result; + auto es = @spanned(lo, hi, args); + auto e_ = ast.expr_call(pm, es.node, ast.ann_none); e = @spanned(lo, hi, e_); } diff --git a/src/test/run-pass/pseudomethod.rs b/src/test/run-pass/pseudomethod.rs index aa5931c0acc7e..33a79ace87fb4 100644 --- a/src/test/run-pass/pseudomethod.rs +++ b/src/test/run-pass/pseudomethod.rs @@ -3,26 +3,53 @@ use std; import std._vec.len; fn main() { - // Sanity check + // Pseudomethod using a library function let uint a = len[int](vec(1, 2, 3, 4)); log a; - let vec[int] v = vec(1, 2, 3, 4); - let uint b = len[int](v); + let uint b = vec(1, 2, 3, 4)::len[int](); log b; check (a == b); - // Pseudomethod - let uint c = vec(1, 2, 3, 4)::len[int](); + let vec[int] v = vec(1, 2, 3, 4); + let uint c = len[int](v); log c; let uint d = v::len[int](); log d; check (c == d); - // User-defined pseudomethod + // User-defined pseudomethods fn exclaim(str s) -> str { ret s + "!"; } let str e = exclaim("hello"); log e; let str f = "hello"::exclaim(); log f; check (e == f); + + fn plus(int a, int b) -> int { ret a + b; } + let int m = 2 * 3::plus(4) + 5; + let int n = 2 * (3 + 4) + 5; + log m; + log n; + check (m == n); + + // Multi-argument pseudomethod + fn bang_huh(str s1, str s2) -> str { + ret s1 + "!" + s2 + "?"; + } + let str g = bang_huh("hello", "world"); + log g; + let str h = "hello"::bang_huh("world"); + log h; + check (g == h); + + // Stacking pseudomethods + let str i = "hello"::exclaim()::bang_huh("world"); + log i; + let str j = bang_huh(exclaim("hello"), "world"); + log j; + check (i == j); + + let int k = (vec("foo", "bar", "baz")::len[str]() as int)::plus(50); + log k; + check (k == 53); } From 53da1b53e7f38ee605d6d2242585c8bbeeb3899a Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Tue, 26 Apr 2011 23:33:21 -0700 Subject: [PATCH 3/3] One-char typo fix. --- src/comp/front/token.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comp/front/token.rs b/src/comp/front/token.rs index 34bd85436b130..6101291c5162a 100644 --- a/src/comp/front/token.rs +++ b/src/comp/front/token.rs @@ -215,7 +215,7 @@ fn to_str(token t) -> str { case (COMMA) { ret ","; } case (SEMI) { ret ";"; } case (COLON) { ret ":"; } - case (COLONCOLON) { ret ":"; } + case (COLONCOLON) { ret "::"; } case (QUES) { ret "?"; } case (RARROW) { ret "->"; } case (SEND) { ret "<|"; }