about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2013-03-13 22:25:28 -0400
committerBrian Anderson <banderson@mozilla.com>2013-03-29 18:36:20 -0700
commit6965fe4bceea836586bd8e7aa01a92a35b467f78 (patch)
treed95089f050cd67db2a5171a799763faa09f5b0a8 /src/libsyntax/parse
parentf864934f548be9f03d2c0512de8d7e908469e2ae (diff)
downloadrust-6965fe4bceea836586bd8e7aa01a92a35b467f78.tar.gz
rust-6965fe4bceea836586bd8e7aa01a92a35b467f78.zip
Add AbiSet and integrate it into the AST.
I believe this patch incorporates all expected syntax changes from extern
function reform (#3678). You can now write things like:

    extern "<abi>" fn foo(s: S) -> T { ... }
    extern "<abi>" mod { ... }
    extern "<abi>" fn(S) -> T

The ABI for foreign functions is taken from this syntax (rather than from an
annotation).  We support the full ABI specification I described on the mailing
list.  The correct ABI is chosen based on the target architecture.

Calls by pointer to C functions are not yet supported, and the Rust type of
crust fns is still *u8.
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/parser.rs113
1 files changed, 75 insertions, 38 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index ac0e42fc65d..353e3014cf7 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -10,7 +10,9 @@
 
 use core::prelude::*;
 
-use ast::{Sigil, BorrowedSigil, ManagedSigil, OwnedSigil, RustAbi};
+use abi;
+use abi::AbiSet;
+use ast::{Sigil, BorrowedSigil, ManagedSigil, OwnedSigil};
 use ast::{CallSugar, NoSugar, DoSugar, ForSugar};
 use ast::{TyBareFn, TyClosure};
 use ast::{RegionTyParamBound, TraitTyParamBound};
@@ -361,11 +363,13 @@ pub impl Parser {
 
         */
 
+        let opt_abis = self.parse_opt_abis();
+        let abis = opt_abis.get_or_default(AbiSet::Rust());
         let purity = self.parse_purity();
         self.expect_keyword(&~"fn");
         let (decl, lifetimes) = self.parse_ty_fn_decl();
         return ty_bare_fn(@TyBareFn {
-            abi: RustAbi,
+            abis: abis,
             purity: purity,
             lifetimes: lifetimes,
             decl: decl
@@ -3041,11 +3045,13 @@ pub impl Parser {
                      span: mk_sp(lo, hi) }
     }
 
-    fn parse_item_fn(&self, purity: purity) -> item_info {
+    fn parse_item_fn(&self, purity: purity, abis: AbiSet) -> item_info {
         let (ident, generics) = self.parse_fn_header();
         let decl = self.parse_fn_decl(|p| p.parse_arg());
         let (inner_attrs, body) = self.parse_inner_attrs_and_block(true);
-        (ident, item_fn(decl, purity, generics, body), Some(inner_attrs))
+        (ident,
+         item_fn(decl, purity, abis, generics, body),
+         Some(inner_attrs))
     }
 
     fn parse_method(&self) -> @method {
@@ -3607,7 +3613,7 @@ pub impl Parser {
     }
 
     fn parse_foreign_mod_items(&self, sort: ast::foreign_mod_sort,
-                               +abi: ast::ident,
+                               +abis: AbiSet,
                                +first_item_attrs: ~[attribute])
                             -> foreign_mod {
         // Shouldn't be any view items since we've already parsed an item attr
@@ -3630,30 +3636,20 @@ pub impl Parser {
         }
         ast::foreign_mod {
             sort: sort,
-            abi: abi,
+            abis: abis,
             view_items: view_items,
             items: items
         }
     }
 
-    fn parse_item_foreign_mod(&self, lo: BytePos,
+    fn parse_item_foreign_mod(&self,
+                              lo: BytePos,
+                              opt_abis: Option<AbiSet>,
                               visibility: visibility,
                               attrs: ~[attribute],
                               items_allowed: bool)
-                           -> item_or_view_item {
-
-        // Parse the ABI.
-        let abi_opt;
-        match *self.token {
-            token::LIT_STR(copy found_abi) => {
-                self.bump();
-                abi_opt = Some(found_abi);
-            }
-            _ => {
-                abi_opt = None;
-            }
-        }
-
+                           -> item_or_view_item
+    {
         let mut must_be_named_mod = false;
         if self.is_keyword(&~"mod") {
             must_be_named_mod = true;
@@ -3688,14 +3684,10 @@ pub impl Parser {
 
         // extern mod { ... }
         if items_allowed && self.eat(&token::LBRACE) {
-            let abi;
-            match abi_opt {
-                Some(found_abi) => abi = found_abi,
-                None => abi = special_idents::c_abi,
-            }
+            let abis = opt_abis.get_or_default(AbiSet::C());
 
             let (inner, next) = self.parse_inner_attrs_and_next();
-            let m = self.parse_foreign_mod_items(sort, abi, next);
+            let m = self.parse_foreign_mod_items(sort, abis, next);
             self.expect(&token::RBRACE);
 
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident,
@@ -3704,12 +3696,8 @@ pub impl Parser {
                                                        Some(inner))));
         }
 
-        match abi_opt {
-            None => {}  // OK.
-            Some(_) => {
-                self.span_err(*self.span, ~"an ABI may not be specified \
-                                                here");
-            }
+        if opt_abis.is_some() {
+            self.span_err(*self.span, ~"an ABI may not be specified here");
         }
 
         // extern mod foo;
@@ -3913,6 +3901,49 @@ pub impl Parser {
         }
     }
 
+    fn parse_opt_abis(&self) -> Option<AbiSet> {
+        match *self.token {
+            token::LIT_STR(s) => {
+                self.bump();
+                let the_string = self.id_to_str(s);
+                let mut words = ~[];
+                for str::each_word(*the_string) |s| { words.push(s) }
+                let mut abis = AbiSet::empty();
+                for words.each |word| {
+                    match abi::lookup(*word) {
+                        Some(abi) => {
+                            if abis.contains(abi) {
+                                self.span_err(
+                                    *self.span,
+                                    fmt!("ABI `%s` appears twice",
+                                         *word));
+                            } else {
+                                abis.add(abi);
+                            }
+                        }
+
+                        None => {
+                            self.span_err(
+                                *self.span,
+                                fmt!("illegal ABI: \
+                                      expected one of [%s], \
+                                      found `%s`",
+                                     str::connect_slices(
+                                         abi::all_names(),
+                                         ", "),
+                                     *word));
+                        }
+                    }
+                }
+                Some(abis)
+            }
+
+            _ => {
+                None
+            }
+        }
+    }
+
     // parse one of the items or view items allowed by the
     // flags; on failure, return iovi_none.
     fn parse_item_or_view_item(
@@ -3961,7 +3992,8 @@ pub impl Parser {
             self.is_keyword(&~"fn") &&
             !self.fn_expr_lookahead(self.look_ahead(1u)) {
             self.bump();
-            let (ident, item_, extra_attrs) = self.parse_item_fn(impure_fn);
+            let (ident, item_, extra_attrs) =
+                self.parse_item_fn(impure_fn, AbiSet::Rust());
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
@@ -3970,7 +4002,8 @@ pub impl Parser {
             // PURE FUNCTION ITEM
             self.obsolete(*self.last_span, ObsoletePurity);
             self.expect_keyword(&~"fn");
-            let (ident, item_, extra_attrs) = self.parse_item_fn(impure_fn);
+            let (ident, item_, extra_attrs) =
+                self.parse_item_fn(impure_fn, AbiSet::Rust());
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
@@ -3987,16 +4020,20 @@ pub impl Parser {
             // UNSAFE FUNCTION ITEM (where items are allowed)
             self.bump();
             self.expect_keyword(&~"fn");
-            let (ident, item_, extra_attrs) = self.parse_item_fn(unsafe_fn);
+            let (ident, item_, extra_attrs) =
+                self.parse_item_fn(unsafe_fn, AbiSet::Rust());
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
         if self.eat_keyword(&~"extern") {
+            let opt_abis = self.parse_opt_abis();
+
             if items_allowed && self.eat_keyword(&~"fn") {
                 // EXTERN FUNCTION ITEM
+                let abis = opt_abis.get_or_default(AbiSet::C());
                 let (ident, item_, extra_attrs) =
-                    self.parse_item_fn(extern_fn);
+                    self.parse_item_fn(extern_fn, abis);
                 return iovi_item(self.mk_item(lo, self.last_span.hi, ident,
                                               item_, visibility,
                                               maybe_append(attrs,
@@ -4004,7 +4041,7 @@ pub impl Parser {
             }
             if !foreign_items_allowed {
                 // EXTERN MODULE ITEM
-                return self.parse_item_foreign_mod(lo, visibility, attrs,
+                return self.parse_item_foreign_mod(lo, opt_abis, visibility, attrs,
                                                    items_allowed);
             }
         }