about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorLuqman Aden <laden@csclub.uwaterloo.ca>2013-10-25 01:56:34 -0400
committerLuqman Aden <laden@csclub.uwaterloo.ca>2013-11-04 23:53:11 -0500
commitc669ccf3d30da3eb505832d0872bf03607eb98eb (patch)
tree274c13139ca8e1dfdf7934317c2c7b8be1267931 /src/libsyntax
parent658637baf45b41e4cff049440bc07f267d810218 (diff)
downloadrust-c669ccf3d30da3eb505832d0872bf03607eb98eb.tar.gz
rust-c669ccf3d30da3eb505832d0872bf03607eb98eb.zip
libsyntax/librustc: Allow calling variadic foreign functions.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs1
-rw-r--r--src/libsyntax/ext/build.rs1
-rw-r--r--src/libsyntax/fold.rs2
-rw-r--r--src/libsyntax/parse/lexer.rs18
-rw-r--r--src/libsyntax/parse/mod.rs3
-rw-r--r--src/libsyntax/parse/parser.rs81
-rw-r--r--src/libsyntax/parse/token.rs2
-rw-r--r--src/libsyntax/print/pprust.rs9
8 files changed, 90 insertions, 27 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index cf72455a83a..6aec7380f40 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -892,6 +892,7 @@ pub struct fn_decl {
     inputs: ~[arg],
     output: Ty,
     cf: ret_style,
+    variadic: bool
 }
 
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 76d9f755d3c..0a5e20fc2b2 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -728,6 +728,7 @@ impl AstBuilder for @ExtCtxt {
             inputs: inputs,
             output: output,
             cf: ast::return_val,
+            variadic: false
         }
     }
 
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index d579e7dd2c7..388de29b456 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -99,6 +99,7 @@ pub trait ast_fold {
                                                                       self)),
                                 output: self.fold_ty(&fdec.output),
                                 cf: fdec.cf,
+                                variadic: fdec.variadic
                             },
                             fold_generics(generics, self))
                     }
@@ -466,6 +467,7 @@ pub fn fold_fn_decl<T:ast_fold>(decl: &ast::fn_decl, fld: &T)
         inputs: decl.inputs.map(|x| fold_arg_(x, fld)), // bad copy
         output: fld.fold_ty(&decl.output),
         cf: decl.cf,
+        variadic: decl.variadic
     }
 }
 
diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs
index 7ac999c46a4..49445312a12 100644
--- a/src/libsyntax/parse/lexer.rs
+++ b/src/libsyntax/parse/lexer.rs
@@ -664,12 +664,18 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
       ';' => { bump(rdr); return token::SEMI; }
       ',' => { bump(rdr); return token::COMMA; }
       '.' => {
-        bump(rdr);
-        if rdr.curr == '.' && nextch(rdr) != '.' {
-            bump(rdr);
-            return token::DOTDOT;
-        }
-        return token::DOT;
+          bump(rdr);
+          return if rdr.curr == '.' {
+              bump(rdr);
+              if rdr.curr == '.' {
+                  bump(rdr);
+                  token::DOTDOTDOT
+              } else {
+                  token::DOTDOT
+              }
+          } else {
+              token::DOT
+          };
       }
       '(' => { bump(rdr); return token::LPAREN; }
       ')' => { bump(rdr); return token::RPAREN; }
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index fbe711b5efe..6c81784b5de 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -701,7 +701,8 @@ mod test {
                                 output: ast::Ty{id: ast::DUMMY_NODE_ID,
                                                  node: ast::ty_nil,
                                                  span:sp(15,15)}, // not sure
-                                cf: ast::return_val
+                                cf: ast::return_val,
+                                variadic: false
                             },
                                     ast::impure_fn,
                                     abi::AbiSet::Rust(),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 56254704e28..7c98d8d1c85 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -863,7 +863,7 @@ impl Parser {
         let abis = opt_abis.unwrap_or(AbiSet::Rust());
         let purity = self.parse_unsafety();
         self.expect_keyword(keywords::Fn);
-        let (decl, lifetimes) = self.parse_ty_fn_decl();
+        let (decl, lifetimes) = self.parse_ty_fn_decl(true);
         return ty_bare_fn(@TyBareFn {
             abis: abis,
             purity: purity,
@@ -875,7 +875,7 @@ impl Parser {
     // Parses a procedure type (`proc`). The initial `proc` keyword must
     // already have been parsed.
     pub fn parse_proc_type(&self) -> ty_ {
-        let (decl, lifetimes) = self.parse_ty_fn_decl();
+        let (decl, lifetimes) = self.parse_ty_fn_decl(false);
         ty_closure(@TyClosure {
             sigil: OwnedSigil,
             region: None,
@@ -919,7 +919,7 @@ impl Parser {
                 // Old-style closure syntax (`fn(A)->B`).
                 self.expect_keyword(keywords::Fn);
                 let bounds = self.parse_optional_ty_param_bounds();
-                let (decl, lifetimes) = self.parse_ty_fn_decl();
+                let (decl, lifetimes) = self.parse_ty_fn_decl(false);
                 (sigil, decl, lifetimes, bounds)
             }
             None => {
@@ -960,6 +960,7 @@ impl Parser {
                     inputs: inputs,
                     output: output,
                     cf: return_style,
+                    variadic: false
                 };
 
                 (BorrowedSigil, decl, lifetimes, bounds)
@@ -994,7 +995,7 @@ impl Parser {
     }
 
     // parse a function type (following the 'fn')
-    pub fn parse_ty_fn_decl(&self) -> (fn_decl, OptVec<ast::Lifetime>) {
+    pub fn parse_ty_fn_decl(&self, allow_variadic: bool) -> (fn_decl, OptVec<ast::Lifetime>) {
         /*
 
         (fn) <'lt> (S) -> T
@@ -1013,17 +1014,13 @@ impl Parser {
             opt_vec::Empty
         };
 
-        let inputs = self.parse_unspanned_seq(
-            &token::LPAREN,
-            &token::RPAREN,
-            seq_sep_trailing_disallowed(token::COMMA),
-            |p| p.parse_arg_general(false)
-        );
+        let (inputs, variadic) = self.parse_fn_args(false, allow_variadic);
         let (ret_style, ret_ty) = self.parse_ret_ty();
         let decl = ast::fn_decl {
             inputs: inputs,
             output: ret_ty,
-            cf: ret_style
+            cf: ret_style,
+            variadic: variadic
         };
         (decl, lifetimes)
     }
@@ -2475,7 +2472,8 @@ impl Parser {
                               node: ty_infer,
                               span: *self.span
                           },
-                          cf: return_val
+                          cf: return_val,
+                          variadic: false
                       }
                   }
                 }
@@ -3526,21 +3524,63 @@ impl Parser {
         (lifetimes, opt_vec::take_vec(result))
     }
 
-    // parse the argument list and result type of a function declaration
-    pub fn parse_fn_decl(&self) -> fn_decl {
-        let args: ~[arg] =
+    fn parse_fn_args(&self, named_args: bool, allow_variadic: bool) -> (~[arg], bool) {
+        let sp = *self.span;
+        let mut args: ~[Option<arg>] =
             self.parse_unspanned_seq(
                 &token::LPAREN,
                 &token::RPAREN,
                 seq_sep_trailing_disallowed(token::COMMA),
-                |p| p.parse_arg()
+                |p| {
+                    if *p.token == token::DOTDOTDOT {
+                        p.bump();
+                        if allow_variadic {
+                            if *p.token != token::RPAREN {
+                                p.span_fatal(*p.span,
+                                    "`...` must be last in argument list for variadic function");
+                            }
+                        } else {
+                            p.span_fatal(*p.span,
+                                         "only foreign functions are allowed to be variadic");
+                        }
+                        None
+                    } else {
+                        Some(p.parse_arg_general(named_args))
+                    }
+                }
             );
 
+        let variadic = match args.pop_opt() {
+            Some(None) => true,
+            Some(x) => {
+                // Need to put back that last arg
+                args.push(x);
+                false
+            }
+            None => false
+        };
+
+        if variadic && args.is_empty() {
+            self.span_err(sp,
+                          "variadic function must be declared with at least one named argument");
+        }
+
+        let args = args.move_iter().map(|x| x.unwrap()).collect();
+
+        (args, variadic)
+    }
+
+    // parse the argument list and result type of a function declaration
+    pub fn parse_fn_decl(&self, allow_variadic: bool) -> fn_decl {
+
+        let (args, variadic) = self.parse_fn_args(true, allow_variadic);
         let (ret_style, ret_ty) = self.parse_ret_ty();
+
         ast::fn_decl {
             inputs: args,
             output: ret_ty,
             cf: ret_style,
+            variadic: variadic
         }
     }
 
@@ -3729,7 +3769,8 @@ impl Parser {
         let fn_decl = ast::fn_decl {
             inputs: fn_inputs,
             output: ret_ty,
-            cf: ret_style
+            cf: ret_style,
+            variadic: false
         };
 
         (spanned(lo, hi, explicit_self), fn_decl)
@@ -3759,6 +3800,7 @@ impl Parser {
             inputs: inputs_captures,
             output: output,
             cf: return_val,
+            variadic: false
         }
     }
 
@@ -3784,6 +3826,7 @@ impl Parser {
             inputs: inputs,
             output: output,
             cf: return_val,
+            variadic: false
         }
     }
 
@@ -3808,7 +3851,7 @@ impl Parser {
     // parse an item-position function declaration.
     fn parse_item_fn(&self, purity: purity, abis: AbiSet) -> item_info {
         let (ident, generics) = self.parse_fn_header();
-        let decl = self.parse_fn_decl();
+        let decl = self.parse_fn_decl(false);
         let (inner_attrs, body) = self.parse_inner_attrs_and_block();
         (ident,
          item_fn(decl, purity, abis, generics, body),
@@ -4239,7 +4282,7 @@ impl Parser {
         }
 
         let (ident, generics) = self.parse_fn_header();
-        let decl = self.parse_fn_decl();
+        let decl = self.parse_fn_decl(true);
         let hi = self.span.hi;
         self.expect(&token::SEMI);
         @ast::foreign_item { ident: ident,
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 3d8fa1b6728..63f4f97889c 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -54,6 +54,7 @@ pub enum Token {
     AT,
     DOT,
     DOTDOT,
+    DOTDOTDOT,
     COMMA,
     SEMI,
     COLON,
@@ -147,6 +148,7 @@ pub fn to_str(input: @ident_interner, t: &Token) -> ~str {
       AT => ~"@",
       DOT => ~".",
       DOTDOT => ~"..",
+      DOTDOTDOT => ~"...",
       COMMA => ~",",
       SEMI => ~";",
       COLON => ~":",
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 0eb1045efe9..08c2ae88e4f 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1774,6 +1774,9 @@ pub fn print_fn_args_and_ret(s: @ps, decl: &ast::fn_decl,
                              opt_explicit_self: Option<ast::explicit_self_>) {
     popen(s);
     print_fn_args(s, decl, opt_explicit_self);
+    if decl.variadic {
+        word(s.s, ", ...");
+    }
     pclose(s);
 
     maybe_print_comment(s, decl.output.span.lo);
@@ -2066,6 +2069,9 @@ pub fn print_ty_fn(s: @ps,
 
         opt_bounds.as_ref().map(|bounds| print_bounds(s, bounds, true));
     } else {
+        if decl.variadic {
+            word(s.s, ", ...");
+        }
         pclose(s);
     }
 
@@ -2408,7 +2414,8 @@ mod test {
             output: ast::Ty {id: 0,
                               node: ast::ty_nil,
                               span: codemap::dummy_sp()},
-            cf: ast::return_val
+            cf: ast::return_val,
+            variadic: false
         };
         let generics = ast_util::empty_generics();
         assert_eq!(&fun_to_str(&decl, ast::impure_fn, abba_ident,