about summary refs log tree commit diff
path: root/src/comp/syntax
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-12-20 16:33:55 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2011-12-23 18:09:25 +0100
commit057617c6654bfd5a677112cd26141d0b9c137145 (patch)
tree316c1b2cbcb11aa3cd02f05107e76fa5cd624fef /src/comp/syntax
parent92927449595782926c4db5a579ba7e4c6952287d (diff)
Parse `iface` items and interface references in `impl` items.
The (temporary) syntax is

    iface seq<T> {
        fn len() -> uint;
        fn iter(f: block(T));
    }

    // The 'blah<T>' can be left of to default the name of the
    // impl to seq<T>. The 'of seq<T>' can be left off when
    // not implementing a named interface.
    impl blah<T> of seq<T> for [T] {
        fn len() -> uint { vec::len(self) }
        fn iter(f: block(T)) { for x in self { f(x); } }
    }
Diffstat (limited to 'src/comp/syntax')
-rw-r--r--src/comp/syntax/ast.rs4
-rw-r--r--src/comp/syntax/fold.rs15
-rw-r--r--src/comp/syntax/parse/parser.rs117
-rw-r--r--src/comp/syntax/print/pprust.rs38
-rw-r--r--src/comp/syntax/visit.rs11
5 files changed, 110 insertions, 75 deletions
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs
index a94e860b764..9952dd55546 100644
--- a/src/comp/syntax/ast.rs
+++ b/src/comp/syntax/ast.rs
@@ -490,7 +490,9 @@ tag item_ {
     item_obj(_obj, [ty_param], /* constructor id */node_id);
     item_res(fn_decl /* dtor */, [ty_param], blk,
              node_id /* dtor id */, node_id /* ctor id */);
-    item_impl([ty_param], @ty /* self */, [@method]);
+    item_iface([ty_param], [ty_method]);
+    item_impl([ty_param], option::t<@ty> /* iface */,
+              @ty /* self */, [@method]);
 }
 
 type native_item =
diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs
index 0c136819ce9..d06c98b0a31 100644
--- a/src/comp/syntax/fold.rs
+++ b/src/comp/syntax/fold.rs
@@ -65,7 +65,7 @@ type a_f =
      fold_native_mod: fn@(native_mod) -> native_mod,
      fold_variant: fn@(variant) -> variant,
      fold_ident: fn@(&&ident) -> ident,
-     fold_path: fn@(@path) -> @path,
+     fold_path: fn@(&&@path) -> @path,
      fold_local: fn@(&&@local) -> @local,
      map_exprs: fn@(fn@(&&@expr) -> @expr, [@expr]) -> [@expr],
      new_id: fn@(node_id) -> node_id,
@@ -94,7 +94,7 @@ fn nf_mod_dummy(_m: _mod) -> _mod { fail; }
 fn nf_native_mod_dummy(_n: native_mod) -> native_mod { fail; }
 fn nf_variant_dummy(_v: variant) -> variant { fail; }
 fn nf_ident_dummy(&&_i: ident) -> ident { fail; }
-fn nf_path_dummy(_p: @path) -> @path { fail; }
+fn nf_path_dummy(&&_p: @path) -> @path { fail; }
 fn nf_obj_field_dummy(_o: obj_field) -> obj_field { fail; }
 fn nf_local_dummy(&&_o: @local) -> @local { fail; }
 
@@ -243,10 +243,13 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
                       methods: vec::map(o.methods, fld.fold_method)},
                      typms, d)
           }
-          item_impl(tps, ty, methods) {
-            item_impl(tps, fld.fold_ty(ty),
+          item_impl(tps, ifce, ty, methods) {
+            item_impl(tps, option::map(ifce, fld.fold_ty), fld.fold_ty(ty),
                       vec::map(methods, fld.fold_method))
           }
+          item_iface(tps, methods) {
+            item_iface(tps, methods)
+          }
           item_res(decl, typms, body, did, cid) {
             item_res(fold_fn_decl(decl, fld), typms, fld.fold_block(body),
                      did, cid)
@@ -471,7 +474,7 @@ fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ {
 
 fn noop_fold_ident(&&i: ident, _fld: ast_fold) -> ident { ret i; }
 
-fn noop_fold_path(p: path_, fld: ast_fold) -> path_ {
+fn noop_fold_path(&&p: path_, fld: ast_fold) -> path_ {
     ret {global: p.global,
          idents: vec::map(p.idents, fld.fold_ident),
          types: vec::map(p.types, fld.fold_ty)};
@@ -630,7 +633,7 @@ fn make_fold(afp: ast_fold_precursor) -> ast_fold {
     fn f_ident(afp: ast_fold_precursor, f: ast_fold, &&x: ident) -> ident {
         ret afp.fold_ident(x, f);
     }
-    fn f_path(afp: ast_fold_precursor, f: ast_fold, x: @path) -> @path {
+    fn f_path(afp: ast_fold_precursor, f: ast_fold, &&x: @path) -> @path {
         ret @{node: afp.fold_path(x.node, f), span: afp.new_span(x.span)};
     }
     fn f_local(afp: ast_fold_precursor, f: ast_fold, &&x: @local) -> @local {
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index 484659f4bc5..8299f23ae20 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -165,7 +165,7 @@ fn bad_expr_word_table() -> hashmap<str, ()> {
                  "cont", "ret", "be", "fail", "type", "resource", "check",
                  "assert", "claim", "native", "fn", "lambda", "pure",
                  "unsafe", "block", "import", "export", "let", "const",
-                 "log", "tag", "obj", "copy", "sendfn", "impl"] {
+                 "log", "tag", "obj", "copy", "sendfn", "impl", "iface"] {
         words.insert(word, ());
     }
     words
@@ -285,7 +285,7 @@ fn parse_ty_fn(proto: ast::proto, p: parser) -> ast::ty_ {
                     constraints: constrs});
 }
 
-fn parse_ty_obj(p: parser) -> ast::ty_ {
+fn parse_ty_methods(p: parser) -> [ast::ty_method] {
     fn parse_method_sig(p: parser) -> ast::ty_method {
         let flo = p.get_lo_pos();
         let proto: ast::proto = parse_method_proto(p);
@@ -298,10 +298,8 @@ fn parse_ty_obj(p: parser) -> ast::ty_ {
           }
         }
     }
-    let meths =
-        parse_seq(token::LBRACE, token::RBRACE, seq_sep_none(),
-                  parse_method_sig, p);
-    ret ast::ty_obj(meths.node);
+    parse_seq(token::LBRACE, token::RBRACE, seq_sep_none(),
+              parse_method_sig, p).node
 }
 
 fn parse_mt(p: parser) -> ast::mt {
@@ -519,7 +517,7 @@ fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty {
     } else if eat_word(p, "sendfn") {
         t = parse_ty_fn(ast::proto_send, p);
     } else if eat_word(p, "obj") {
-        t = parse_ty_obj(p);
+        t = ast::ty_obj(parse_ty_methods(p));
     } else if p.peek() == token::MOD_SEP || is_ident(p.peek()) {
         let path = parse_path(p);
         t = ast::ty_path(path, p.get_id());
@@ -676,47 +674,22 @@ fn is_plain_ident(p: parser) -> bool {
 
 fn parse_path(p: parser) -> @ast::path {
     let lo = p.get_lo_pos();
-    let hi = lo;
-
-    let global;
-    if p.peek() == token::MOD_SEP {
-        global = true;
-        p.bump();
-    } else { global = false; }
-
-    let ids: [ast::ident] = [];
-    while true {
-        alt p.peek() {
-          token::IDENT(i, _) {
-            hi = p.get_hi_pos();
-            ids += [p.get_str(i)];
-            hi = p.get_hi_pos();
-            p.bump();
-            if p.peek() == token::MOD_SEP && p.look_ahead(1u) != token::LT {
-                p.bump();
-            } else { break; }
-          }
-          _ { break; }
-        }
+    let global = eat(p, token::MOD_SEP), ids = [parse_ident(p)];
+    while p.look_ahead(1u) != token::LT && eat(p, token::MOD_SEP) {
+        ids += [parse_ident(p)];
     }
-    ret @spanned(lo, hi, {global: global, idents: ids, types: []});
+    ret @spanned(lo, p.get_last_hi_pos(),
+                 {global: global, idents: ids, types: []});
 }
 
-fn parse_path_and_ty_param_substs(p: parser) -> @ast::path {
+fn parse_path_and_ty_param_substs(p: parser, colons: bool) -> @ast::path {
     let lo = p.get_lo_pos();
     let path = parse_path(p);
-    if p.peek() == token::MOD_SEP {
-        p.bump();
-
-        let seq =
-            parse_seq_lt_gt(some(token::COMMA), {|p| parse_ty(p, false)}, p);
-        let hi = seq.span.hi;
-        path = @spanned(lo, hi,
-                        {global: path.node.global,
-                         idents: path.node.idents,
-                         types: seq.node});
-    }
-    ret path;
+    if colons ? eat(p, token::MOD_SEP) : p.peek() == token::LT {
+        let seq = parse_seq_lt_gt(some(token::COMMA),
+                                  {|p| parse_ty(p, false)}, p);
+        @spanned(lo, seq.span.hi, {types: seq.node with path.node})
+    } else { path }
 }
 
 fn parse_mutability(p: parser) -> ast::mutability {
@@ -958,7 +931,7 @@ fn parse_bottom_expr(p: parser) -> @ast::expr {
                   is_ident(p.peek()) && !is_word(p, "true") &&
                       !is_word(p, "false") {
         check_bad_word(p);
-        let pth = parse_path_and_ty_param_substs(p);
+        let pth = parse_path_and_ty_param_substs(p, true);
         hi = pth.span.hi;
         ex = ast::expr_path(pth);
     } else {
@@ -984,10 +957,11 @@ fn parse_syntax_ext(p: parser) -> @ast::expr {
 }
 
 fn parse_syntax_ext_naked(p: parser, lo: uint) -> @ast::expr {
-    let pth = parse_path(p);
-    if vec::len(pth.node.idents) == 0u {
-        p.fatal("expected a syntax expander name");
+    alt p.peek() {
+      token::IDENT(_, _) {}
+      _ { p.fatal("expected a syntax expander name"); }
     }
+    let pth = parse_path(p);
     //temporary for a backwards-compatible cycle:
     let sep = seq_sep(token::COMMA);
     let es =
@@ -1518,7 +1492,7 @@ fn parse_pat(p: parser) -> @ast::pat {
             let sub = eat(p, token::AT) ? some(parse_pat(p)) : none;
             pat = ast::pat_bind(name, sub);
         } else {
-            let tag_path = parse_path_and_ty_param_substs(p);
+            let tag_path = parse_path_and_ty_param_substs(p, true);
             hi = tag_path.span.hi;
             let args: [@ast::pat];
             alt p.peek() {
@@ -1751,12 +1725,9 @@ fn parse_ty_param(p: parser) -> ast::ty_param {
 }
 
 fn parse_ty_params(p: parser) -> [ast::ty_param] {
-    let ty_params: [ast::ty_param] = [];
-    if p.peek() == token::LT {
-        p.bump();
-        ty_params = parse_seq_to_gt(some(token::COMMA), parse_ty_param, p);
-    }
-    ret ty_params;
+    if eat(p, token::LT) {
+        parse_seq_to_gt(some(token::COMMA), parse_ty_param, p)
+    } else { [] }
 }
 
 fn parse_fn_decl(p: parser, proto: ast::proto, purity: ast::purity)
@@ -1866,15 +1837,47 @@ fn parse_item_obj(p: parser, attrs: [ast::attribute]) -> @ast::item {
                 attrs);
 }
 
-fn parse_item_impl(p: parser, attrs: [ast::attribute]) -> @ast::item {
+fn parse_item_iface(p: parser, attrs: [ast::attribute]) -> @ast::item {
     let lo = p.get_last_lo_pos(), ident = parse_ident(p),
+        tps = parse_ty_params(p), meths = parse_ty_methods(p);
+    ret mk_item(p, lo, p.get_last_hi_pos(), ident,
+                ast::item_iface(tps, meths), attrs);
+}
+
+fn parse_item_impl(p: parser, attrs: [ast::attribute]) -> @ast::item {
+    let lo = p.get_last_lo_pos(), ident, tps, ifce;
+    fn wrap_path(p: parser, pt: @ast::path) -> @ast::ty {
+        @{node: ast::ty_path(pt, p.get_id()), span: pt.span}
+    }
+    if eat_word(p, "of") {
+        let path = parse_path_and_ty_param_substs(p, false);
+        tps = vec::map(path.node.types, {|tp|
+            alt tp.node {
+              ast::ty_path(pt, _) {
+                if vec::len(pt.node.idents) == 1u &&
+                   vec::len(pt.node.types) == 0u {
+                     ret {ident: pt.node.idents[0], kind: ast::kind_sendable};
+                }
+              }
+              _ {}
+            }
+            p.fatal("only single-word, parameter-less types allowed here");
+        });
+        ident = path.node.idents[vec::len(path.node.idents)-1u];
+        ifce = some(wrap_path(p, path));
+    } else {
+        ident = parse_ident(p);
         tps = parse_ty_params(p);
+        ifce = if eat_word(p, "of") {
+            some(wrap_path(p, parse_path_and_ty_param_substs(p, false)))
+        } else { none };
+    };
     expect_word(p, "for");
     let ty = parse_ty(p, false), meths = [];
     expect(p, token::LBRACE);
     while !eat(p, token::RBRACE) { meths += [parse_method(p, true)]; }
     ret mk_item(p, lo, p.get_last_hi_pos(), ident,
-                ast::item_impl(tps, ty, meths), attrs);
+                ast::item_impl(tps, ifce, ty, meths), attrs);
 }
 
 fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item {
@@ -2145,6 +2148,8 @@ fn parse_item(p: parser, attrs: [ast::attribute]) -> option::t<@ast::item> {
     } else if is_word(p, "obj") && p.look_ahead(1u) != token::LPAREN {
         p.bump();
         ret some(parse_item_obj(p, attrs));
+    } else if eat_word(p, "iface") {
+        ret some(parse_item_iface(p, attrs));
     } else if eat_word(p, "impl") {
         ret some(parse_item_impl(p, attrs));
     } else if eat_word(p, "resource") {
diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs
index e2856c60f8d..99793d1b816 100644
--- a/src/comp/syntax/print/pprust.rs
+++ b/src/comp/syntax/print/pprust.rs
@@ -311,14 +311,7 @@ fn print_type(s: ps, &&ty: @ast::ty) {
       ast::ty_obj(methods) {
         head(s, "obj");
         bopen(s);
-        for m: ast::ty_method in methods {
-            hardbreak_if_not_bol(s);
-            cbox(s, indent_unit);
-            maybe_print_comment(s, m.span.lo);
-            print_ty_fn(s, m.decl, some(m.ident));
-            word(s.s, ";");
-            end(s);
-        }
+        for m in methods { print_ty_method(s, m); }
         bclose(s, ty.span);
       }
       ast::ty_path(path, _) { print_path(s, path, false); }
@@ -473,11 +466,19 @@ fn print_item(s: ps, &&item: @ast::item) {
         }
         bclose(s, item.span);
       }
-      ast::item_impl(tps, ty, methods) {
+      ast::item_impl(tps, ifce, ty, methods) {
         head(s, "impl");
         word(s.s, item.ident);
         print_type_params(s, tps);
-        nbsp(s);
+        space(s.s);
+        alt ifce {
+          some(ty) {
+            word_nbsp(s, "of");
+            print_type(s, ty);
+            space(s.s);
+          }
+          _ {}
+        }
         word_nbsp(s, "for");
         print_type(s, ty);
         space(s.s);
@@ -491,6 +492,14 @@ fn print_item(s: ps, &&item: @ast::item) {
         }
         bclose(s, item.span);
       }
+      ast::item_iface(tps, methods) {
+        head(s, "iface");
+        word(s.s, item.ident);
+        print_type_params(s, tps);
+        bopen(s);
+        for meth in methods { print_ty_method(s, meth); }
+        bclose(s, item.span);
+      }
       ast::item_res(decl, tps, body, dt_id, ct_id) {
         head(s, "resource");
         word(s.s, item.ident);
@@ -506,6 +515,15 @@ fn print_item(s: ps, &&item: @ast::item) {
     s.ann.post(ann_node);
 }
 
+fn print_ty_method(s: ps, m: ast::ty_method) {
+    hardbreak_if_not_bol(s);
+    cbox(s, indent_unit);
+    maybe_print_comment(s, m.span.lo);
+    print_ty_fn(s, m.decl, some(m.ident));
+    word(s.s, ";");
+    end(s);
+}
+
 fn print_outer_attributes(s: ps, attrs: [ast::attribute]) {
     let count = 0;
     for attr: ast::attribute in attrs {
diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs
index dc91064dba6..ecdf8c9a05d 100644
--- a/src/comp/syntax/visit.rs
+++ b/src/comp/syntax/visit.rs
@@ -120,13 +120,20 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
                              some(m.ident), m.id, e, v);
         }
       }
-      item_impl(_, ty, methods) {
-        visit_ty(ty, e, v);
+      item_impl(_, ifce, ty, methods) {
+        alt ifce { some(ty) { v.visit_ty(ty, e, v); } _ {} }
+        v.visit_ty(ty, e, v);
         for m in methods {
             v.visit_fn_proto(m.decl, m.tps, m.body, m.span,
                              some(m.ident), m.id, e, v);
         }
       }
+      item_iface(_, methods) {
+        for m in methods {
+            for a in m.decl.inputs { v.visit_ty(a.ty, e, v); }
+            v.visit_ty(m.decl.output, e, v);
+        }
+      }
     }
 }