2012-03-16 22:14:37 +00:00
|
|
|
import result::result;
|
|
|
|
import either::{either, left, right};
|
2012-03-14 19:07:23 +00:00
|
|
|
import std::map::{hashmap, str_hash};
|
2012-04-18 04:14:40 +00:00
|
|
|
import token::{can_begin_expr, is_ident, is_plain_ident};
|
2012-02-10 10:03:21 +00:00
|
|
|
import codemap::{span,fss_none};
|
2011-07-05 09:48:19 +00:00
|
|
|
import util::interner;
|
2012-04-26 23:13:59 +00:00
|
|
|
import ast_util::{spanned, mk_sp, ident_to_path, operator_prec};
|
2012-05-08 14:07:32 +00:00
|
|
|
import ast::*;
|
2012-01-13 08:56:53 +00:00
|
|
|
import lexer::reader;
|
2012-04-26 23:13:59 +00:00
|
|
|
import prec::{as_prec, token_to_binop};
|
2012-04-20 03:51:31 +00:00
|
|
|
import attr::{parse_outer_attrs_or_ext,
|
|
|
|
parse_inner_attrs_and_next,
|
|
|
|
parse_outer_attributes,
|
|
|
|
parse_optional_meta};
|
2012-04-20 04:18:33 +00:00
|
|
|
import common::*;
|
2012-05-10 14:24:56 +00:00
|
|
|
import dvec::{dvec, extensions};
|
2010-08-18 22:41:13 +00:00
|
|
|
|
2012-04-18 06:34:48 +00:00
|
|
|
export expect;
|
2012-04-18 02:34:44 +00:00
|
|
|
export file_type;
|
|
|
|
export mk_item;
|
2012-04-18 06:34:48 +00:00
|
|
|
export restriction;
|
2012-04-18 02:34:44 +00:00
|
|
|
export parser;
|
2012-04-18 06:34:48 +00:00
|
|
|
export parse_crate_directives;
|
2012-04-18 02:34:44 +00:00
|
|
|
export parse_crate_mod;
|
|
|
|
export parse_expr;
|
|
|
|
export parse_item;
|
|
|
|
export parse_mod_items;
|
|
|
|
export parse_pat;
|
2012-04-20 03:51:31 +00:00
|
|
|
export parse_seq;
|
2012-04-18 02:34:44 +00:00
|
|
|
export parse_stmt;
|
|
|
|
export parse_ty;
|
2012-04-20 03:51:31 +00:00
|
|
|
export parse_lit;
|
|
|
|
export parse_syntax_ext_naked;
|
|
|
|
|
2012-04-18 06:34:48 +00:00
|
|
|
// FIXME: #ast expects to find this here but it's actually defined in `parse`
|
2012-04-20 02:17:59 +00:00
|
|
|
// Fixing this will be easier when we have export decls on individual items --
|
|
|
|
// then parse can export this publicly, and everything else crate-visibly.
|
|
|
|
// (See #1893)
|
2012-04-18 06:34:48 +00:00
|
|
|
import parse_from_source_str;
|
|
|
|
export parse_from_source_str;
|
|
|
|
|
2012-01-19 22:24:03 +00:00
|
|
|
enum restriction {
|
2012-01-20 01:56:05 +00:00
|
|
|
UNRESTRICTED,
|
|
|
|
RESTRICT_STMT_EXPR,
|
|
|
|
RESTRICT_NO_CALL_EXPRS,
|
|
|
|
RESTRICT_NO_BAR_OP,
|
2011-12-21 04:12:52 +00:00
|
|
|
}
|
2011-01-24 23:26:10 +00:00
|
|
|
|
2012-01-20 01:56:05 +00:00
|
|
|
enum file_type { CRATE_FILE, SOURCE_FILE, }
|
2011-02-25 01:00:24 +00:00
|
|
|
|
2012-01-13 08:56:53 +00:00
|
|
|
type parser = @{
|
|
|
|
sess: parse_sess,
|
2012-05-08 14:07:32 +00:00
|
|
|
cfg: crate_cfg,
|
2012-01-13 08:56:53 +00:00
|
|
|
file_type: file_type,
|
2012-03-27 01:35:18 +00:00
|
|
|
mut token: token::token,
|
|
|
|
mut span: span,
|
|
|
|
mut last_span: span,
|
2012-05-10 14:24:56 +00:00
|
|
|
buffer: dvec<{tok: token::token, span: span}>,
|
2012-03-27 01:35:18 +00:00
|
|
|
mut restriction: restriction,
|
2012-01-13 08:56:53 +00:00
|
|
|
reader: reader,
|
2012-04-19 23:44:24 +00:00
|
|
|
keywords: hashmap<str, ()>,
|
2012-04-25 05:33:49 +00:00
|
|
|
restricted_keywords: hashmap<str, ()>
|
2012-01-13 08:56:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
impl parser for parser {
|
|
|
|
fn bump() {
|
|
|
|
self.last_span = self.span;
|
2012-05-10 14:24:56 +00:00
|
|
|
if self.buffer.len() == 0u {
|
2012-01-13 08:56:53 +00:00
|
|
|
let next = lexer::next_token(self.reader);
|
|
|
|
self.token = next.tok;
|
2012-04-23 11:04:46 +00:00
|
|
|
self.span = mk_sp(next.chpos, self.reader.chpos);
|
2012-01-13 08:56:53 +00:00
|
|
|
} else {
|
2012-05-10 14:24:56 +00:00
|
|
|
let next = self.buffer.shift();
|
2012-01-13 08:56:53 +00:00
|
|
|
self.token = next.tok;
|
|
|
|
self.span = next.span;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn swap(next: token::token, lo: uint, hi: uint) {
|
|
|
|
self.token = next;
|
2012-04-23 11:04:46 +00:00
|
|
|
self.span = mk_sp(lo, hi);
|
2012-01-13 08:56:53 +00:00
|
|
|
}
|
|
|
|
fn look_ahead(distance: uint) -> token::token {
|
2012-05-10 14:24:56 +00:00
|
|
|
while self.buffer.len() < distance {
|
2012-01-13 08:56:53 +00:00
|
|
|
let next = lexer::next_token(self.reader);
|
2012-04-23 11:04:46 +00:00
|
|
|
let sp = mk_sp(next.chpos, self.reader.chpos);
|
2012-05-10 14:24:56 +00:00
|
|
|
self.buffer.push({tok: next.tok, span: sp});
|
2012-01-13 08:56:53 +00:00
|
|
|
}
|
|
|
|
ret self.buffer[distance - 1u].tok;
|
|
|
|
}
|
|
|
|
fn fatal(m: str) -> ! {
|
2012-01-25 05:42:54 +00:00
|
|
|
self.sess.span_diagnostic.span_fatal(self.span, m)
|
2012-01-13 08:56:53 +00:00
|
|
|
}
|
|
|
|
fn span_fatal(sp: span, m: str) -> ! {
|
2012-01-25 05:42:54 +00:00
|
|
|
self.sess.span_diagnostic.span_fatal(sp, m)
|
2012-01-13 08:56:53 +00:00
|
|
|
}
|
2012-04-19 23:44:24 +00:00
|
|
|
fn bug(m: str) -> ! {
|
|
|
|
self.sess.span_diagnostic.span_bug(self.span, m)
|
|
|
|
}
|
2012-01-13 08:56:53 +00:00
|
|
|
fn warn(m: str) {
|
2012-01-25 05:42:54 +00:00
|
|
|
self.sess.span_diagnostic.span_warn(self.span, m)
|
2012-01-13 08:56:53 +00:00
|
|
|
}
|
|
|
|
fn get_str(i: token::str_num) -> str {
|
|
|
|
interner::get(*self.reader.interner, i)
|
|
|
|
}
|
|
|
|
fn get_id() -> node_id { next_node_id(self.sess) }
|
|
|
|
}
|
2010-08-18 22:41:13 +00:00
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_ty_fn(p: parser) -> fn_decl {
|
|
|
|
fn parse_fn_input_ty(p: parser) -> arg {
|
2011-09-12 09:27:30 +00:00
|
|
|
let mode = parse_arg_mode(p);
|
2012-04-18 04:14:40 +00:00
|
|
|
let name = if is_plain_ident(p.token)
|
|
|
|
&& p.look_ahead(1u) == token::COLON {
|
|
|
|
|
2011-12-22 16:49:54 +00:00
|
|
|
let name = parse_value_ident(p);
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
2011-12-22 16:49:54 +00:00
|
|
|
name
|
|
|
|
} else { "" };
|
|
|
|
ret {mode: mode, ty: parse_ty(p, false), ident: name, id: p.get_id()};
|
2010-11-05 22:23:03 +00:00
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
let inputs =
|
2011-11-21 15:36:11 +00:00
|
|
|
parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
|
2011-07-27 12:19:39 +00:00
|
|
|
parse_fn_input_ty, p);
|
2012-04-20 02:17:59 +00:00
|
|
|
// FIXME: constrs is empty because right now, higher-order functions
|
|
|
|
// can't have constrained types.
|
|
|
|
// Not sure whether that would be desirable anyway. See #34 for the
|
|
|
|
// story on constrained types.
|
2012-05-08 14:07:32 +00:00
|
|
|
let constrs: [@constr] = [];
|
2011-11-23 09:56:10 +00:00
|
|
|
let (ret_style, ret_ty) = parse_ret_ty(p);
|
2012-01-31 05:00:57 +00:00
|
|
|
ret {inputs: inputs.node, output: ret_ty,
|
2012-05-08 14:07:32 +00:00
|
|
|
purity: impure_fn, cf: ret_style,
|
2012-02-13 17:56:09 +00:00
|
|
|
constraints: constrs};
|
2011-02-19 01:30:57 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_ty_methods(p: parser) -> [ty_method] {
|
2011-12-22 07:45:18 +00:00
|
|
|
parse_seq(token::LBRACE, token::RBRACE, seq_sep_none(), {|p|
|
2012-01-30 19:43:45 +00:00
|
|
|
let attrs = parse_outer_attributes(p);
|
2012-01-13 08:56:53 +00:00
|
|
|
let flo = p.span.lo;
|
2012-02-13 17:56:09 +00:00
|
|
|
let pur = parse_fn_purity(p);
|
2012-01-26 14:52:28 +00:00
|
|
|
let ident = parse_method_name(p);
|
2012-01-13 09:58:31 +00:00
|
|
|
let tps = parse_ty_params(p);
|
2012-01-31 05:00:57 +00:00
|
|
|
let d = parse_ty_fn(p), fhi = p.last_span.hi;
|
2011-05-12 15:24:54 +00:00
|
|
|
expect(p, token::SEMI);
|
2012-02-13 17:56:09 +00:00
|
|
|
{ident: ident, attrs: attrs, decl: {purity: pur with d}, tps: tps,
|
2012-04-23 11:04:46 +00:00
|
|
|
span: mk_sp(flo, fhi)}
|
2012-02-13 17:56:09 +00:00
|
|
|
}, p).node
|
2010-12-15 01:42:12 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_mt(p: parser) -> mt {
|
2012-02-15 19:25:39 +00:00
|
|
|
let mutbl = parse_mutability(p);
|
2011-08-15 19:06:10 +00:00
|
|
|
let t = parse_ty(p, false);
|
2012-02-15 19:25:39 +00:00
|
|
|
ret {ty: t, mutbl: mutbl};
|
2011-03-18 00:39:47 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_ty_field(p: parser) -> ty_field {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2012-02-15 19:25:39 +00:00
|
|
|
let mutbl = parse_mutability(p);
|
2011-07-27 12:19:39 +00:00
|
|
|
let id = parse_ident(p);
|
2011-07-25 15:37:58 +00:00
|
|
|
expect(p, token::COLON);
|
2011-08-15 19:06:10 +00:00
|
|
|
let ty = parse_ty(p, false);
|
2012-02-15 19:25:39 +00:00
|
|
|
ret spanned(lo, ty.span.hi, {ident: id, mt: {ty: ty, mutbl: mutbl}});
|
2011-07-25 15:37:58 +00:00
|
|
|
}
|
2011-06-15 18:19:50 +00:00
|
|
|
|
2011-06-11 02:12:42 +00:00
|
|
|
// if i is the jth ident in args, return j
|
|
|
|
// otherwise, fail
|
2012-05-08 14:07:32 +00:00
|
|
|
fn ident_index(p: parser, args: [arg], i: ident) -> uint {
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut j = 0u;
|
2012-04-06 18:01:43 +00:00
|
|
|
for args.each {|a| if a.ident == i { ret j; } j += 1u; }
|
2012-03-06 00:27:27 +00:00
|
|
|
p.fatal("unbound variable `" + i + "` in constraint arg");
|
2011-06-11 02:12:42 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_type_constr_arg(p: parser) -> @ty_constr_arg {
|
2012-01-13 08:56:53 +00:00
|
|
|
let sp = p.span;
|
2012-05-08 14:07:32 +00:00
|
|
|
let mut carg = carg_base;
|
2011-07-20 00:52:34 +00:00
|
|
|
expect(p, token::BINOP(token::STAR));
|
2012-01-13 08:56:53 +00:00
|
|
|
if p.token == token::DOT {
|
2011-07-20 00:52:34 +00:00
|
|
|
// "*..." notation for record fields
|
|
|
|
p.bump();
|
2012-04-24 22:52:52 +00:00
|
|
|
let pth = parse_path_without_tps(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
carg = carg_ident(pth);
|
2011-07-20 00:52:34 +00:00
|
|
|
}
|
|
|
|
// No literals yet, I guess?
|
2011-07-27 12:19:39 +00:00
|
|
|
ret @{node: carg, span: sp};
|
2011-07-20 00:52:34 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_constr_arg(args: [arg], p: parser) -> @constr_arg {
|
2012-01-13 08:56:53 +00:00
|
|
|
let sp = p.span;
|
2012-05-08 14:07:32 +00:00
|
|
|
let mut carg = carg_base;
|
2012-01-13 08:56:53 +00:00
|
|
|
if p.token == token::BINOP(token::STAR) {
|
2011-03-04 22:15:19 +00:00
|
|
|
p.bump();
|
|
|
|
} else {
|
2012-05-08 14:07:32 +00:00
|
|
|
let i: ident = parse_value_ident(p);
|
|
|
|
carg = carg_ident(ident_index(p, args, i));
|
2011-03-04 22:15:19 +00:00
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
ret @{node: carg, span: sp};
|
2011-03-04 22:15:19 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_ty_constr(fn_args: [arg], p: parser) -> @constr {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2012-04-24 22:52:52 +00:00
|
|
|
let path = parse_path_without_tps(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
let args: {node: [@constr_arg], span: span} =
|
2011-11-21 15:36:11 +00:00
|
|
|
parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
|
2011-10-28 14:41:56 +00:00
|
|
|
{|p| parse_constr_arg(fn_args, p)}, p);
|
2011-06-11 02:12:42 +00:00
|
|
|
ret @spanned(lo, args.span.hi,
|
2011-07-27 12:19:39 +00:00
|
|
|
{path: path, args: args.node, id: p.get_id()});
|
2011-03-04 22:15:19 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_constr_in_type(p: parser) -> @ty_constr {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2012-04-24 22:52:52 +00:00
|
|
|
let path = parse_path_without_tps(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
let args: [@ty_constr_arg] =
|
2011-11-21 15:36:11 +00:00
|
|
|
parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
|
2011-07-27 12:19:39 +00:00
|
|
|
parse_type_constr_arg, p).node;
|
2012-01-13 08:56:53 +00:00
|
|
|
let hi = p.span.lo;
|
2012-05-08 14:07:32 +00:00
|
|
|
let tc: ty_constr_ = {path: path, args: args, id: p.get_id()};
|
2011-07-20 00:52:34 +00:00
|
|
|
ret @spanned(lo, hi, tc);
|
2011-03-04 22:15:19 +00:00
|
|
|
}
|
|
|
|
|
2011-07-20 00:52:34 +00:00
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_constrs<T: copy>(pser: fn(parser) -> @constr_general<T>,
|
2011-11-18 11:39:20 +00:00
|
|
|
p: parser) ->
|
2012-05-08 14:07:32 +00:00
|
|
|
[@constr_general<T>] {
|
|
|
|
let mut constrs: [@constr_general<T>] = [];
|
2012-03-11 04:34:17 +00:00
|
|
|
loop {
|
2011-07-27 12:19:39 +00:00
|
|
|
let constr = pser(p);
|
2011-08-19 22:16:48 +00:00
|
|
|
constrs += [constr];
|
2012-03-11 04:34:17 +00:00
|
|
|
if p.token == token::COMMA { p.bump(); } else { ret constrs; }
|
|
|
|
};
|
2011-07-20 00:52:34 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_type_constraints(p: parser) -> [@ty_constr] {
|
2011-07-20 00:52:34 +00:00
|
|
|
ret parse_constrs(parse_constr_in_type, p);
|
2011-03-04 22:15:19 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_ret_ty(p: parser) -> (ret_style, @ty) {
|
2011-09-14 08:46:40 +00:00
|
|
|
ret if eat(p, token::RARROW) {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2011-09-14 08:46:40 +00:00
|
|
|
if eat(p, token::NOT) {
|
2012-05-08 14:07:32 +00:00
|
|
|
(noreturn, @{id: p.get_id(),
|
|
|
|
node: ty_bot,
|
2012-04-23 11:04:46 +00:00
|
|
|
span: mk_sp(lo, p.last_span.hi)})
|
2012-03-12 23:26:31 +00:00
|
|
|
} else {
|
2012-05-08 14:07:32 +00:00
|
|
|
(return_val, parse_ty(p, false))
|
2012-03-12 23:26:31 +00:00
|
|
|
}
|
2011-09-14 08:38:23 +00:00
|
|
|
} else {
|
2012-01-13 08:56:53 +00:00
|
|
|
let pos = p.span.lo;
|
2012-05-08 14:07:32 +00:00
|
|
|
(return_val, @{id: p.get_id(),
|
|
|
|
node: ty_nil,
|
2012-04-23 11:04:46 +00:00
|
|
|
span: mk_sp(pos, pos)})
|
2011-05-15 02:02:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn region_from_name(p: parser, s: option<str>) -> @region {
|
2012-04-10 00:32:49 +00:00
|
|
|
let r = alt s {
|
2012-05-08 14:07:32 +00:00
|
|
|
some (string) { re_named(string) }
|
|
|
|
none { re_anon }
|
2012-03-10 00:10:11 +00:00
|
|
|
};
|
2012-04-10 00:32:49 +00:00
|
|
|
|
2012-04-24 22:52:52 +00:00
|
|
|
@{id: p.get_id(), node: r}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parses something like "&x"
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_region(p: parser) -> @region {
|
2012-04-24 22:52:52 +00:00
|
|
|
expect(p, token::BINOP(token::AND));
|
|
|
|
alt p.token {
|
|
|
|
token::IDENT(sid, _) {
|
|
|
|
p.bump();
|
|
|
|
let n = p.get_str(sid);
|
|
|
|
region_from_name(p, some(n))
|
|
|
|
}
|
|
|
|
_ {
|
|
|
|
region_from_name(p, none)
|
|
|
|
}
|
|
|
|
}
|
2012-04-10 00:32:49 +00:00
|
|
|
}
|
|
|
|
|
2012-04-24 22:52:52 +00:00
|
|
|
// Parses something like "&x." (note the trailing dot)
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_region_dot(p: parser) -> @region {
|
2012-04-10 00:32:49 +00:00
|
|
|
let name =
|
|
|
|
alt p.token {
|
|
|
|
token::IDENT(sid, _) if p.look_ahead(1u) == token::DOT {
|
|
|
|
p.bump(); p.bump();
|
|
|
|
some(p.get_str(sid))
|
|
|
|
}
|
|
|
|
_ { none }
|
|
|
|
};
|
|
|
|
region_from_name(p, name)
|
2012-03-08 19:26:31 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_ty(p: parser, colons_before_params: bool) -> @ty {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2012-02-01 23:19:45 +00:00
|
|
|
|
2012-04-22 23:58:04 +00:00
|
|
|
alt maybe_parse_dollar_mac(p) {
|
2012-03-12 23:26:31 +00:00
|
|
|
some(e) {
|
|
|
|
ret @{id: p.get_id(),
|
2012-05-08 14:07:32 +00:00
|
|
|
node: ty_mac(spanned(lo, p.span.hi, e)),
|
2012-04-23 11:04:46 +00:00
|
|
|
span: mk_sp(lo, p.span.hi)};
|
2012-03-12 23:26:31 +00:00
|
|
|
}
|
2012-02-01 23:19:45 +00:00
|
|
|
none {}
|
|
|
|
}
|
|
|
|
|
2012-02-06 14:29:56 +00:00
|
|
|
let t = if p.token == token::LPAREN {
|
2011-05-13 19:30:08 +00:00
|
|
|
p.bump();
|
2012-01-13 08:56:53 +00:00
|
|
|
if p.token == token::RPAREN {
|
2011-08-15 10:18:27 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
ty_nil
|
2011-08-15 10:18:27 +00:00
|
|
|
} else {
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut ts = [parse_ty(p, false)];
|
2012-01-13 08:56:53 +00:00
|
|
|
while p.token == token::COMMA {
|
2011-08-15 10:18:27 +00:00
|
|
|
p.bump();
|
2011-08-19 22:16:48 +00:00
|
|
|
ts += [parse_ty(p, false)];
|
2011-08-15 10:18:27 +00:00
|
|
|
}
|
2012-02-06 14:29:56 +00:00
|
|
|
let t = if vec::len(ts) == 1u { ts[0].node }
|
2012-05-08 14:07:32 +00:00
|
|
|
else { ty_tup(ts) };
|
2011-07-27 12:19:39 +00:00
|
|
|
expect(p, token::RPAREN);
|
2012-02-06 14:29:56 +00:00
|
|
|
t
|
2011-02-19 01:30:57 +00:00
|
|
|
}
|
2012-01-13 08:56:53 +00:00
|
|
|
} else if p.token == token::AT {
|
2011-05-13 19:30:08 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
ty_box(parse_mt(p))
|
2012-01-13 08:56:53 +00:00
|
|
|
} else if p.token == token::TILDE {
|
2011-09-20 23:07:09 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
ty_uniq(parse_mt(p))
|
2012-01-13 08:56:53 +00:00
|
|
|
} else if p.token == token::BINOP(token::STAR) {
|
2011-06-03 18:34:19 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
ty_ptr(parse_mt(p))
|
2012-01-13 08:56:53 +00:00
|
|
|
} else if p.token == token::LBRACE {
|
2011-07-27 12:19:39 +00:00
|
|
|
let elems =
|
2011-11-21 15:36:11 +00:00
|
|
|
parse_seq(token::LBRACE, token::RBRACE, seq_sep_opt(token::COMMA),
|
2011-07-27 12:19:39 +00:00
|
|
|
parse_ty_field, p);
|
2012-03-20 14:05:14 +00:00
|
|
|
if vec::len(elems.node) == 0u { unexpected_last(p, token::RBRACE); }
|
2011-11-02 10:42:31 +00:00
|
|
|
let hi = elems.span.hi;
|
2012-02-06 14:29:56 +00:00
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
let t = ty_rec(elems.node);
|
2012-01-13 08:56:53 +00:00
|
|
|
if p.token == token::COLON {
|
2011-07-25 15:37:58 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
ty_constr(@{id: p.get_id(),
|
2012-03-12 23:26:31 +00:00
|
|
|
node: t,
|
2012-04-23 11:04:46 +00:00
|
|
|
span: mk_sp(lo, hi)},
|
2012-03-12 23:26:31 +00:00
|
|
|
parse_type_constraints(p))
|
2012-02-06 14:29:56 +00:00
|
|
|
} else { t }
|
2012-01-13 08:56:53 +00:00
|
|
|
} else if p.token == token::LBRACKET {
|
2011-07-18 15:41:35 +00:00
|
|
|
expect(p, token::LBRACKET);
|
2012-05-08 14:07:32 +00:00
|
|
|
let t = ty_vec(parse_mt(p));
|
2011-07-18 15:41:35 +00:00
|
|
|
expect(p, token::RBRACKET);
|
2012-02-06 14:29:56 +00:00
|
|
|
t
|
2012-03-08 19:26:31 +00:00
|
|
|
} else if p.token == token::BINOP(token::AND) {
|
|
|
|
p.bump();
|
2012-04-24 22:52:52 +00:00
|
|
|
let region = parse_region_dot(p);
|
2012-03-08 19:26:31 +00:00
|
|
|
let mt = parse_mt(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
ty_rptr(region, mt)
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "fn") {
|
2011-10-14 21:57:21 +00:00
|
|
|
let proto = parse_fn_ty_proto(p);
|
2012-01-11 17:58:05 +00:00
|
|
|
alt proto {
|
2012-05-08 14:07:32 +00:00
|
|
|
proto_bare { p.warn("fn is deprecated, use native fn"); }
|
2012-01-11 17:58:05 +00:00
|
|
|
_ { /* fallthrough */ }
|
|
|
|
}
|
2012-05-08 14:07:32 +00:00
|
|
|
ty_fn(proto, parse_ty_fn(p))
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "native") {
|
|
|
|
expect_keyword(p, "fn");
|
2012-05-08 14:07:32 +00:00
|
|
|
ty_fn(proto_bare, parse_ty_fn(p))
|
2012-01-13 08:56:53 +00:00
|
|
|
} else if p.token == token::MOD_SEP || is_ident(p.token) {
|
2012-04-24 22:52:52 +00:00
|
|
|
let path = parse_path_with_tps(p, colons_before_params);
|
2012-05-08 14:07:32 +00:00
|
|
|
ty_path(path, p.get_id())
|
2012-02-06 14:29:56 +00:00
|
|
|
} else { p.fatal("expecting type"); };
|
2012-04-24 22:52:52 +00:00
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn mk_ty(p: parser, t: ty_, lo: uint, hi: uint) -> @ty {
|
2012-04-24 22:52:52 +00:00
|
|
|
@{id: p.get_id(),
|
|
|
|
node: t,
|
|
|
|
span: mk_sp(lo, hi)}
|
|
|
|
}
|
|
|
|
|
|
|
|
let ty = mk_ty(p, t, lo, p.last_span.hi);
|
|
|
|
|
|
|
|
// Consider a vstore suffix like /@ or /~
|
|
|
|
alt maybe_parse_vstore(p) {
|
|
|
|
none {
|
|
|
|
ret ty;
|
|
|
|
}
|
|
|
|
some(v) {
|
2012-05-08 14:07:32 +00:00
|
|
|
let t1 = ty_vstore(ty, v);
|
2012-04-24 22:52:52 +00:00
|
|
|
ret mk_ty(p, t1, lo, p.last_span.hi);
|
|
|
|
}
|
|
|
|
}
|
2010-09-21 23:22:32 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_arg_mode(p: parser) -> mode {
|
2012-02-03 00:50:17 +00:00
|
|
|
if eat(p, token::BINOP(token::AND)) {
|
2012-05-08 14:07:32 +00:00
|
|
|
expl(by_mutbl_ref)
|
2012-02-03 00:50:17 +00:00
|
|
|
} else if eat(p, token::BINOP(token::MINUS)) {
|
2012-05-08 14:07:32 +00:00
|
|
|
expl(by_move)
|
2012-02-03 00:50:17 +00:00
|
|
|
} else if eat(p, token::ANDAND) {
|
2012-05-08 14:07:32 +00:00
|
|
|
expl(by_ref)
|
2012-02-03 00:50:17 +00:00
|
|
|
} else if eat(p, token::BINOP(token::PLUS)) {
|
|
|
|
if eat(p, token::BINOP(token::PLUS)) {
|
2012-05-08 14:07:32 +00:00
|
|
|
expl(by_val)
|
2012-02-03 00:50:17 +00:00
|
|
|
} else {
|
2012-05-08 14:07:32 +00:00
|
|
|
expl(by_copy)
|
2012-02-03 00:50:17 +00:00
|
|
|
}
|
2012-05-08 14:07:32 +00:00
|
|
|
} else { infer(p.get_id()) }
|
2011-08-12 19:58:37 +00:00
|
|
|
}
|
|
|
|
|
2012-05-04 19:33:04 +00:00
|
|
|
fn parse_capture_item_or(
|
|
|
|
p: parser,
|
|
|
|
parse_arg_fn: fn() -> arg_or_capture_item) -> arg_or_capture_item {
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_capture_item(p: parser, is_move: bool) -> capture_item {
|
2012-05-04 19:33:04 +00:00
|
|
|
let id = p.get_id();
|
|
|
|
let sp = mk_sp(p.span.lo, p.span.hi);
|
|
|
|
let ident = parse_ident(p);
|
|
|
|
{id: id, is_move: is_move, name: ident, span: sp}
|
|
|
|
}
|
|
|
|
|
|
|
|
if eat_keyword(p, "move") {
|
|
|
|
either::right(parse_capture_item(p, true))
|
|
|
|
} else if eat_keyword(p, "copy") {
|
|
|
|
either::right(parse_capture_item(p, false))
|
|
|
|
} else {
|
|
|
|
parse_arg_fn()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_arg(p: parser) -> arg_or_capture_item {
|
2011-09-12 09:27:30 +00:00
|
|
|
let m = parse_arg_mode(p);
|
2011-08-12 19:58:37 +00:00
|
|
|
let i = parse_value_ident(p);
|
|
|
|
expect(p, token::COLON);
|
|
|
|
let t = parse_ty(p, false);
|
2012-05-04 19:33:04 +00:00
|
|
|
either::left({mode: m, ty: t, ident: i, id: p.get_id()})
|
2011-08-12 19:58:37 +00:00
|
|
|
}
|
|
|
|
|
2012-05-04 19:33:04 +00:00
|
|
|
fn parse_arg_or_capture_item(p: parser) -> arg_or_capture_item {
|
|
|
|
parse_capture_item_or(p) {|| parse_arg(p) }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_fn_block_arg(p: parser) -> arg_or_capture_item {
|
|
|
|
parse_capture_item_or(p) {||
|
|
|
|
let m = parse_arg_mode(p);
|
|
|
|
let i = parse_value_ident(p);
|
|
|
|
let t = if eat(p, token::COLON) {
|
|
|
|
parse_ty(p, false)
|
|
|
|
} else {
|
|
|
|
@{id: p.get_id(),
|
2012-05-08 14:07:32 +00:00
|
|
|
node: ty_infer,
|
2012-05-04 19:33:04 +00:00
|
|
|
span: mk_sp(p.span.lo, p.span.hi)}
|
|
|
|
};
|
|
|
|
either::left({mode: m, ty: t, ident: i, id: p.get_id()})
|
|
|
|
}
|
2010-09-21 23:22:32 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn maybe_parse_dollar_mac(p: parser) -> option<mac_> {
|
2012-01-25 23:38:09 +00:00
|
|
|
alt p.token {
|
2012-04-22 23:58:04 +00:00
|
|
|
token::DOLLAR {
|
2012-01-27 08:50:57 +00:00
|
|
|
let lo = p.span.lo;
|
|
|
|
p.bump();
|
2012-04-22 23:58:04 +00:00
|
|
|
alt p.token {
|
2012-05-08 14:07:32 +00:00
|
|
|
token::LIT_INT(num, ty_i) {
|
2012-04-22 23:58:04 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
some(mac_var(num as uint))
|
2012-04-22 23:58:04 +00:00
|
|
|
}
|
|
|
|
token::LPAREN {
|
|
|
|
p.bump();
|
|
|
|
let e = parse_expr(p);
|
|
|
|
expect(p, token::RPAREN);
|
|
|
|
let hi = p.last_span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
some(mac_aq(mk_sp(lo,hi), e))
|
2012-04-22 23:58:04 +00:00
|
|
|
}
|
|
|
|
_ {
|
|
|
|
p.fatal("expected `(` or integer literal");
|
|
|
|
}
|
|
|
|
}
|
2012-01-27 08:50:57 +00:00
|
|
|
}
|
|
|
|
_ {none}
|
2012-01-25 23:38:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn maybe_parse_vstore(p: parser) -> option<vstore> {
|
2012-04-10 00:32:49 +00:00
|
|
|
if p.token == token::BINOP(token::SLASH) {
|
|
|
|
p.bump();
|
|
|
|
alt p.token {
|
|
|
|
token::AT {
|
2012-05-08 14:07:32 +00:00
|
|
|
p.bump(); some(vstore_box)
|
2012-04-10 00:32:49 +00:00
|
|
|
}
|
|
|
|
token::TILDE {
|
2012-05-08 14:07:32 +00:00
|
|
|
p.bump(); some(vstore_uniq)
|
2012-04-10 00:32:49 +00:00
|
|
|
}
|
|
|
|
token::UNDERSCORE {
|
2012-05-08 14:07:32 +00:00
|
|
|
p.bump(); some(vstore_fixed(none))
|
2012-04-10 00:32:49 +00:00
|
|
|
}
|
2012-05-08 14:07:32 +00:00
|
|
|
token::LIT_INT(i, ty_i) if i >= 0i64 {
|
|
|
|
p.bump(); some(vstore_fixed(some(i as uint)))
|
2012-04-10 00:32:49 +00:00
|
|
|
}
|
|
|
|
token::BINOP(token::AND) {
|
2012-05-08 14:07:32 +00:00
|
|
|
some(vstore_slice(parse_region(p)))
|
2012-04-10 00:32:49 +00:00
|
|
|
}
|
|
|
|
_ {
|
|
|
|
none
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
none
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn lit_from_token(p: parser, tok: token::token) -> lit_ {
|
2011-10-07 14:22:53 +00:00
|
|
|
alt tok {
|
2012-05-08 14:07:32 +00:00
|
|
|
token::LIT_INT(i, it) { lit_int(i, it) }
|
|
|
|
token::LIT_UINT(u, ut) { lit_uint(u, ut) }
|
|
|
|
token::LIT_FLOAT(s, ft) { lit_float(p.get_str(s), ft) }
|
|
|
|
token::LIT_STR(s) { lit_str(p.get_str(s)) }
|
|
|
|
token::LPAREN { expect(p, token::RPAREN); lit_nil }
|
2012-03-20 14:05:14 +00:00
|
|
|
_ { unexpected_last(p, tok); }
|
2011-10-07 14:22:53 +00:00
|
|
|
}
|
|
|
|
}
|
2011-07-06 00:57:34 +00:00
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_lit(p: parser) -> lit {
|
2012-04-10 00:32:49 +00:00
|
|
|
let lo = p.span.lo;
|
2012-04-25 03:16:53 +00:00
|
|
|
let lit = if eat_keyword(p, "true") {
|
2012-05-08 14:07:32 +00:00
|
|
|
lit_bool(true)
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "false") {
|
2012-05-08 14:07:32 +00:00
|
|
|
lit_bool(false)
|
2011-05-13 19:30:08 +00:00
|
|
|
} else {
|
2012-01-13 08:56:53 +00:00
|
|
|
let tok = p.token;
|
2011-10-07 14:22:53 +00:00
|
|
|
p.bump();
|
|
|
|
lit_from_token(p, tok)
|
|
|
|
};
|
2012-04-23 11:04:46 +00:00
|
|
|
ret {node: lit, span: mk_sp(lo, p.last_span.hi)};
|
2010-08-18 22:41:13 +00:00
|
|
|
}
|
2010-08-12 17:29:23 +00:00
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_path_without_tps(p: parser) -> @path {
|
2012-04-27 19:35:04 +00:00
|
|
|
parse_path_without_tps_(p, parse_ident, parse_ident)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_path_without_tps_(
|
2012-05-08 14:07:32 +00:00
|
|
|
p: parser, parse_ident: fn(parser) -> ident,
|
|
|
|
parse_last_ident: fn(parser) -> ident) -> @path {
|
2012-04-27 19:35:04 +00:00
|
|
|
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2012-03-15 13:47:03 +00:00
|
|
|
let global = eat(p, token::MOD_SEP);
|
2012-04-27 01:35:16 +00:00
|
|
|
let mut ids = [];
|
2012-04-27 19:22:42 +00:00
|
|
|
loop {
|
|
|
|
let is_not_last =
|
|
|
|
p.look_ahead(2u) != token::LT
|
|
|
|
&& p.look_ahead(1u) == token::MOD_SEP;
|
|
|
|
|
|
|
|
if is_not_last {
|
2012-04-27 19:35:04 +00:00
|
|
|
ids += [parse_ident(p)];
|
2012-04-27 19:22:42 +00:00
|
|
|
expect(p, token::MOD_SEP);
|
|
|
|
} else {
|
2012-04-27 19:35:04 +00:00
|
|
|
ids += [parse_last_ident(p)];
|
2012-04-27 19:22:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-04-24 22:52:52 +00:00
|
|
|
@{span: mk_sp(lo, p.last_span.hi), global: global,
|
|
|
|
idents: ids, rp: none, types: []}
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_value_path(p: parser) -> @path {
|
2012-04-27 19:35:04 +00:00
|
|
|
parse_path_without_tps_(p, parse_ident, parse_value_ident)
|
2012-02-10 14:48:25 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_path_with_tps(p: parser, colons: bool) -> @path {
|
2012-04-24 22:52:52 +00:00
|
|
|
#debug["parse_path_with_tps(colons=%b)", colons];
|
|
|
|
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2012-04-24 22:52:52 +00:00
|
|
|
let path = parse_path_without_tps(p);
|
|
|
|
if colons && !eat(p, token::MOD_SEP) {
|
|
|
|
ret path;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the region parameter, if any, which will
|
|
|
|
// be written "foo/&x"
|
|
|
|
let rp = {
|
|
|
|
// Hack: avoid parsing vstores like /@ and /~. This is painful
|
|
|
|
// because the notation for region bounds and the notation for vstores
|
|
|
|
// is... um... the same. I guess that's my fault. This is still not
|
|
|
|
// ideal as for str/& we end up parsing more than we ought to and have
|
|
|
|
// to sort it out later.
|
|
|
|
if p.token == token::BINOP(token::SLASH)
|
|
|
|
&& p.look_ahead(1u) == token::BINOP(token::AND) {
|
|
|
|
|
|
|
|
expect(p, token::BINOP(token::SLASH));
|
|
|
|
some(parse_region(p))
|
|
|
|
} else {
|
|
|
|
none
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Parse any type parameters which may appear:
|
|
|
|
let tps = {
|
|
|
|
if p.token == token::LT {
|
|
|
|
parse_seq_lt_gt(some(token::COMMA), {|p| parse_ty(p, false)}, p)
|
|
|
|
} else {
|
|
|
|
{node: [], span: path.span}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
ret @{span: mk_sp(lo, tps.span.hi),
|
|
|
|
rp: rp,
|
|
|
|
types: tps.node with *path};
|
2010-10-05 00:25:52 +00:00
|
|
|
}
|
2010-09-28 01:25:02 +00:00
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_mutability(p: parser) -> mutability {
|
2012-04-25 03:16:53 +00:00
|
|
|
if eat_keyword(p, "mut") {
|
2012-05-08 14:07:32 +00:00
|
|
|
m_mutbl
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "mut") {
|
2012-05-08 14:07:32 +00:00
|
|
|
m_mutbl
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "const") {
|
2012-05-08 14:07:32 +00:00
|
|
|
m_const
|
2011-11-16 21:52:08 +00:00
|
|
|
} else {
|
2012-05-08 14:07:32 +00:00
|
|
|
m_imm
|
2010-10-12 23:30:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_field(p: parser, sep: token::token) -> field {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2011-07-27 12:19:39 +00:00
|
|
|
let m = parse_mutability(p);
|
|
|
|
let i = parse_ident(p);
|
2011-07-25 15:37:58 +00:00
|
|
|
expect(p, sep);
|
2011-07-27 12:19:39 +00:00
|
|
|
let e = parse_expr(p);
|
2012-02-15 19:25:39 +00:00
|
|
|
ret spanned(lo, e.span.hi, {mutbl: m, ident: i, expr: e});
|
2010-12-14 23:32:13 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn mk_expr(p: parser, lo: uint, hi: uint, +node: expr_) -> @expr {
|
2012-04-23 11:04:46 +00:00
|
|
|
ret @{id: p.get_id(), node: node, span: mk_sp(lo, hi)};
|
2011-06-21 20:16:40 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn mk_mac_expr(p: parser, lo: uint, hi: uint, m: mac_) -> @expr {
|
2011-07-27 12:19:39 +00:00
|
|
|
ret @{id: p.get_id(),
|
2012-05-08 14:07:32 +00:00
|
|
|
node: expr_mac({node: m, span: mk_sp(lo, hi)}),
|
2012-04-23 11:04:46 +00:00
|
|
|
span: mk_sp(lo, hi)};
|
2011-07-08 23:35:09 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn mk_lit_u32(p: parser, i: u32) -> @expr {
|
2012-01-13 08:56:53 +00:00
|
|
|
let span = p.span;
|
2012-05-08 14:07:32 +00:00
|
|
|
let lv_lit = @{node: lit_uint(i as u64, ty_u32),
|
2011-12-21 22:31:31 +00:00
|
|
|
span: span};
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
ret @{id: p.get_id(), node: expr_lit(lv_lit), span: span};
|
2011-12-21 22:31:31 +00:00
|
|
|
}
|
|
|
|
|
2012-01-04 06:03:07 +00:00
|
|
|
// We don't allow single-entry tuples in the true AST; that indicates a
|
|
|
|
// parenthesized expression. However, we preserve them temporarily while
|
|
|
|
// parsing because `(while{...})+3` parses differently from `while{...}+3`.
|
|
|
|
//
|
2012-05-08 14:07:32 +00:00
|
|
|
// To reflect the fact that the @expr is not a true expr that should be
|
2012-01-19 22:24:03 +00:00
|
|
|
// part of the AST, we wrap such expressions in the pexpr enum. They
|
2012-01-04 06:03:07 +00:00
|
|
|
// can then be converted to true expressions by a call to `to_expr()`.
|
2012-01-19 22:24:03 +00:00
|
|
|
enum pexpr {
|
2012-05-08 14:07:32 +00:00
|
|
|
pexpr(@expr),
|
2012-01-04 06:03:07 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn mk_pexpr(p: parser, lo: uint, hi: uint, node: expr_) -> pexpr {
|
2012-01-04 06:03:07 +00:00
|
|
|
ret pexpr(mk_expr(p, lo, hi, node));
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn to_expr(e: pexpr) -> @expr {
|
2012-01-04 06:03:07 +00:00
|
|
|
alt e.node {
|
2012-05-08 14:07:32 +00:00
|
|
|
expr_tup(es) if vec::len(es) == 1u { es[0u] }
|
2012-01-04 06:03:07 +00:00
|
|
|
_ { *e }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_bottom_expr(p: parser) -> pexpr {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut hi = p.span.hi;
|
2011-06-15 18:19:50 +00:00
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
let mut ex: expr_;
|
2012-01-25 23:38:09 +00:00
|
|
|
|
2012-04-22 23:58:04 +00:00
|
|
|
alt maybe_parse_dollar_mac(p) {
|
2012-01-25 23:38:09 +00:00
|
|
|
some(x) {ret pexpr(mk_mac_expr(p, lo, p.span.hi, x));}
|
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
|
2012-01-13 08:56:53 +00:00
|
|
|
if p.token == token::LPAREN {
|
2011-05-13 19:30:08 +00:00
|
|
|
p.bump();
|
2012-01-13 08:56:53 +00:00
|
|
|
if p.token == token::RPAREN {
|
|
|
|
hi = p.span.hi;
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
let lit = @spanned(lo, hi, lit_nil);
|
|
|
|
ret mk_pexpr(p, lo, hi, expr_lit(lit));
|
2011-05-13 19:30:08 +00:00
|
|
|
}
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut es = [parse_expr(p)];
|
2012-01-13 08:56:53 +00:00
|
|
|
while p.token == token::COMMA { p.bump(); es += [parse_expr(p)]; }
|
|
|
|
hi = p.span.hi;
|
2011-05-13 19:30:08 +00:00
|
|
|
expect(p, token::RPAREN);
|
2012-01-04 06:03:07 +00:00
|
|
|
|
|
|
|
// Note: we retain the expr_tup() even for simple
|
|
|
|
// parenthesized expressions, but only for a "little while".
|
|
|
|
// This is so that wrappers around parse_bottom_expr()
|
|
|
|
// can tell whether the expression was parenthesized or not,
|
|
|
|
// which affects expr_is_complete().
|
2012-05-08 14:07:32 +00:00
|
|
|
ret mk_pexpr(p, lo, hi, expr_tup(es));
|
2012-01-13 08:56:53 +00:00
|
|
|
} else if p.token == token::LBRACE {
|
2011-07-25 15:37:58 +00:00
|
|
|
p.bump();
|
2012-04-25 03:16:53 +00:00
|
|
|
if is_keyword(p, "mut") ||
|
2012-04-18 04:14:40 +00:00
|
|
|
is_plain_ident(p.token) && p.look_ahead(1u) == token::COLON {
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut fields = [parse_field(p, token::COLON)];
|
|
|
|
let mut base = none;
|
2012-01-13 08:56:53 +00:00
|
|
|
while p.token != token::RBRACE {
|
2012-04-25 03:16:53 +00:00
|
|
|
if eat_keyword(p, "with") {
|
|
|
|
base = some(parse_expr(p)); break;
|
|
|
|
}
|
2011-07-25 15:37:58 +00:00
|
|
|
expect(p, token::COMMA);
|
2012-01-13 08:56:53 +00:00
|
|
|
if p.token == token::RBRACE {
|
2011-11-21 15:36:11 +00:00
|
|
|
// record ends by an optional trailing comma
|
|
|
|
break;
|
|
|
|
}
|
2011-08-19 22:16:48 +00:00
|
|
|
fields += [parse_field(p, token::COLON)];
|
2011-07-25 15:37:58 +00:00
|
|
|
}
|
2012-01-13 08:56:53 +00:00
|
|
|
hi = p.span.hi;
|
2011-07-25 15:37:58 +00:00
|
|
|
expect(p, token::RBRACE);
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_rec(fields, base);
|
2012-04-18 04:14:40 +00:00
|
|
|
} else if token::is_bar(p.token) {
|
2012-01-04 06:03:07 +00:00
|
|
|
ret pexpr(parse_fn_block_expr(p));
|
2011-07-25 15:37:58 +00:00
|
|
|
} else {
|
2012-05-08 14:07:32 +00:00
|
|
|
let blk = parse_block_tail(p, lo, default_blk);
|
|
|
|
ret mk_pexpr(p, blk.span.lo, blk.span.hi, expr_block(blk));
|
2011-07-25 15:37:58 +00:00
|
|
|
}
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "new") {
|
2012-03-14 19:16:46 +00:00
|
|
|
expect(p, token::LPAREN);
|
|
|
|
let r = parse_expr(p);
|
|
|
|
expect(p, token::RPAREN);
|
|
|
|
let v = parse_expr(p);
|
|
|
|
ret mk_pexpr(p, lo, p.span.hi,
|
2012-05-08 14:07:32 +00:00
|
|
|
expr_new(r, p.get_id(), v));
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "if") {
|
2012-01-04 06:03:07 +00:00
|
|
|
ret pexpr(parse_if_expr(p));
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "for") {
|
2012-01-04 06:03:07 +00:00
|
|
|
ret pexpr(parse_for_expr(p));
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "while") {
|
2012-01-04 06:03:07 +00:00
|
|
|
ret pexpr(parse_while_expr(p));
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "loop") {
|
2012-03-10 00:11:56 +00:00
|
|
|
ret pexpr(parse_loop_expr(p));
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "alt") {
|
2012-01-04 06:03:07 +00:00
|
|
|
ret pexpr(parse_alt_expr(p));
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "fn") {
|
2011-12-14 05:43:36 +00:00
|
|
|
let proto = parse_fn_ty_proto(p);
|
2012-01-11 17:58:05 +00:00
|
|
|
alt proto {
|
2012-05-08 14:07:32 +00:00
|
|
|
proto_bare { p.fatal("fn expr are deprecated, use fn@"); }
|
|
|
|
proto_any { p.fatal("fn* cannot be used in an expression"); }
|
2012-01-11 17:58:05 +00:00
|
|
|
_ { /* fallthrough */ }
|
|
|
|
}
|
2012-01-04 06:03:07 +00:00
|
|
|
ret pexpr(parse_fn_expr(p, proto));
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "unchecked") {
|
2012-05-08 14:07:32 +00:00
|
|
|
ret pexpr(parse_block_expr(p, lo, unchecked_blk));
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "unsafe") {
|
2012-05-08 14:07:32 +00:00
|
|
|
ret pexpr(parse_block_expr(p, lo, unsafe_blk));
|
2012-01-13 08:56:53 +00:00
|
|
|
} else if p.token == token::LBRACKET {
|
2011-05-16 22:25:10 +00:00
|
|
|
p.bump();
|
2012-02-15 19:25:39 +00:00
|
|
|
let mutbl = parse_mutability(p);
|
2011-07-27 12:19:39 +00:00
|
|
|
let es =
|
2011-11-21 15:36:11 +00:00
|
|
|
parse_seq_to_end(token::RBRACKET, seq_sep(token::COMMA),
|
|
|
|
parse_expr, p);
|
2012-04-10 00:32:49 +00:00
|
|
|
hi = p.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_vec(es, mutbl);
|
2012-04-22 22:15:18 +00:00
|
|
|
} else if p.token == token::POUND && p.look_ahead(1u) == token::LT {
|
|
|
|
p.bump();
|
2011-06-30 01:07:04 +00:00
|
|
|
p.bump();
|
2011-08-15 19:06:10 +00:00
|
|
|
let ty = parse_ty(p, false);
|
2011-06-30 01:07:04 +00:00
|
|
|
expect(p, token::GT);
|
2011-07-27 12:19:39 +00:00
|
|
|
|
2011-07-08 23:35:09 +00:00
|
|
|
/* hack: early return to take advantage of specialized function */
|
2012-01-13 08:56:53 +00:00
|
|
|
ret pexpr(mk_mac_expr(p, lo, p.span.hi,
|
2012-05-08 14:07:32 +00:00
|
|
|
mac_embed_type(ty)));
|
2012-04-22 22:15:18 +00:00
|
|
|
} else if p.token == token::POUND && p.look_ahead(1u) == token::LBRACE {
|
|
|
|
p.bump();
|
2011-06-30 01:07:04 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
let blk = mac_embed_block(
|
|
|
|
parse_block_tail(p, lo, default_blk));
|
2012-01-13 08:56:53 +00:00
|
|
|
ret pexpr(mk_mac_expr(p, lo, p.span.hi, blk));
|
|
|
|
} else if p.token == token::ELLIPSIS {
|
2011-07-21 23:47:47 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
ret pexpr(mk_mac_expr(p, lo, p.span.hi, mac_ellipsis));
|
2012-04-22 22:15:18 +00:00
|
|
|
} else if p.token == token::POUND {
|
|
|
|
let ex_ext = parse_syntax_ext(p);
|
|
|
|
hi = ex_ext.span.hi;
|
|
|
|
ex = ex_ext.node;
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "bind") {
|
2011-07-27 12:19:39 +00:00
|
|
|
let e = parse_expr_res(p, RESTRICT_NO_CALL_EXPRS);
|
|
|
|
let es =
|
2011-11-21 15:36:11 +00:00
|
|
|
parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
|
2012-02-07 14:37:08 +00:00
|
|
|
parse_expr_or_hole, p);
|
2011-05-13 19:30:08 +00:00
|
|
|
hi = es.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_bind(e, es.node);
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "fail") {
|
2012-01-13 08:56:53 +00:00
|
|
|
if can_begin_expr(p.token) {
|
2011-07-27 12:19:39 +00:00
|
|
|
let e = parse_expr(p);
|
2011-07-03 17:39:07 +00:00
|
|
|
hi = e.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_fail(some(e));
|
|
|
|
} else { ex = expr_fail(none); }
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "log") {
|
2011-12-22 02:05:08 +00:00
|
|
|
expect(p, token::LPAREN);
|
2011-12-21 22:31:31 +00:00
|
|
|
let lvl = parse_expr(p);
|
2011-12-22 02:05:08 +00:00
|
|
|
expect(p, token::COMMA);
|
2011-12-21 23:43:38 +00:00
|
|
|
let e = parse_expr(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_log(2, lvl, e);
|
2012-01-13 08:56:53 +00:00
|
|
|
hi = p.span.hi;
|
2011-12-22 02:05:08 +00:00
|
|
|
expect(p, token::RPAREN);
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "assert") {
|
2011-07-27 12:19:39 +00:00
|
|
|
let e = parse_expr(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_assert(e);
|
2011-07-08 23:35:09 +00:00
|
|
|
hi = e.span.hi;
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "check") {
|
2011-07-13 22:44:09 +00:00
|
|
|
/* Should be a predicate (pure boolean function) applied to
|
2011-05-13 19:30:08 +00:00
|
|
|
arguments that are all either slot variables or literals.
|
|
|
|
but the typechecker enforces that. */
|
2011-07-27 12:19:39 +00:00
|
|
|
let e = parse_expr(p);
|
2011-07-08 23:35:09 +00:00
|
|
|
hi = e.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_check(checked_expr, e);
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "claim") {
|
2011-06-28 23:29:37 +00:00
|
|
|
/* Same rules as check, except that if check-claims
|
|
|
|
is enabled (a command-line flag), then the parser turns
|
|
|
|
claims into check */
|
2011-07-13 22:44:09 +00:00
|
|
|
|
2011-07-27 12:19:39 +00:00
|
|
|
let e = parse_expr(p);
|
2011-07-08 23:35:09 +00:00
|
|
|
hi = e.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_check(claimed_expr, e);
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "ret") {
|
2012-01-13 08:56:53 +00:00
|
|
|
if can_begin_expr(p.token) {
|
2011-07-27 12:19:39 +00:00
|
|
|
let e = parse_expr(p);
|
2011-07-13 22:00:59 +00:00
|
|
|
hi = e.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_ret(some(e));
|
|
|
|
} else { ex = expr_ret(none); }
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "break") {
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_break;
|
2012-01-13 08:56:53 +00:00
|
|
|
hi = p.span.hi;
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "cont") {
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_cont;
|
2012-01-13 08:56:53 +00:00
|
|
|
hi = p.span.hi;
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "copy") {
|
2011-08-15 22:35:40 +00:00
|
|
|
let e = parse_expr(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_copy(e);
|
2011-08-15 22:35:40 +00:00
|
|
|
hi = e.span.hi;
|
2012-01-13 08:56:53 +00:00
|
|
|
} else if p.token == token::MOD_SEP ||
|
2012-04-25 03:16:53 +00:00
|
|
|
is_ident(p.token) && !is_keyword(p, "true") &&
|
|
|
|
!is_keyword(p, "false") {
|
2012-04-24 22:52:52 +00:00
|
|
|
let pth = parse_path_with_tps(p, true);
|
2011-05-13 19:30:08 +00:00
|
|
|
hi = pth.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_path(pth);
|
2011-05-13 19:30:08 +00:00
|
|
|
} else {
|
2011-07-27 12:19:39 +00:00
|
|
|
let lit = parse_lit(p);
|
2011-05-13 19:30:08 +00:00
|
|
|
hi = lit.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_lit(@lit);
|
2010-09-28 01:25:02 +00:00
|
|
|
}
|
2012-04-10 00:32:49 +00:00
|
|
|
|
|
|
|
// Vstore is legal following expr_lit(lit_str(...)) and expr_vec(...)
|
|
|
|
// only.
|
|
|
|
alt ex {
|
2012-05-08 14:07:32 +00:00
|
|
|
expr_lit(@{node: lit_str(_), span: _}) |
|
|
|
|
expr_vec(_, _) {
|
2012-04-11 01:32:34 +00:00
|
|
|
alt maybe_parse_vstore(p) {
|
2012-04-10 00:32:49 +00:00
|
|
|
none { }
|
|
|
|
some(v) {
|
|
|
|
hi = p.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_vstore(mk_expr(p, lo, hi, ex), v);
|
2012-04-10 00:32:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ { }
|
|
|
|
}
|
|
|
|
|
2012-01-04 06:03:07 +00:00
|
|
|
ret mk_pexpr(p, lo, hi, ex);
|
2010-09-28 01:25:02 +00:00
|
|
|
}
|
|
|
|
|
2011-10-06 23:42:27 +00:00
|
|
|
fn parse_block_expr(p: parser,
|
|
|
|
lo: uint,
|
2012-05-08 14:07:32 +00:00
|
|
|
blk_mode: blk_check_mode) -> @expr {
|
2011-10-06 23:42:27 +00:00
|
|
|
expect(p, token::LBRACE);
|
|
|
|
let blk = parse_block_tail(p, lo, blk_mode);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret mk_expr(p, blk.span.lo, blk.span.hi, expr_block(blk));
|
2011-10-06 23:42:27 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_syntax_ext(p: parser) -> @expr {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2011-06-15 20:27:39 +00:00
|
|
|
expect(p, token::POUND);
|
2011-06-16 19:19:27 +00:00
|
|
|
ret parse_syntax_ext_naked(p, lo);
|
2011-06-15 20:27:39 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_syntax_ext_naked(p: parser, lo: uint) -> @expr {
|
2012-01-13 08:56:53 +00:00
|
|
|
alt p.token {
|
2011-12-20 15:33:55 +00:00
|
|
|
token::IDENT(_, _) {}
|
|
|
|
_ { p.fatal("expected a syntax expander name"); }
|
2011-07-02 04:59:33 +00:00
|
|
|
}
|
2012-04-24 22:52:52 +00:00
|
|
|
let pth = parse_path_without_tps(p);
|
2011-07-28 00:36:37 +00:00
|
|
|
//temporary for a backwards-compatible cycle:
|
2011-11-21 15:36:11 +00:00
|
|
|
let sep = seq_sep(token::COMMA);
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut e = none;
|
2012-02-01 07:20:31 +00:00
|
|
|
if (p.token == token::LPAREN || p.token == token::LBRACKET) {
|
|
|
|
let es =
|
|
|
|
if p.token == token::LPAREN {
|
|
|
|
parse_seq(token::LPAREN, token::RPAREN,
|
|
|
|
sep, parse_expr, p)
|
|
|
|
} else {
|
|
|
|
parse_seq(token::LBRACKET, token::RBRACKET,
|
|
|
|
sep, parse_expr, p)
|
|
|
|
};
|
|
|
|
let hi = es.span.hi;
|
|
|
|
e = some(mk_expr(p, es.span.lo, hi,
|
2012-05-08 14:07:32 +00:00
|
|
|
expr_vec(es.node, m_imm)));
|
2012-02-01 07:20:31 +00:00
|
|
|
}
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut b = none;
|
2012-02-01 06:50:12 +00:00
|
|
|
if p.token == token::LBRACE {
|
|
|
|
p.bump();
|
|
|
|
let lo = p.span.lo;
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut depth = 1u;
|
2012-02-01 06:50:12 +00:00
|
|
|
while (depth > 0u) {
|
|
|
|
alt (p.token) {
|
|
|
|
token::LBRACE {depth += 1u;}
|
|
|
|
token::RBRACE {depth -= 1u;}
|
|
|
|
token::EOF {p.fatal("unexpected EOF in macro body");}
|
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
p.bump();
|
|
|
|
}
|
2012-02-01 09:58:28 +00:00
|
|
|
let hi = p.last_span.lo;
|
2012-02-01 06:50:12 +00:00
|
|
|
b = some({span: mk_sp(lo,hi)});
|
|
|
|
}
|
2012-05-08 14:07:32 +00:00
|
|
|
ret mk_mac_expr(p, lo, p.span.hi, mac_invoc(pth, e, b));
|
2011-02-24 04:48:01 +00:00
|
|
|
}
|
|
|
|
|
2012-01-04 06:03:07 +00:00
|
|
|
fn parse_dot_or_call_expr(p: parser) -> pexpr {
|
2011-09-15 07:39:24 +00:00
|
|
|
let b = parse_bottom_expr(p);
|
2011-12-21 04:12:52 +00:00
|
|
|
parse_dot_or_call_expr_with(p, b)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn permits_call(p: parser) -> bool {
|
2012-01-13 08:56:53 +00:00
|
|
|
ret p.restriction != RESTRICT_NO_CALL_EXPRS;
|
2011-06-14 13:20:04 +00:00
|
|
|
}
|
|
|
|
|
2012-01-04 06:03:07 +00:00
|
|
|
fn parse_dot_or_call_expr_with(p: parser, e0: pexpr) -> pexpr {
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut e = e0;
|
2011-07-27 12:19:39 +00:00
|
|
|
let lo = e.span.lo;
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut hi = e.span.hi;
|
2012-03-11 04:34:17 +00:00
|
|
|
loop {
|
2012-01-31 12:31:02 +00:00
|
|
|
// expr.f
|
|
|
|
if eat(p, token::DOT) {
|
|
|
|
alt p.token {
|
|
|
|
token::IDENT(i, _) {
|
|
|
|
hi = p.span.hi;
|
|
|
|
p.bump();
|
|
|
|
let tys = if eat(p, token::MOD_SEP) {
|
|
|
|
expect(p, token::LT);
|
|
|
|
parse_seq_to_gt(some(token::COMMA),
|
|
|
|
{|p| parse_ty(p, false)}, p)
|
|
|
|
} else { [] };
|
|
|
|
e = mk_pexpr(p, lo, hi,
|
2012-05-08 14:07:32 +00:00
|
|
|
expr_field(to_expr(e),
|
2012-01-31 12:31:02 +00:00
|
|
|
p.get_str(i),
|
|
|
|
tys));
|
|
|
|
}
|
2012-03-20 14:05:14 +00:00
|
|
|
_ { unexpected(p); }
|
2012-01-31 12:31:02 +00:00
|
|
|
}
|
|
|
|
cont;
|
|
|
|
}
|
|
|
|
if expr_is_complete(p, e) { break; }
|
2012-01-13 08:56:53 +00:00
|
|
|
alt p.token {
|
2011-12-21 04:12:52 +00:00
|
|
|
// expr(...)
|
2012-01-19 06:37:22 +00:00
|
|
|
token::LPAREN if permits_call(p) {
|
2012-02-07 14:37:08 +00:00
|
|
|
let es_opt =
|
|
|
|
parse_seq(token::LPAREN, token::RPAREN,
|
|
|
|
seq_sep(token::COMMA), parse_expr_or_hole, p);
|
|
|
|
hi = es_opt.span.hi;
|
|
|
|
|
|
|
|
let nd =
|
|
|
|
if vec::any(es_opt.node, {|e| option::is_none(e) }) {
|
2012-05-08 14:07:32 +00:00
|
|
|
expr_bind(to_expr(e), es_opt.node)
|
2012-02-07 14:37:08 +00:00
|
|
|
} else {
|
|
|
|
let es = vec::map(es_opt.node) {|e| option::get(e) };
|
2012-05-08 14:07:32 +00:00
|
|
|
expr_call(to_expr(e), es, false)
|
2012-02-07 14:37:08 +00:00
|
|
|
};
|
2012-01-04 06:03:07 +00:00
|
|
|
e = mk_pexpr(p, lo, hi, nd);
|
2011-12-21 04:12:52 +00:00
|
|
|
}
|
|
|
|
|
2012-01-04 06:03:07 +00:00
|
|
|
// expr {|| ... }
|
2012-04-18 04:14:40 +00:00
|
|
|
token::LBRACE if (token::is_bar(p.look_ahead(1u))
|
|
|
|
&& permits_call(p)) {
|
2011-12-21 04:12:52 +00:00
|
|
|
p.bump();
|
|
|
|
let blk = parse_fn_block_expr(p);
|
|
|
|
alt e.node {
|
2012-05-08 14:07:32 +00:00
|
|
|
expr_call(f, args, false) {
|
|
|
|
e = pexpr(@{node: expr_call(f, args + [blk], true)
|
2012-01-04 06:03:07 +00:00
|
|
|
with *to_expr(e)});
|
2011-12-21 04:12:52 +00:00
|
|
|
}
|
|
|
|
_ {
|
2012-01-13 08:56:53 +00:00
|
|
|
e = mk_pexpr(p, lo, p.last_span.hi,
|
2012-05-08 14:07:32 +00:00
|
|
|
expr_call(to_expr(e), [blk], true));
|
2011-12-21 04:12:52 +00:00
|
|
|
}
|
2010-12-15 00:59:13 +00:00
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2011-12-21 04:12:52 +00:00
|
|
|
|
|
|
|
// expr[...]
|
2012-01-19 06:37:22 +00:00
|
|
|
token::LBRACKET {
|
2011-08-19 19:01:01 +00:00
|
|
|
p.bump();
|
|
|
|
let ix = parse_expr(p);
|
|
|
|
hi = ix.span.hi;
|
|
|
|
expect(p, token::RBRACKET);
|
2012-01-26 14:23:04 +00:00
|
|
|
p.get_id(); // see ast_util::op_expr_callee_id
|
2012-05-08 14:07:32 +00:00
|
|
|
e = mk_pexpr(p, lo, hi, expr_index(to_expr(e), ix));
|
2011-08-19 19:01:01 +00:00
|
|
|
}
|
2011-12-21 04:12:52 +00:00
|
|
|
|
2011-07-27 12:19:39 +00:00
|
|
|
_ { ret e; }
|
2010-09-28 17:30:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret e;
|
|
|
|
}
|
2010-09-28 01:25:02 +00:00
|
|
|
|
2012-01-04 06:03:07 +00:00
|
|
|
fn parse_prefix_expr(p: parser) -> pexpr {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut hi = p.span.hi;
|
2011-06-15 18:19:50 +00:00
|
|
|
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut ex;
|
2012-01-13 08:56:53 +00:00
|
|
|
alt p.token {
|
2012-01-19 06:37:22 +00:00
|
|
|
token::NOT {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
2012-01-04 06:03:07 +00:00
|
|
|
let e = to_expr(parse_prefix_expr(p));
|
2011-07-27 12:19:39 +00:00
|
|
|
hi = e.span.hi;
|
2012-01-26 11:26:14 +00:00
|
|
|
p.get_id(); // see ast_util::op_expr_callee_id
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_unary(not, e);
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
|
|
|
token::BINOP(b) {
|
|
|
|
alt b {
|
2012-01-19 06:37:22 +00:00
|
|
|
token::MINUS {
|
2010-09-28 21:01:21 +00:00
|
|
|
p.bump();
|
2012-01-04 06:03:07 +00:00
|
|
|
let e = to_expr(parse_prefix_expr(p));
|
2011-04-08 16:44:20 +00:00
|
|
|
hi = e.span.hi;
|
2012-01-26 11:26:14 +00:00
|
|
|
p.get_id(); // see ast_util::op_expr_callee_id
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_unary(neg, e);
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-01-19 06:37:22 +00:00
|
|
|
token::STAR {
|
2010-09-28 17:30:34 +00:00
|
|
|
p.bump();
|
2012-01-04 06:03:07 +00:00
|
|
|
let e = to_expr(parse_prefix_expr(p));
|
2011-04-08 16:44:20 +00:00
|
|
|
hi = e.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_unary(deref, e);
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-03-08 20:12:04 +00:00
|
|
|
token::AND {
|
|
|
|
p.bump();
|
2012-03-09 00:34:36 +00:00
|
|
|
let m = parse_mutability(p);
|
2012-03-08 20:12:04 +00:00
|
|
|
let e = to_expr(parse_prefix_expr(p));
|
|
|
|
hi = e.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_addr_of(m, e);
|
2012-03-08 20:12:04 +00:00
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
_ { ret parse_dot_or_call_expr(p); }
|
2010-09-28 17:30:34 +00:00
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-01-19 06:37:22 +00:00
|
|
|
token::AT {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
|
|
|
let m = parse_mutability(p);
|
2012-01-04 06:03:07 +00:00
|
|
|
let e = to_expr(parse_prefix_expr(p));
|
2011-07-27 12:19:39 +00:00
|
|
|
hi = e.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_unary(box(m), e);
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-01-19 06:37:22 +00:00
|
|
|
token::TILDE {
|
2011-09-21 01:06:47 +00:00
|
|
|
p.bump();
|
|
|
|
let m = parse_mutability(p);
|
2012-01-04 06:03:07 +00:00
|
|
|
let e = to_expr(parse_prefix_expr(p));
|
2011-09-21 01:06:47 +00:00
|
|
|
hi = e.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ex = expr_unary(uniq(m), e);
|
2011-09-21 01:06:47 +00:00
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
_ { ret parse_dot_or_call_expr(p); }
|
2010-09-28 17:30:34 +00:00
|
|
|
}
|
2012-01-04 06:03:07 +00:00
|
|
|
ret mk_pexpr(p, lo, hi, ex);
|
2010-09-28 17:30:34 +00:00
|
|
|
}
|
|
|
|
|
2011-05-12 15:24:54 +00:00
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_binops(p: parser) -> @expr {
|
2012-04-26 23:13:59 +00:00
|
|
|
ret parse_more_binops(p, parse_prefix_expr(p), 0u);
|
2010-09-28 17:30:34 +00:00
|
|
|
}
|
|
|
|
|
2012-04-26 23:13:59 +00:00
|
|
|
fn parse_more_binops(p: parser, plhs: pexpr, min_prec: uint) ->
|
2012-05-08 14:07:32 +00:00
|
|
|
@expr {
|
2012-01-04 06:03:07 +00:00
|
|
|
let lhs = to_expr(plhs);
|
|
|
|
if expr_is_complete(p, plhs) { ret lhs; }
|
2012-01-13 08:56:53 +00:00
|
|
|
let peeked = p.token;
|
2011-12-02 12:42:51 +00:00
|
|
|
if peeked == token::BINOP(token::OR) &&
|
2012-01-13 08:56:53 +00:00
|
|
|
p.restriction == RESTRICT_NO_BAR_OP { ret lhs; }
|
2012-04-26 23:13:59 +00:00
|
|
|
let cur_opt = token_to_binop(peeked);
|
|
|
|
alt cur_opt {
|
|
|
|
some(cur_op) {
|
|
|
|
let cur_prec = operator_prec(cur_op);
|
|
|
|
if cur_prec > min_prec {
|
|
|
|
p.bump();
|
|
|
|
let expr = parse_prefix_expr(p);
|
|
|
|
let rhs = parse_more_binops(p, expr, cur_prec);
|
|
|
|
p.get_id(); // see ast_util::op_expr_callee_id
|
|
|
|
let bin = mk_pexpr(p, lhs.span.lo, rhs.span.hi,
|
2012-05-08 14:07:32 +00:00
|
|
|
expr_binary(cur_op, lhs, rhs));
|
2012-04-26 23:13:59 +00:00
|
|
|
ret parse_more_binops(p, bin, min_prec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ {}
|
2010-09-28 17:30:34 +00:00
|
|
|
}
|
2012-04-25 03:16:53 +00:00
|
|
|
if as_prec > min_prec && eat_keyword(p, "as") {
|
2011-08-15 19:06:10 +00:00
|
|
|
let rhs = parse_ty(p, true);
|
2011-07-27 12:19:39 +00:00
|
|
|
let _as =
|
2012-05-08 14:07:32 +00:00
|
|
|
mk_pexpr(p, lhs.span.lo, rhs.span.hi, expr_cast(lhs, rhs));
|
2011-06-21 20:16:40 +00:00
|
|
|
ret parse_more_binops(p, _as, min_prec);
|
2011-05-13 19:30:08 +00:00
|
|
|
}
|
2011-03-07 14:29:06 +00:00
|
|
|
ret lhs;
|
2010-09-28 01:25:02 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_assign_expr(p: parser) -> @expr {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2012-01-30 16:40:54 +00:00
|
|
|
let lhs = parse_binops(p);
|
2012-01-13 08:56:53 +00:00
|
|
|
alt p.token {
|
2012-01-19 06:37:22 +00:00
|
|
|
token::EQ {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
|
|
|
let rhs = parse_expr(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret mk_expr(p, lo, rhs.span.hi, expr_assign(lhs, rhs));
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
|
|
|
token::BINOPEQ(op) {
|
|
|
|
p.bump();
|
|
|
|
let rhs = parse_expr(p);
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut aop;
|
2011-07-27 12:19:39 +00:00
|
|
|
alt op {
|
2012-05-08 14:07:32 +00:00
|
|
|
token::PLUS { aop = add; }
|
|
|
|
token::MINUS { aop = subtract; }
|
|
|
|
token::STAR { aop = mul; }
|
|
|
|
token::SLASH { aop = div; }
|
|
|
|
token::PERCENT { aop = rem; }
|
|
|
|
token::CARET { aop = bitxor; }
|
|
|
|
token::AND { aop = bitand; }
|
|
|
|
token::OR { aop = bitor; }
|
|
|
|
token::LSL { aop = lsl; }
|
|
|
|
token::LSR { aop = lsr; }
|
|
|
|
token::ASR { aop = asr; }
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-01-26 11:26:14 +00:00
|
|
|
p.get_id(); // see ast_util::op_expr_callee_id
|
2012-05-08 14:07:32 +00:00
|
|
|
ret mk_expr(p, lo, rhs.span.hi, expr_assign_op(aop, lhs, rhs));
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-01-19 06:37:22 +00:00
|
|
|
token::LARROW {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
|
|
|
let rhs = parse_expr(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret mk_expr(p, lo, rhs.span.hi, expr_move(lhs, rhs));
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-01-19 06:37:22 +00:00
|
|
|
token::DARROW {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
|
|
|
let rhs = parse_expr(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret mk_expr(p, lo, rhs.span.hi, expr_swap(lhs, rhs));
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
|
|
|
_ {/* fall through */ }
|
2010-10-19 23:33:11 +00:00
|
|
|
}
|
|
|
|
ret lhs;
|
|
|
|
}
|
|
|
|
|
2011-09-12 09:27:30 +00:00
|
|
|
fn parse_if_expr_1(p: parser) ->
|
2012-05-08 14:07:32 +00:00
|
|
|
{cond: @expr,
|
|
|
|
then: blk,
|
|
|
|
els: option<@expr>,
|
2011-07-27 12:19:39 +00:00
|
|
|
lo: uint,
|
|
|
|
hi: uint} {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.last_span.lo;
|
2011-07-27 12:19:39 +00:00
|
|
|
let cond = parse_expr(p);
|
|
|
|
let thn = parse_block(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
let mut els: option<@expr> = none;
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut hi = thn.span.hi;
|
2012-04-25 03:16:53 +00:00
|
|
|
if eat_keyword(p, "else") {
|
2011-07-27 12:19:39 +00:00
|
|
|
let elexpr = parse_else_expr(p);
|
2011-05-13 19:30:08 +00:00
|
|
|
els = some(elexpr);
|
|
|
|
hi = elexpr.span.hi;
|
2010-10-04 22:55:12 +00:00
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
ret {cond: cond, then: thn, els: els, lo: lo, hi: hi};
|
2011-06-16 18:56:34 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_if_expr(p: parser) -> @expr {
|
2012-04-25 03:16:53 +00:00
|
|
|
if eat_keyword(p, "check") {
|
2011-07-27 12:19:39 +00:00
|
|
|
let q = parse_if_expr_1(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret mk_expr(p, q.lo, q.hi, expr_if_check(q.cond, q.then, q.els));
|
2011-07-27 12:19:39 +00:00
|
|
|
} else {
|
|
|
|
let q = parse_if_expr_1(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret mk_expr(p, q.lo, q.hi, expr_if(q.cond, q.then, q.els));
|
2011-06-16 18:56:34 +00:00
|
|
|
}
|
2010-10-04 22:55:12 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_fn_expr(p: parser, proto: proto) -> @expr {
|
2012-05-04 19:33:04 +00:00
|
|
|
let lo = p.last_span.lo;
|
2011-12-08 19:47:01 +00:00
|
|
|
|
2012-05-04 19:33:04 +00:00
|
|
|
let cc_old = parse_old_skool_capture_clause(p);
|
2011-12-08 19:47:01 +00:00
|
|
|
|
2012-05-04 19:33:04 +00:00
|
|
|
// if we want to allow fn expression argument types to be inferred in the
|
|
|
|
// future, just have to change parse_arg to parse_fn_block_arg.
|
|
|
|
let (decl, capture_clause) =
|
2012-05-08 14:07:32 +00:00
|
|
|
parse_fn_decl(p, impure_fn, parse_arg_or_capture_item);
|
2011-12-08 19:47:01 +00:00
|
|
|
|
2011-07-27 12:19:39 +00:00
|
|
|
let body = parse_block(p);
|
2011-12-22 16:49:54 +00:00
|
|
|
ret mk_expr(p, lo, body.span.hi,
|
2012-05-08 14:07:32 +00:00
|
|
|
expr_fn(proto, decl, body,
|
2012-05-07 18:31:57 +00:00
|
|
|
@(*capture_clause + cc_old)));
|
2011-12-14 00:52:33 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_fn_block_expr(p: parser) -> @expr {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.last_span.lo;
|
2012-05-04 19:33:04 +00:00
|
|
|
let (decl, captures) = parse_fn_block_decl(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
let body = parse_block_tail(p, lo, default_blk);
|
2012-05-04 19:33:04 +00:00
|
|
|
ret mk_expr(p, lo, body.span.hi,
|
2012-05-08 14:07:32 +00:00
|
|
|
expr_fn_block(decl, body, captures));
|
2011-08-12 19:58:37 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_else_expr(p: parser) -> @expr {
|
2012-04-25 03:16:53 +00:00
|
|
|
if eat_keyword(p, "if") {
|
2011-05-13 19:30:08 +00:00
|
|
|
ret parse_if_expr(p);
|
|
|
|
} else {
|
2011-07-27 12:19:39 +00:00
|
|
|
let blk = parse_block(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret mk_expr(p, blk.span.lo, blk.span.hi, expr_block(blk));
|
2011-01-30 19:15:22 +00:00
|
|
|
}
|
2010-10-04 22:55:12 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_for_expr(p: parser) -> @expr {
|
2012-03-26 14:09:27 +00:00
|
|
|
let lo = p.last_span;
|
2012-04-06 18:36:43 +00:00
|
|
|
let call = parse_expr_res(p, RESTRICT_STMT_EXPR);
|
|
|
|
alt call.node {
|
2012-05-08 14:07:32 +00:00
|
|
|
expr_call(f, args, true) {
|
2012-04-06 18:36:43 +00:00
|
|
|
let b_arg = vec::last(args);
|
|
|
|
let last = mk_expr(p, b_arg.span.lo, b_arg.span.hi,
|
2012-05-08 14:07:32 +00:00
|
|
|
expr_loop_body(b_arg));
|
|
|
|
@{node: expr_call(f, vec::init(args) + [last], true)
|
2012-04-06 18:36:43 +00:00
|
|
|
with *call}
|
|
|
|
}
|
|
|
|
_ {
|
|
|
|
p.span_fatal(lo, "`for` must be followed by a block call");
|
|
|
|
}
|
2012-03-26 14:09:27 +00:00
|
|
|
}
|
2011-01-20 21:11:47 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_while_expr(p: parser) -> @expr {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.last_span.lo;
|
2011-07-27 12:19:39 +00:00
|
|
|
let cond = parse_expr(p);
|
2011-09-15 07:39:24 +00:00
|
|
|
let body = parse_block_no_value(p);
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut hi = body.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ret mk_expr(p, lo, hi, expr_while(cond, body));
|
2010-11-03 18:05:15 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_loop_expr(p: parser) -> @expr {
|
2012-03-10 00:11:56 +00:00
|
|
|
let lo = p.last_span.lo;
|
|
|
|
let body = parse_block_no_value(p);
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut hi = body.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
ret mk_expr(p, lo, hi, expr_loop(body));
|
2012-03-10 00:11:56 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_alt_expr(p: parser) -> @expr {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.last_span.lo;
|
2012-05-08 14:07:32 +00:00
|
|
|
let mode = if eat_keyword(p, "check") { alt_check }
|
|
|
|
else { alt_exhaustive };
|
2011-07-27 12:19:39 +00:00
|
|
|
let discriminant = parse_expr(p);
|
2011-05-12 15:24:54 +00:00
|
|
|
expect(p, token::LBRACE);
|
2012-05-08 14:07:32 +00:00
|
|
|
let mut arms: [arm] = [];
|
2012-01-13 08:56:53 +00:00
|
|
|
while p.token != token::RBRACE {
|
2011-07-27 12:19:39 +00:00
|
|
|
let pats = parse_pats(p);
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut guard = none;
|
2012-04-25 03:16:53 +00:00
|
|
|
if eat_keyword(p, "if") { guard = some(parse_expr(p)); }
|
2011-07-27 12:19:39 +00:00
|
|
|
let blk = parse_block(p);
|
2011-08-22 12:38:48 +00:00
|
|
|
arms += [{pats: pats, guard: guard, body: blk}];
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut hi = p.span.hi;
|
2010-11-25 00:29:44 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
ret mk_expr(p, lo, hi, expr_alt(discriminant, arms, mode));
|
2010-11-24 22:42:01 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_expr(p: parser) -> @expr {
|
2011-01-24 23:26:10 +00:00
|
|
|
ret parse_expr_res(p, UNRESTRICTED);
|
2011-01-01 01:28:43 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_expr_or_hole(p: parser) -> option<@expr> {
|
2012-02-07 14:37:08 +00:00
|
|
|
alt p.token {
|
|
|
|
token::UNDERSCORE { p.bump(); ret none; }
|
|
|
|
_ { ret some(parse_expr(p)); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_expr_res(p: parser, r: restriction) -> @expr {
|
2012-01-13 08:56:53 +00:00
|
|
|
let old = p.restriction;
|
|
|
|
p.restriction = r;
|
2011-07-27 12:19:39 +00:00
|
|
|
let e = parse_assign_expr(p);
|
2012-01-13 08:56:53 +00:00
|
|
|
p.restriction = old;
|
2011-01-01 01:28:43 +00:00
|
|
|
ret e;
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_initializer(p: parser) -> option<initializer> {
|
2012-01-13 08:56:53 +00:00
|
|
|
alt p.token {
|
2012-01-19 06:37:22 +00:00
|
|
|
token::EQ {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
ret some({op: init_assign, expr: parse_expr(p)});
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-01-19 06:37:22 +00:00
|
|
|
token::LARROW {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
ret some({op: init_move, expr: parse_expr(p)});
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
|
|
|
// Now that the the channel is the first argument to receive,
|
|
|
|
// combining it with an initializer doesn't really make sense.
|
|
|
|
// case (token::RECV) {
|
|
|
|
// p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
// ret some(rec(op = init_recv,
|
2011-07-27 12:19:39 +00:00
|
|
|
// expr = parse_expr(p)));
|
|
|
|
// }
|
|
|
|
_ {
|
|
|
|
ret none;
|
|
|
|
}
|
2010-10-12 01:20:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_pats(p: parser) -> [@pat] {
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut pats = [];
|
2012-03-11 04:34:17 +00:00
|
|
|
loop {
|
2011-08-19 22:16:48 +00:00
|
|
|
pats += [parse_pat(p)];
|
2012-03-11 04:34:17 +00:00
|
|
|
if p.token == token::BINOP(token::OR) { p.bump(); } else { ret pats; }
|
|
|
|
};
|
2011-07-08 14:27:55 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_pat(p: parser) -> @pat {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut hi = p.span.hi;
|
|
|
|
let mut pat;
|
2012-01-13 08:56:53 +00:00
|
|
|
alt p.token {
|
2012-05-08 14:07:32 +00:00
|
|
|
token::UNDERSCORE { p.bump(); pat = pat_wild; }
|
2012-01-19 06:37:22 +00:00
|
|
|
token::AT {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
|
|
|
let sub = parse_pat(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
pat = pat_box(sub);
|
2011-07-27 12:19:39 +00:00
|
|
|
hi = sub.span.hi;
|
|
|
|
}
|
2012-01-19 06:37:22 +00:00
|
|
|
token::TILDE {
|
2011-09-23 18:15:17 +00:00
|
|
|
p.bump();
|
|
|
|
let sub = parse_pat(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
pat = pat_uniq(sub);
|
2011-09-23 18:15:17 +00:00
|
|
|
hi = sub.span.hi;
|
|
|
|
}
|
2012-01-19 06:37:22 +00:00
|
|
|
token::LBRACE {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut fields = [];
|
|
|
|
let mut etc = false;
|
|
|
|
let mut first = true;
|
2012-01-13 08:56:53 +00:00
|
|
|
while p.token != token::RBRACE {
|
2011-07-27 12:19:39 +00:00
|
|
|
if first { first = false; } else { expect(p, token::COMMA); }
|
|
|
|
|
2012-01-13 08:56:53 +00:00
|
|
|
if p.token == token::UNDERSCORE {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
2012-01-13 08:56:53 +00:00
|
|
|
if p.token != token::RBRACE {
|
2011-09-02 22:34:58 +00:00
|
|
|
p.fatal("expecting }, found " +
|
2012-04-15 10:44:32 +00:00
|
|
|
token_to_str(p.reader, p.token));
|
2011-07-11 12:13:20 +00:00
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
etc = true;
|
|
|
|
break;
|
|
|
|
}
|
2011-07-11 22:20:33 +00:00
|
|
|
|
2012-01-15 00:05:07 +00:00
|
|
|
let lo1 = p.last_span.lo;
|
2012-04-27 22:44:40 +00:00
|
|
|
let fieldname = if p.look_ahead(1u) == token::COLON {
|
|
|
|
parse_ident(p)
|
|
|
|
} else {
|
|
|
|
parse_value_ident(p)
|
|
|
|
};
|
2012-01-15 00:05:07 +00:00
|
|
|
let hi1 = p.last_span.lo;
|
2012-04-23 11:04:46 +00:00
|
|
|
let fieldpath = ast_util::ident_to_path(mk_sp(lo1, hi1),
|
2012-01-15 00:05:07 +00:00
|
|
|
fieldname);
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut subpat;
|
2012-01-13 08:56:53 +00:00
|
|
|
if p.token == token::COLON {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
|
|
|
subpat = parse_pat(p);
|
|
|
|
} else {
|
2011-12-08 10:56:16 +00:00
|
|
|
subpat = @{id: p.get_id(),
|
2012-05-08 14:07:32 +00:00
|
|
|
node: pat_ident(fieldpath, none),
|
2012-04-23 11:04:46 +00:00
|
|
|
span: mk_sp(lo, hi)};
|
2011-07-11 12:13:20 +00:00
|
|
|
}
|
2011-08-19 22:16:48 +00:00
|
|
|
fields += [{ident: fieldname, pat: subpat}];
|
2011-07-11 12:13:20 +00:00
|
|
|
}
|
2012-01-13 08:56:53 +00:00
|
|
|
hi = p.span.hi;
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
pat = pat_rec(fields, etc);
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-01-19 06:37:22 +00:00
|
|
|
token::LPAREN {
|
2011-08-15 11:15:19 +00:00
|
|
|
p.bump();
|
2012-01-13 08:56:53 +00:00
|
|
|
if p.token == token::RPAREN {
|
|
|
|
hi = p.span.hi;
|
2011-08-15 11:15:19 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
let lit = @{node: lit_nil, span: mk_sp(lo, hi)};
|
|
|
|
let expr = mk_expr(p, lo, hi, expr_lit(lit));
|
|
|
|
pat = pat_lit(expr);
|
2011-08-15 11:15:19 +00:00
|
|
|
} else {
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut fields = [parse_pat(p)];
|
2012-01-13 08:56:53 +00:00
|
|
|
while p.token == token::COMMA {
|
2011-08-15 11:15:19 +00:00
|
|
|
p.bump();
|
2011-08-19 22:16:48 +00:00
|
|
|
fields += [parse_pat(p)];
|
2011-08-15 11:15:19 +00:00
|
|
|
}
|
2011-08-15 23:38:23 +00:00
|
|
|
if vec::len(fields) == 1u { expect(p, token::COMMA); }
|
2012-01-13 08:56:53 +00:00
|
|
|
hi = p.span.hi;
|
2011-08-15 11:15:19 +00:00
|
|
|
expect(p, token::RPAREN);
|
2012-05-08 14:07:32 +00:00
|
|
|
pat = pat_tup(fields);
|
2011-08-15 11:15:19 +00:00
|
|
|
}
|
2011-09-01 05:34:41 +00:00
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
tok {
|
2012-04-25 03:16:53 +00:00
|
|
|
if !is_ident(tok) || is_keyword(p, "true") || is_keyword(p, "false") {
|
2011-12-02 12:42:51 +00:00
|
|
|
let val = parse_expr_res(p, RESTRICT_NO_BAR_OP);
|
2012-04-25 03:16:53 +00:00
|
|
|
if eat_keyword(p, "to") {
|
2011-12-02 12:42:51 +00:00
|
|
|
let end = parse_expr_res(p, RESTRICT_NO_BAR_OP);
|
2011-09-28 19:07:33 +00:00
|
|
|
hi = end.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
pat = pat_range(val, end);
|
2011-09-28 19:07:33 +00:00
|
|
|
} else {
|
2011-12-02 12:42:51 +00:00
|
|
|
hi = val.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
pat = pat_lit(val);
|
2011-09-28 19:07:33 +00:00
|
|
|
}
|
2012-04-18 04:14:40 +00:00
|
|
|
} else if is_plain_ident(p.token) &&
|
2012-02-10 14:48:25 +00:00
|
|
|
alt p.look_ahead(1u) {
|
|
|
|
token::LPAREN | token::LBRACKET | token::LT { false }
|
|
|
|
_ { true }
|
|
|
|
} {
|
|
|
|
let name = parse_value_path(p);
|
2012-02-10 13:33:36 +00:00
|
|
|
let sub = if eat(p, token::AT) { some(parse_pat(p)) }
|
|
|
|
else { none };
|
2012-05-08 14:07:32 +00:00
|
|
|
pat = pat_ident(name, sub);
|
2011-07-27 12:19:39 +00:00
|
|
|
} else {
|
2012-04-24 22:52:52 +00:00
|
|
|
let enum_path = parse_path_with_tps(p, true);
|
2012-01-25 13:34:31 +00:00
|
|
|
hi = enum_path.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
let mut args: [@pat] = [];
|
2012-04-20 07:54:42 +00:00
|
|
|
let mut star_pat = false;
|
2012-01-13 08:56:53 +00:00
|
|
|
alt p.token {
|
2012-01-19 06:37:22 +00:00
|
|
|
token::LPAREN {
|
2012-04-20 07:54:42 +00:00
|
|
|
alt p.look_ahead(1u) {
|
|
|
|
token::BINOP(token::STAR) {
|
|
|
|
// This is a "top constructor only" pat
|
|
|
|
p.bump(); p.bump();
|
|
|
|
star_pat = true;
|
|
|
|
expect(p, token::RPAREN);
|
|
|
|
}
|
|
|
|
_ {
|
|
|
|
let a =
|
|
|
|
parse_seq(token::LPAREN, token::RPAREN,
|
|
|
|
seq_sep(token::COMMA), parse_pat, p);
|
|
|
|
args = a.node;
|
|
|
|
hi = a.span.hi;
|
|
|
|
}
|
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-04-20 07:54:42 +00:00
|
|
|
_ { }
|
2011-05-13 19:30:08 +00:00
|
|
|
}
|
2012-01-19 22:24:03 +00:00
|
|
|
// at this point, we're not sure whether it's a enum or a bind
|
2012-04-20 07:54:42 +00:00
|
|
|
if star_pat {
|
2012-05-08 14:07:32 +00:00
|
|
|
pat = pat_enum(enum_path, none);
|
2012-04-20 07:54:42 +00:00
|
|
|
}
|
|
|
|
else if vec::is_empty(args) &&
|
2012-04-23 11:04:46 +00:00
|
|
|
vec::len(enum_path.idents) == 1u {
|
2012-05-08 14:07:32 +00:00
|
|
|
pat = pat_ident(enum_path, none);
|
2012-01-15 00:05:07 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-05-08 14:07:32 +00:00
|
|
|
pat = pat_enum(enum_path, some(args));
|
2012-01-15 00:05:07 +00:00
|
|
|
}
|
2010-11-24 22:42:01 +00:00
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2010-11-24 22:42:01 +00:00
|
|
|
}
|
2012-04-23 11:04:46 +00:00
|
|
|
ret @{id: p.get_id(), node: pat, span: mk_sp(lo, hi)};
|
2010-11-24 22:42:01 +00:00
|
|
|
}
|
|
|
|
|
2012-02-29 03:28:29 +00:00
|
|
|
fn parse_local(p: parser, is_mutbl: bool,
|
2012-05-08 14:07:32 +00:00
|
|
|
allow_init: bool) -> @local {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2011-07-28 10:01:45 +00:00
|
|
|
let pat = parse_pat(p);
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut ty = @{id: p.get_id(),
|
2012-05-08 14:07:32 +00:00
|
|
|
node: ty_infer,
|
2012-04-23 11:04:46 +00:00
|
|
|
span: mk_sp(lo, lo)};
|
2011-08-15 19:06:10 +00:00
|
|
|
if eat(p, token::COLON) { ty = parse_ty(p, false); }
|
2011-07-27 12:19:39 +00:00
|
|
|
let init = if allow_init { parse_initializer(p) } else { none };
|
2012-01-13 08:56:53 +00:00
|
|
|
ret @spanned(lo, p.last_span.hi,
|
2012-02-29 03:28:29 +00:00
|
|
|
{is_mutbl: is_mutbl, ty: ty, pat: pat,
|
|
|
|
init: init, id: p.get_id()});
|
2010-10-19 01:19:16 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_let(p: parser) -> @decl {
|
2012-04-25 03:16:53 +00:00
|
|
|
let is_mutbl = eat_keyword(p, "mut");
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut locals = [parse_local(p, is_mutbl, true)];
|
2011-09-15 09:42:56 +00:00
|
|
|
while eat(p, token::COMMA) {
|
2012-02-29 03:28:29 +00:00
|
|
|
locals += [parse_local(p, is_mutbl, true)];
|
2011-07-26 08:27:26 +00:00
|
|
|
}
|
2012-05-08 14:07:32 +00:00
|
|
|
ret @spanned(lo, p.last_span.hi, decl_local(locals));
|
2011-07-26 08:27:26 +00:00
|
|
|
}
|
|
|
|
|
2012-03-19 17:19:00 +00:00
|
|
|
/* assumes "let" token has already been consumed */
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_instance_var(p:parser, pr: visibility) -> @class_member {
|
|
|
|
let mut is_mutbl = class_immutable;
|
2012-03-04 01:49:23 +00:00
|
|
|
let lo = p.span.lo;
|
2012-04-25 03:16:53 +00:00
|
|
|
if eat_keyword(p, "mut") {
|
2012-05-08 14:07:32 +00:00
|
|
|
is_mutbl = class_mutable;
|
2012-02-01 03:30:40 +00:00
|
|
|
}
|
2012-04-18 04:14:40 +00:00
|
|
|
if !is_plain_ident(p.token) {
|
2012-02-01 03:30:40 +00:00
|
|
|
p.fatal("expecting ident");
|
|
|
|
}
|
|
|
|
let name = parse_ident(p);
|
|
|
|
expect(p, token::COLON);
|
|
|
|
let ty = parse_ty(p, false);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret @{node: instance_var(name, ty, is_mutbl, p.get_id(), pr),
|
2012-04-23 11:04:46 +00:00
|
|
|
span: mk_sp(lo, p.last_span.hi)};
|
2012-02-01 03:30:40 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_stmt(p: parser, +first_item_attrs: [attribute]) -> @stmt {
|
|
|
|
fn check_expected_item(p: parser, current_attrs: [attribute]) {
|
2012-01-16 01:23:59 +00:00
|
|
|
// If we have attributes then we should have an item
|
|
|
|
if vec::is_not_empty(current_attrs) {
|
|
|
|
p.fatal("expected item");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2012-04-25 03:16:53 +00:00
|
|
|
if is_keyword(p, "let") {
|
2012-01-16 01:23:59 +00:00
|
|
|
check_expected_item(p, first_item_attrs);
|
2012-04-25 03:16:53 +00:00
|
|
|
expect_keyword(p, "let");
|
2011-07-27 12:19:39 +00:00
|
|
|
let decl = parse_let(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret @spanned(lo, decl.span.hi, stmt_decl(decl, p.get_id()));
|
2011-05-13 19:30:08 +00:00
|
|
|
} else {
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut item_attrs;
|
2012-01-16 01:23:59 +00:00
|
|
|
alt parse_outer_attrs_or_ext(p, first_item_attrs) {
|
2012-01-19 06:37:22 +00:00
|
|
|
none { item_attrs = []; }
|
2011-07-27 12:19:39 +00:00
|
|
|
some(left(attrs)) { item_attrs = attrs; }
|
|
|
|
some(right(ext)) {
|
2012-05-08 14:07:32 +00:00
|
|
|
ret @spanned(lo, ext.span.hi, stmt_expr(ext, p.get_id()));
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2011-06-15 20:27:39 +00:00
|
|
|
}
|
|
|
|
|
2012-01-16 01:23:59 +00:00
|
|
|
let item_attrs = first_item_attrs + item_attrs;
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
alt parse_item(p, item_attrs, public) {
|
2011-07-29 13:01:06 +00:00
|
|
|
some(i) {
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut hi = i.span.hi;
|
2012-05-08 14:07:32 +00:00
|
|
|
let decl = @spanned(lo, hi, decl_item(i));
|
|
|
|
ret @spanned(lo, hi, stmt_decl(decl, p.get_id()));
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2011-12-21 04:12:52 +00:00
|
|
|
none() { /* fallthrough */ }
|
2010-10-04 22:55:12 +00:00
|
|
|
}
|
2011-12-21 04:12:52 +00:00
|
|
|
|
2012-01-16 01:23:59 +00:00
|
|
|
check_expected_item(p, item_attrs);
|
2011-12-21 04:12:52 +00:00
|
|
|
|
|
|
|
// Remainder are line-expr stmts.
|
|
|
|
let e = parse_expr_res(p, RESTRICT_STMT_EXPR);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret @spanned(lo, e.span.hi, stmt_expr(e, p.get_id()));
|
2010-09-21 23:22:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-04 06:03:07 +00:00
|
|
|
fn expr_is_complete(p: parser, e: pexpr) -> bool {
|
2012-01-13 08:56:53 +00:00
|
|
|
log(debug, ("expr_is_complete", p.restriction,
|
2012-01-04 06:03:07 +00:00
|
|
|
print::pprust::expr_to_str(*e),
|
2012-04-18 05:02:00 +00:00
|
|
|
classify::expr_requires_semi_to_be_stmt(*e)));
|
2012-01-13 08:56:53 +00:00
|
|
|
ret p.restriction == RESTRICT_STMT_EXPR &&
|
2012-04-18 05:02:00 +00:00
|
|
|
!classify::expr_requires_semi_to_be_stmt(*e);
|
2010-11-30 01:11:03 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_block(p: parser) -> blk {
|
2012-01-16 01:23:59 +00:00
|
|
|
let (attrs, blk) = parse_inner_attrs_and_block(p, false);
|
|
|
|
assert vec::is_empty(attrs);
|
|
|
|
ret blk;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_inner_attrs_and_block(
|
2012-05-08 14:07:32 +00:00
|
|
|
p: parser, parse_attrs: bool) -> ([attribute], blk) {
|
2012-01-16 01:23:59 +00:00
|
|
|
|
|
|
|
fn maybe_parse_inner_attrs_and_next(
|
|
|
|
p: parser, parse_attrs: bool) ->
|
2012-05-08 14:07:32 +00:00
|
|
|
{inner: [attribute], next: [attribute]} {
|
2012-01-16 01:23:59 +00:00
|
|
|
if parse_attrs {
|
|
|
|
parse_inner_attrs_and_next(p)
|
|
|
|
} else {
|
|
|
|
{inner: [], next: []}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2012-04-25 03:16:53 +00:00
|
|
|
if eat_keyword(p, "unchecked") {
|
2011-10-07 22:51:55 +00:00
|
|
|
expect(p, token::LBRACE);
|
2012-01-16 01:23:59 +00:00
|
|
|
let {inner, next} = maybe_parse_inner_attrs_and_next(p, parse_attrs);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret (inner, parse_block_tail_(p, lo, unchecked_blk, next));
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "unsafe") {
|
2011-10-07 22:51:55 +00:00
|
|
|
expect(p, token::LBRACE);
|
2012-01-16 01:23:59 +00:00
|
|
|
let {inner, next} = maybe_parse_inner_attrs_and_next(p, parse_attrs);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret (inner, parse_block_tail_(p, lo, unsafe_blk, next));
|
2011-09-02 22:34:58 +00:00
|
|
|
} else {
|
2011-08-26 00:42:38 +00:00
|
|
|
expect(p, token::LBRACE);
|
2012-01-16 01:23:59 +00:00
|
|
|
let {inner, next} = maybe_parse_inner_attrs_and_next(p, parse_attrs);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret (inner, parse_block_tail_(p, lo, default_blk, next));
|
2011-08-26 00:42:38 +00:00
|
|
|
}
|
2011-06-30 01:07:04 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_block_no_value(p: parser) -> blk {
|
2011-12-29 20:03:39 +00:00
|
|
|
// We parse blocks that cannot have a value the same as any other block;
|
|
|
|
// the type checker will make sure that the tail expression (if any) has
|
|
|
|
// unit type.
|
|
|
|
ret parse_block(p);
|
2011-09-15 07:39:24 +00:00
|
|
|
}
|
|
|
|
|
2011-08-26 00:42:38 +00:00
|
|
|
// Precondition: already parsed the '{' or '#{'
|
|
|
|
// I guess that also means "already parsed the 'impure'" if
|
|
|
|
// necessary, and this should take a qualifier.
|
2011-07-13 22:44:09 +00:00
|
|
|
// some blocks start with "#{"...
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_block_tail(p: parser, lo: uint, s: blk_check_mode) -> blk {
|
2012-01-16 01:23:59 +00:00
|
|
|
parse_block_tail_(p, lo, s, [])
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_block_tail_(p: parser, lo: uint, s: blk_check_mode,
|
|
|
|
+first_item_attrs: [attribute]) -> blk {
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut stmts = [];
|
|
|
|
let mut expr = none;
|
2012-05-08 21:01:38 +00:00
|
|
|
let {attrs_remaining, view_items} = parse_view(p, first_item_attrs, true);
|
|
|
|
let mut initial_attrs = attrs_remaining;
|
2012-01-16 01:23:59 +00:00
|
|
|
|
|
|
|
if p.token == token::RBRACE && !vec::is_empty(initial_attrs) {
|
|
|
|
p.fatal("expected item");
|
|
|
|
}
|
|
|
|
|
2012-01-13 08:56:53 +00:00
|
|
|
while p.token != token::RBRACE {
|
|
|
|
alt p.token {
|
2012-01-19 06:37:22 +00:00
|
|
|
token::SEMI {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump(); // empty
|
|
|
|
}
|
|
|
|
_ {
|
2012-01-16 01:23:59 +00:00
|
|
|
let stmt = parse_stmt(p, initial_attrs);
|
|
|
|
initial_attrs = [];
|
2012-01-04 22:16:41 +00:00
|
|
|
alt stmt.node {
|
2012-05-08 14:07:32 +00:00
|
|
|
stmt_expr(e, stmt_id) { // Expression without semicolon:
|
2012-01-13 08:56:53 +00:00
|
|
|
alt p.token {
|
2012-01-19 06:37:22 +00:00
|
|
|
token::SEMI {
|
2012-01-04 22:16:41 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
stmts += [@{node: stmt_semi(e, stmt_id) with *stmt}];
|
2012-01-04 22:16:41 +00:00
|
|
|
}
|
2012-01-19 06:37:22 +00:00
|
|
|
token::RBRACE {
|
2012-01-04 22:16:41 +00:00
|
|
|
expr = some(e);
|
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
t {
|
2012-04-18 05:02:00 +00:00
|
|
|
if classify::stmt_ends_with_semi(*stmt) {
|
2011-12-19 08:48:28 +00:00
|
|
|
p.fatal("expected ';' or '}' after expression but \
|
2012-04-15 10:44:32 +00:00
|
|
|
found '" + token_to_str(p.reader, t) +
|
2011-12-19 08:48:28 +00:00
|
|
|
"'");
|
2010-11-30 01:11:03 +00:00
|
|
|
}
|
2011-08-19 22:16:48 +00:00
|
|
|
stmts += [stmt];
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2010-11-30 01:11:03 +00:00
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-01-04 22:16:41 +00:00
|
|
|
|
|
|
|
_ { // All other kinds of statements:
|
2011-08-19 22:16:48 +00:00
|
|
|
stmts += [stmt];
|
2011-07-27 12:19:39 +00:00
|
|
|
|
2012-04-18 05:02:00 +00:00
|
|
|
if classify::stmt_ends_with_semi(*stmt) {
|
2011-07-27 12:19:39 +00:00
|
|
|
expect(p, token::SEMI);
|
|
|
|
}
|
|
|
|
}
|
2010-11-30 01:11:03 +00:00
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2010-11-30 01:11:03 +00:00
|
|
|
}
|
|
|
|
}
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut hi = p.span.hi;
|
2011-03-24 15:33:20 +00:00
|
|
|
p.bump();
|
2011-11-23 19:57:34 +00:00
|
|
|
let bloc = {view_items: view_items, stmts: stmts, expr: expr,
|
|
|
|
id: p.get_id(), rules: s};
|
2011-06-14 20:08:30 +00:00
|
|
|
ret spanned(lo, hi, bloc);
|
2010-09-21 23:22:32 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_ty_param(p: parser) -> ty_param {
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut bounds = [];
|
2011-12-28 16:50:12 +00:00
|
|
|
let ident = parse_ident(p);
|
|
|
|
if eat(p, token::COLON) {
|
2012-01-13 08:56:53 +00:00
|
|
|
while p.token != token::COMMA && p.token != token::GT {
|
2012-05-08 14:07:32 +00:00
|
|
|
if eat_keyword(p, "send") { bounds += [bound_send]; }
|
|
|
|
else if eat_keyword(p, "copy") { bounds += [bound_copy]; }
|
|
|
|
else { bounds += [bound_iface(parse_ty(p, false))]; }
|
2011-12-28 16:50:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret {ident: ident, id: p.get_id(), bounds: @bounds};
|
2011-07-28 17:22:59 +00:00
|
|
|
}
|
2010-11-25 02:01:20 +00:00
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_ty_params(p: parser) -> [ty_param] {
|
2011-12-20 15:33:55 +00:00
|
|
|
if eat(p, token::LT) {
|
|
|
|
parse_seq_to_gt(some(token::COMMA), parse_ty_param, p)
|
|
|
|
} else { [] }
|
2010-11-25 01:15:54 +00:00
|
|
|
}
|
|
|
|
|
2012-05-04 19:33:04 +00:00
|
|
|
// FIXME Remove after snapshot
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_old_skool_capture_clause(p: parser) -> [capture_item] {
|
2012-05-04 19:33:04 +00:00
|
|
|
fn expect_opt_trailing_semi(p: parser) {
|
|
|
|
if !eat(p, token::SEMI) {
|
|
|
|
if p.token != token::RBRACKET {
|
|
|
|
p.fatal("expecting ; or ]");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn eat_ident_list(p: parser, is_move: bool) -> [capture_item] {
|
2012-05-04 19:33:04 +00:00
|
|
|
let mut res = [];
|
|
|
|
loop {
|
|
|
|
alt p.token {
|
|
|
|
token::IDENT(_, _) {
|
|
|
|
let id = p.get_id();
|
|
|
|
let sp = mk_sp(p.span.lo, p.span.hi);
|
|
|
|
let ident = parse_ident(p);
|
|
|
|
res += [{id:id, is_move: is_move, name:ident, span:sp}];
|
|
|
|
if !eat(p, token::COMMA) {
|
|
|
|
ret res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_ { ret res; }
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut cap_items = [];
|
|
|
|
|
|
|
|
if eat(p, token::LBRACKET) {
|
|
|
|
while !eat(p, token::RBRACKET) {
|
|
|
|
if eat_keyword(p, "copy") {
|
|
|
|
cap_items += eat_ident_list(p, false);
|
|
|
|
expect_opt_trailing_semi(p);
|
|
|
|
} else if eat_keyword(p, "move") {
|
|
|
|
cap_items += eat_ident_list(p, true);
|
|
|
|
expect_opt_trailing_semi(p);
|
|
|
|
} else {
|
|
|
|
let s: str = "expecting send, copy, or move clause";
|
|
|
|
p.fatal(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret cap_items;
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
type arg_or_capture_item = either<arg, capture_item>;
|
2012-05-04 19:33:04 +00:00
|
|
|
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_fn_decl(p: parser, purity: purity,
|
2012-05-04 19:33:04 +00:00
|
|
|
parse_arg_fn: fn(parser) -> arg_or_capture_item)
|
2012-05-08 14:07:32 +00:00
|
|
|
-> (fn_decl, capture_clause) {
|
2012-05-04 19:33:04 +00:00
|
|
|
|
|
|
|
let args_or_capture_items: [arg_or_capture_item] =
|
2011-11-21 15:36:11 +00:00
|
|
|
parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
|
2012-05-04 19:33:04 +00:00
|
|
|
parse_arg_fn, p).node;
|
|
|
|
|
|
|
|
let inputs = either::lefts(args_or_capture_items);
|
2012-05-07 18:31:57 +00:00
|
|
|
let capture_clause = @either::rights(args_or_capture_items);
|
2012-05-04 19:33:04 +00:00
|
|
|
|
2011-07-27 07:13:00 +00:00
|
|
|
// Use the args list to translate each bound variable
|
|
|
|
// mentioned in a constraint to an arg index.
|
|
|
|
// Seems weird to do this in the parser, but I'm not sure how else to.
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut constrs = [];
|
2012-01-13 08:56:53 +00:00
|
|
|
if p.token == token::COLON {
|
2011-07-20 00:52:34 +00:00
|
|
|
p.bump();
|
2012-05-04 19:33:04 +00:00
|
|
|
constrs = parse_constrs({|x| parse_ty_constr(inputs, x) }, p);
|
2011-07-20 00:52:34 +00:00
|
|
|
}
|
2011-11-23 09:56:10 +00:00
|
|
|
let (ret_style, ret_ty) = parse_ret_ty(p);
|
2012-05-04 19:33:04 +00:00
|
|
|
ret ({inputs: inputs,
|
|
|
|
output: ret_ty,
|
|
|
|
purity: purity,
|
|
|
|
cf: ret_style,
|
|
|
|
constraints: constrs}, capture_clause);
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_fn_block_decl(p: parser) -> (fn_decl, capture_clause) {
|
2012-05-04 19:33:04 +00:00
|
|
|
let inputs_captures = {
|
|
|
|
if eat(p, token::OROR) {
|
|
|
|
[]
|
|
|
|
} else {
|
|
|
|
parse_seq(token::BINOP(token::OR),
|
|
|
|
token::BINOP(token::OR),
|
|
|
|
seq_sep(token::COMMA),
|
|
|
|
parse_fn_block_arg, p).node
|
|
|
|
}
|
|
|
|
};
|
2012-01-30 02:33:08 +00:00
|
|
|
let output = if eat(p, token::RARROW) {
|
|
|
|
parse_ty(p, false)
|
|
|
|
} else {
|
2012-05-08 14:07:32 +00:00
|
|
|
@{id: p.get_id(), node: ty_infer, span: p.span}
|
2012-01-30 02:33:08 +00:00
|
|
|
};
|
2012-05-04 19:33:04 +00:00
|
|
|
ret ({inputs: either::lefts(inputs_captures),
|
|
|
|
output: output,
|
2012-05-08 14:07:32 +00:00
|
|
|
purity: impure_fn,
|
|
|
|
cf: return_val,
|
2012-05-04 19:33:04 +00:00
|
|
|
constraints: []},
|
2012-05-07 18:31:57 +00:00
|
|
|
@either::rights(inputs_captures));
|
2011-08-12 19:58:37 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_fn_header(p: parser) -> {ident: ident, tps: [ty_param]} {
|
2011-07-27 12:19:39 +00:00
|
|
|
let id = parse_value_ident(p);
|
2011-11-18 11:39:20 +00:00
|
|
|
let ty_params = parse_ty_params(p);
|
2011-07-27 12:19:39 +00:00
|
|
|
ret {ident: id, tps: ty_params};
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn mk_item(p: parser, lo: uint, hi: uint, +ident: ident,
|
|
|
|
+node: item_, vis: visibility,
|
|
|
|
+attrs: [attribute]) -> @item {
|
2011-07-27 12:19:39 +00:00
|
|
|
ret @{ident: ident,
|
|
|
|
attrs: attrs,
|
|
|
|
id: p.get_id(),
|
|
|
|
node: node,
|
2012-05-08 14:06:24 +00:00
|
|
|
vis: vis,
|
2012-04-23 11:04:46 +00:00
|
|
|
span: mk_sp(lo, hi)};
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
type item_info = (ident, item_, option<[attribute]>);
|
2012-05-08 13:37:32 +00:00
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_item_fn(p: parser, purity: purity) -> item_info {
|
2011-07-27 12:19:39 +00:00
|
|
|
let t = parse_fn_header(p);
|
2012-05-04 19:33:04 +00:00
|
|
|
let (decl, _) = parse_fn_decl(p, purity, parse_arg);
|
2012-01-16 01:23:59 +00:00
|
|
|
let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
|
2012-05-08 14:07:32 +00:00
|
|
|
(t.ident, item_fn(decl, t.tps, body), some(inner_attrs))
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_method_name(p: parser) -> ident {
|
2012-01-26 14:52:28 +00:00
|
|
|
alt p.token {
|
|
|
|
token::BINOP(op) { p.bump(); token::binop_to_str(op) }
|
|
|
|
token::NOT { p.bump(); "!" }
|
|
|
|
token::LBRACKET { p.bump(); expect(p, token::RBRACKET); "[]" }
|
2012-01-27 09:06:53 +00:00
|
|
|
_ {
|
|
|
|
let id = parse_value_ident(p);
|
|
|
|
if id == "unary" && eat(p, token::BINOP(token::MINUS)) { "unary-" }
|
|
|
|
else { id }
|
|
|
|
}
|
2012-01-26 14:52:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_method(p: parser, pr: visibility) -> @method {
|
2012-01-30 19:43:45 +00:00
|
|
|
let attrs = parse_outer_attributes(p);
|
2012-02-13 17:56:09 +00:00
|
|
|
let lo = p.span.lo, pur = parse_fn_purity(p);
|
2012-01-26 14:52:28 +00:00
|
|
|
let ident = parse_method_name(p);
|
2012-01-13 09:58:31 +00:00
|
|
|
let tps = parse_ty_params(p);
|
2012-05-04 19:33:04 +00:00
|
|
|
let (decl, _) = parse_fn_decl(p, pur, parse_arg);
|
2012-01-30 19:43:45 +00:00
|
|
|
let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
|
|
|
|
let attrs = attrs + inner_attrs;
|
|
|
|
@{ident: ident, attrs: attrs, tps: tps, decl: decl, body: body,
|
2012-04-23 11:04:46 +00:00
|
|
|
id: p.get_id(), span: mk_sp(lo, body.span.hi),
|
2012-05-08 14:06:24 +00:00
|
|
|
self_id: p.get_id(), vis: pr}
|
2010-12-14 23:32:13 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 13:37:32 +00:00
|
|
|
fn parse_item_iface(p: parser) -> item_info {
|
|
|
|
let ident = parse_ident(p);
|
2012-04-24 22:52:52 +00:00
|
|
|
let rp = parse_region_param(p);
|
|
|
|
let tps = parse_ty_params(p);
|
|
|
|
let meths = parse_ty_methods(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
(ident, item_iface(tps, rp, meths), none)
|
2011-12-20 15:33:55 +00:00
|
|
|
}
|
|
|
|
|
2012-04-24 22:52:52 +00:00
|
|
|
// Parses three variants (with the region/type params always optional):
|
|
|
|
// impl /&<T: copy> of to_str for [T] { ... }
|
|
|
|
// impl name/&<T> of to_str for [T] { ... }
|
|
|
|
// impl name/&<T> for [T] { ... }
|
2012-05-08 13:37:32 +00:00
|
|
|
fn parse_item_impl(p: parser) -> item_info {
|
2012-05-08 14:07:32 +00:00
|
|
|
fn wrap_path(p: parser, pt: @path) -> @ty {
|
|
|
|
@{id: p.get_id(), node: ty_path(pt, p.get_id()), span: pt.span}
|
2012-04-24 22:52:52 +00:00
|
|
|
}
|
|
|
|
let mut (ident, rp, tps) = {
|
|
|
|
if p.token == token::LT {
|
2012-05-08 14:07:32 +00:00
|
|
|
(none, rp_none, parse_ty_params(p))
|
2012-04-24 22:52:52 +00:00
|
|
|
} else if p.token == token::BINOP(token::SLASH) {
|
|
|
|
(none, parse_region_param(p), parse_ty_params(p))
|
|
|
|
}
|
|
|
|
else if is_keyword(p, "of") {
|
2012-05-08 14:07:32 +00:00
|
|
|
(none, rp_none, [])
|
2012-04-24 22:52:52 +00:00
|
|
|
} else {
|
|
|
|
let id = parse_ident(p);
|
|
|
|
let rp = parse_region_param(p);
|
|
|
|
(some(id), rp, parse_ty_params(p))
|
|
|
|
}
|
|
|
|
};
|
2012-04-25 03:16:53 +00:00
|
|
|
let ifce = if eat_keyword(p, "of") {
|
2012-04-24 22:52:52 +00:00
|
|
|
let path = parse_path_with_tps(p, false);
|
2012-01-03 14:29:28 +00:00
|
|
|
if option::is_none(ident) {
|
2012-04-23 11:04:46 +00:00
|
|
|
ident = some(vec::last(path.idents));
|
2012-01-03 14:29:28 +00:00
|
|
|
}
|
2012-04-13 19:22:35 +00:00
|
|
|
some(@{path: path, id: p.get_id()})
|
2012-01-03 14:29:28 +00:00
|
|
|
} else { none };
|
|
|
|
let ident = alt ident {
|
|
|
|
some(name) { name }
|
2012-04-25 03:16:53 +00:00
|
|
|
none { expect_keyword(p, "of"); fail; }
|
2011-12-20 15:33:55 +00:00
|
|
|
};
|
2012-04-25 03:16:53 +00:00
|
|
|
expect_keyword(p, "for");
|
2012-03-15 13:47:03 +00:00
|
|
|
let ty = parse_ty(p, false);
|
|
|
|
let mut meths = [];
|
2011-12-13 12:19:56 +00:00
|
|
|
expect(p, token::LBRACE);
|
2012-05-08 14:07:32 +00:00
|
|
|
while !eat(p, token::RBRACE) { meths += [parse_method(p, public)]; }
|
|
|
|
(ident, item_impl(tps, rp, ifce, ty, meths), none)
|
2011-12-13 12:19:56 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 13:37:32 +00:00
|
|
|
fn parse_item_res(p: parser) -> item_info {
|
2011-07-27 12:19:39 +00:00
|
|
|
let ident = parse_value_ident(p);
|
2012-04-19 04:26:25 +00:00
|
|
|
let rp = parse_region_param(p);
|
2011-11-18 11:39:20 +00:00
|
|
|
let ty_params = parse_ty_params(p);
|
2011-06-24 16:10:40 +00:00
|
|
|
expect(p, token::LPAREN);
|
2011-07-27 12:19:39 +00:00
|
|
|
let arg_ident = parse_value_ident(p);
|
2011-07-27 07:13:00 +00:00
|
|
|
expect(p, token::COLON);
|
2011-08-15 19:06:10 +00:00
|
|
|
let t = parse_ty(p, false);
|
2011-06-24 16:10:40 +00:00
|
|
|
expect(p, token::RPAREN);
|
2011-09-15 07:39:24 +00:00
|
|
|
let dtor = parse_block_no_value(p);
|
2012-05-08 13:37:32 +00:00
|
|
|
let decl = {
|
2012-05-08 14:07:32 +00:00
|
|
|
inputs: [{mode: expl(by_ref), ty: t,
|
2012-05-08 13:37:32 +00:00
|
|
|
ident: arg_ident, id: p.get_id()}],
|
2012-05-08 14:07:32 +00:00
|
|
|
output: @{id: p.get_id(), node: ty_nil,
|
2012-05-08 13:37:32 +00:00
|
|
|
span: ast_util::dummy_sp()},
|
2012-05-08 14:07:32 +00:00
|
|
|
purity: impure_fn,
|
|
|
|
cf: return_val,
|
2012-05-08 13:37:32 +00:00
|
|
|
constraints: []
|
|
|
|
};
|
2012-05-08 14:07:32 +00:00
|
|
|
(ident, item_res(decl, ty_params, dtor,
|
2012-05-08 13:37:32 +00:00
|
|
|
p.get_id(), p.get_id(), rp), none)
|
2011-06-24 16:10:40 +00:00
|
|
|
}
|
|
|
|
|
2012-04-24 22:52:52 +00:00
|
|
|
// Instantiates ident <i> with references to <typarams> as arguments. Used to
|
|
|
|
// create a path that refers to a class which will be defined as the return
|
|
|
|
// type of the ctor function.
|
2012-05-08 14:07:32 +00:00
|
|
|
fn ident_to_path_tys(p: parser, i: ident,
|
|
|
|
rp: region_param,
|
|
|
|
typarams: [ty_param]) -> @path {
|
2012-04-02 17:48:32 +00:00
|
|
|
let s = p.last_span;
|
2012-04-24 22:52:52 +00:00
|
|
|
|
|
|
|
// Hack. But then, this whole function is in service of a hack.
|
|
|
|
let a_r = alt rp {
|
2012-05-08 14:07:32 +00:00
|
|
|
rp_none { none }
|
|
|
|
rp_self { some(region_from_name(p, some("self"))) }
|
2012-04-24 22:52:52 +00:00
|
|
|
};
|
|
|
|
|
2012-04-23 11:04:46 +00:00
|
|
|
@{span: s, global: false, idents: [i],
|
2012-04-24 22:52:52 +00:00
|
|
|
rp: a_r,
|
2012-04-23 11:04:46 +00:00
|
|
|
types: vec::map(typarams, {|tp|
|
|
|
|
@{id: p.get_id(),
|
2012-05-08 14:07:32 +00:00
|
|
|
node: ty_path(ident_to_path(s, tp.ident), p.get_id()),
|
2012-04-23 11:04:46 +00:00
|
|
|
span: s}})
|
|
|
|
}
|
2012-04-02 17:48:32 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_iface_ref(p:parser) -> @iface_ref {
|
2012-04-24 22:52:52 +00:00
|
|
|
@{path: parse_path_with_tps(p, false),
|
|
|
|
id: p.get_id()}
|
2012-04-13 19:22:35 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_iface_ref_list(p:parser) -> [@iface_ref] {
|
2012-04-11 23:18:00 +00:00
|
|
|
parse_seq_to_before_end(token::LBRACE, seq_sep(token::COMMA),
|
2012-04-13 19:22:35 +00:00
|
|
|
parse_iface_ref, p)
|
2012-04-11 23:18:00 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 13:37:32 +00:00
|
|
|
fn parse_item_class(p: parser) -> item_info {
|
2012-02-01 03:30:40 +00:00
|
|
|
let class_name = parse_value_ident(p);
|
2012-04-19 04:26:25 +00:00
|
|
|
let rp = parse_region_param(p);
|
2012-02-01 03:30:40 +00:00
|
|
|
let ty_params = parse_ty_params(p);
|
2012-04-24 22:52:52 +00:00
|
|
|
let class_path = ident_to_path_tys(p, class_name, rp, ty_params);
|
2012-05-08 14:07:32 +00:00
|
|
|
let ifaces : [@iface_ref] = if eat_keyword(p, "implements")
|
2012-04-11 23:18:00 +00:00
|
|
|
{ parse_iface_ref_list(p) }
|
|
|
|
else { [] };
|
2012-02-01 03:30:40 +00:00
|
|
|
expect(p, token::LBRACE);
|
2012-05-08 14:07:32 +00:00
|
|
|
let mut ms: [@class_member] = [];
|
2012-02-07 19:31:15 +00:00
|
|
|
let ctor_id = p.get_id();
|
2012-05-08 14:07:32 +00:00
|
|
|
let mut the_ctor : option<(fn_decl, blk, codemap::span)> = none;
|
2012-05-14 21:13:32 +00:00
|
|
|
let mut the_dtor : option<(blk, codemap::span)> = none;
|
2012-02-01 03:30:40 +00:00
|
|
|
while p.token != token::RBRACE {
|
2012-02-20 23:42:21 +00:00
|
|
|
alt parse_class_item(p, class_path) {
|
2012-05-14 21:13:32 +00:00
|
|
|
ctor_decl(a_fn_decl, blk, s) {
|
|
|
|
the_ctor = some((a_fn_decl, blk, s));
|
|
|
|
}
|
|
|
|
dtor_decl(blk, s) {
|
|
|
|
the_dtor = some((blk, s));
|
|
|
|
}
|
|
|
|
members(mms) { ms += mms; }
|
2012-02-01 03:30:40 +00:00
|
|
|
}
|
|
|
|
}
|
2012-05-14 21:13:32 +00:00
|
|
|
let actual_dtor = option::map(the_dtor) {|dtor|
|
|
|
|
let (d_body, d_s) = dtor;
|
|
|
|
{node: {id: p.get_id(),
|
|
|
|
self_id: p.get_id(),
|
|
|
|
body: d_body},
|
|
|
|
span: d_s}};
|
2012-02-01 03:30:40 +00:00
|
|
|
p.bump();
|
|
|
|
alt the_ctor {
|
2012-03-28 21:17:41 +00:00
|
|
|
some((ct_d, ct_b, ct_s)) {
|
2012-05-08 13:37:32 +00:00
|
|
|
(class_name,
|
2012-05-08 14:07:32 +00:00
|
|
|
item_class(ty_params, ifaces, ms, {
|
2012-05-08 13:37:32 +00:00
|
|
|
node: {id: ctor_id,
|
|
|
|
self_id: p.get_id(),
|
|
|
|
dec: ct_d,
|
|
|
|
body: ct_b},
|
2012-05-14 21:13:32 +00:00
|
|
|
span: ct_s}, actual_dtor, rp),
|
2012-05-08 13:37:32 +00:00
|
|
|
none)
|
|
|
|
}
|
2012-02-01 03:30:40 +00:00
|
|
|
/*
|
|
|
|
Is it strange for the parser to check this?
|
|
|
|
*/
|
2012-03-06 00:27:27 +00:00
|
|
|
none {
|
|
|
|
p.fatal("class with no ctor");
|
|
|
|
}
|
2012-02-01 03:30:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_single_class_item(p: parser, vis: visibility)
|
|
|
|
-> @class_member {
|
2012-04-25 03:16:53 +00:00
|
|
|
if eat_keyword(p, "let") {
|
2012-05-08 14:06:24 +00:00
|
|
|
let a_var = parse_instance_var(p, vis);
|
2012-04-20 02:17:59 +00:00
|
|
|
expect(p, token::SEMI);
|
|
|
|
ret a_var;
|
|
|
|
}
|
|
|
|
else {
|
2012-05-08 14:06:24 +00:00
|
|
|
let m = parse_method(p, vis);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret @{node: class_method(m), span: m.span};
|
2012-04-20 02:17:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-14 21:13:32 +00:00
|
|
|
/*
|
|
|
|
So that we can distinguish a class ctor or dtor
|
|
|
|
from other class members
|
|
|
|
*/
|
2012-05-08 14:07:32 +00:00
|
|
|
enum class_contents { ctor_decl(fn_decl, blk, codemap::span),
|
2012-05-14 21:13:32 +00:00
|
|
|
dtor_decl(blk, codemap::span),
|
2012-05-08 14:07:32 +00:00
|
|
|
members([@class_member]) }
|
2012-03-29 01:50:33 +00:00
|
|
|
|
2012-05-14 21:13:32 +00:00
|
|
|
fn parse_ctor(p: parser, result_ty: ast::ty_) -> class_contents {
|
|
|
|
// Can ctors/dtors have attrs? FIXME
|
|
|
|
let lo = p.last_span.lo;
|
|
|
|
let (decl_, _) = parse_fn_decl(p, impure_fn, parse_arg);
|
|
|
|
let decl = {output: @{id: p.get_id(),
|
|
|
|
node: result_ty, span: decl_.output.span}
|
|
|
|
with decl_};
|
|
|
|
let body = parse_block(p);
|
|
|
|
ctor_decl(decl, body, mk_sp(lo, p.last_span.hi))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_dtor(p: parser) -> class_contents {
|
|
|
|
// Can ctors/dtors have attrs? FIXME
|
|
|
|
let lo = p.last_span.lo;
|
|
|
|
let body = parse_block(p);
|
|
|
|
dtor_decl(body, mk_sp(lo, p.last_span.hi))
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_class_item(p:parser, class_name_with_tps: @path)
|
2012-04-02 17:48:32 +00:00
|
|
|
-> class_contents {
|
2012-04-25 03:16:53 +00:00
|
|
|
if eat_keyword(p, "new") {
|
2012-05-14 21:13:32 +00:00
|
|
|
// result type is always the type of the class
|
|
|
|
ret parse_ctor(p, ty_path(class_name_with_tps,
|
|
|
|
p.get_id()));
|
|
|
|
}
|
|
|
|
else if eat_keyword(p, "drop") {
|
|
|
|
ret parse_dtor(p);
|
2012-02-01 03:30:40 +00:00
|
|
|
}
|
2012-04-25 03:16:53 +00:00
|
|
|
else if eat_keyword(p, "priv") {
|
2012-02-01 03:30:40 +00:00
|
|
|
expect(p, token::LBRACE);
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut results = [];
|
2012-02-01 03:30:40 +00:00
|
|
|
while p.token != token::RBRACE {
|
2012-05-08 14:07:32 +00:00
|
|
|
results += [parse_single_class_item(p, private)];
|
2012-02-01 03:30:40 +00:00
|
|
|
}
|
|
|
|
p.bump();
|
2012-03-29 01:50:33 +00:00
|
|
|
ret members(results);
|
2012-02-01 03:30:40 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Probably need to parse attrs
|
2012-05-08 14:07:32 +00:00
|
|
|
ret members([parse_single_class_item(p, public)]);
|
2012-02-01 03:30:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_visibility(p: parser, def: visibility) -> visibility {
|
|
|
|
if eat_keyword(p, "pub") { public }
|
|
|
|
else if eat_keyword(p, "priv") { private }
|
2012-05-08 14:06:24 +00:00
|
|
|
else { def }
|
|
|
|
}
|
|
|
|
|
2011-09-12 09:27:30 +00:00
|
|
|
fn parse_mod_items(p: parser, term: token::token,
|
2012-05-08 14:07:32 +00:00
|
|
|
+first_item_attrs: [attribute]) -> _mod {
|
2011-07-27 12:48:34 +00:00
|
|
|
// Shouldn't be any view items since we've already parsed an item attr
|
2012-05-08 21:01:38 +00:00
|
|
|
let {attrs_remaining, view_items} =
|
|
|
|
parse_view(p, first_item_attrs, false);
|
2012-05-08 14:07:32 +00:00
|
|
|
let mut items: [@item] = [];
|
2012-05-08 13:37:32 +00:00
|
|
|
let mut first = true;
|
2012-01-13 08:56:53 +00:00
|
|
|
while p.token != term {
|
2012-05-08 13:37:32 +00:00
|
|
|
let mut attrs = parse_outer_attributes(p);
|
2012-05-08 21:01:38 +00:00
|
|
|
if first { attrs = attrs_remaining + attrs; first = false; }
|
2012-02-02 02:52:08 +00:00
|
|
|
#debug["parse_mod_items: parse_item(attrs=%?)", attrs];
|
2012-05-08 14:07:32 +00:00
|
|
|
let vis = parse_visibility(p, private);
|
2012-05-08 14:06:24 +00:00
|
|
|
alt parse_item(p, attrs, vis) {
|
2011-08-19 22:16:48 +00:00
|
|
|
some(i) { items += [i]; }
|
2011-07-27 12:19:39 +00:00
|
|
|
_ {
|
2011-12-19 08:48:28 +00:00
|
|
|
p.fatal("expected item but found '" +
|
2012-04-15 10:44:32 +00:00
|
|
|
token_to_str(p.reader, p.token) + "'");
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2011-06-14 12:46:46 +00:00
|
|
|
}
|
2012-02-02 02:52:08 +00:00
|
|
|
#debug["parse_mod_items: attrs=%?", attrs];
|
2012-02-23 05:47:23 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 21:01:38 +00:00
|
|
|
if first && attrs_remaining.len() > 0u {
|
2012-02-23 05:47:23 +00:00
|
|
|
// We parsed attributes for the first item but didn't find the item
|
|
|
|
p.fatal("expected item");
|
2010-10-19 01:19:16 +00:00
|
|
|
}
|
2012-02-23 05:47:23 +00:00
|
|
|
|
2011-07-27 12:19:39 +00:00
|
|
|
ret {view_items: view_items, items: items};
|
2011-01-11 02:18:16 +00:00
|
|
|
}
|
2010-10-19 01:19:16 +00:00
|
|
|
|
2012-05-08 13:37:32 +00:00
|
|
|
fn parse_item_const(p: parser) -> item_info {
|
2011-07-27 12:19:39 +00:00
|
|
|
let id = parse_value_ident(p);
|
2011-07-27 07:13:00 +00:00
|
|
|
expect(p, token::COLON);
|
2011-08-15 19:06:10 +00:00
|
|
|
let ty = parse_ty(p, false);
|
2011-05-12 15:24:54 +00:00
|
|
|
expect(p, token::EQ);
|
2011-07-27 12:19:39 +00:00
|
|
|
let e = parse_expr(p);
|
2011-05-12 15:24:54 +00:00
|
|
|
expect(p, token::SEMI);
|
2012-05-08 14:07:32 +00:00
|
|
|
(id, item_const(ty, e), none)
|
2010-12-09 22:37:50 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 13:37:32 +00:00
|
|
|
fn parse_item_mod(p: parser) -> item_info {
|
2011-07-27 12:19:39 +00:00
|
|
|
let id = parse_ident(p);
|
2011-05-12 15:24:54 +00:00
|
|
|
expect(p, token::LBRACE);
|
2011-07-27 12:19:39 +00:00
|
|
|
let inner_attrs = parse_inner_attrs_and_next(p);
|
2012-05-08 13:37:32 +00:00
|
|
|
let m = parse_mod_items(p, token::RBRACE, inner_attrs.next);
|
2011-05-12 15:24:54 +00:00
|
|
|
expect(p, token::RBRACE);
|
2012-05-08 14:07:32 +00:00
|
|
|
(id, item_mod(m), some(inner_attrs.inner))
|
2010-09-23 20:15:51 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_item_native_fn(p: parser, +attrs: [attribute],
|
|
|
|
purity: purity) -> @native_item {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.last_span.lo;
|
2011-07-27 12:19:39 +00:00
|
|
|
let t = parse_fn_header(p);
|
2012-05-04 19:33:04 +00:00
|
|
|
let (decl, _) = parse_fn_decl(p, purity, parse_arg);
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut hi = p.span.hi;
|
2011-05-12 15:24:54 +00:00
|
|
|
expect(p, token::SEMI);
|
2011-07-27 12:19:39 +00:00
|
|
|
ret @{ident: t.ident,
|
|
|
|
attrs: attrs,
|
2012-05-08 14:07:32 +00:00
|
|
|
node: native_item_fn(decl, t.tps),
|
2011-07-27 12:19:39 +00:00
|
|
|
id: p.get_id(),
|
2012-04-23 11:04:46 +00:00
|
|
|
span: mk_sp(lo, hi)};
|
2011-02-04 16:10:04 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_fn_purity(p: parser) -> purity {
|
|
|
|
if eat_keyword(p, "fn") { impure_fn }
|
|
|
|
else if eat_keyword(p, "pure") { expect_keyword(p, "fn"); pure_fn }
|
2012-04-25 03:16:53 +00:00
|
|
|
else if eat_keyword(p, "unsafe") {
|
|
|
|
expect_keyword(p, "fn");
|
2012-05-08 14:07:32 +00:00
|
|
|
unsafe_fn
|
2012-04-25 03:16:53 +00:00
|
|
|
}
|
2012-03-20 14:05:14 +00:00
|
|
|
else { unexpected(p); }
|
2012-02-13 17:56:09 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_native_item(p: parser, +attrs: [attribute]) ->
|
|
|
|
@native_item {
|
2012-02-13 17:56:09 +00:00
|
|
|
parse_item_native_fn(p, attrs, parse_fn_purity(p))
|
2011-02-02 15:43:57 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_native_mod_items(p: parser, +first_item_attrs: [attribute]) ->
|
|
|
|
native_mod {
|
2011-07-27 12:48:34 +00:00
|
|
|
// Shouldn't be any view items since we've already parsed an item attr
|
2012-05-08 21:01:38 +00:00
|
|
|
let {attrs_remaining, view_items} =
|
|
|
|
parse_view(p, first_item_attrs, false);
|
2012-05-08 14:07:32 +00:00
|
|
|
let mut items: [@native_item] = [];
|
2012-05-08 21:01:38 +00:00
|
|
|
let mut initial_attrs = attrs_remaining;
|
2012-01-13 08:56:53 +00:00
|
|
|
while p.token != token::RBRACE {
|
2011-07-27 12:19:39 +00:00
|
|
|
let attrs = initial_attrs + parse_outer_attributes(p);
|
2011-08-19 22:16:48 +00:00
|
|
|
initial_attrs = [];
|
|
|
|
items += [parse_native_item(p, attrs)];
|
2011-07-05 19:38:53 +00:00
|
|
|
}
|
2011-11-20 18:15:40 +00:00
|
|
|
ret {view_items: view_items,
|
2011-07-27 12:19:39 +00:00
|
|
|
items: items};
|
|
|
|
}
|
|
|
|
|
2012-05-08 13:37:32 +00:00
|
|
|
fn parse_item_native_mod(p: parser) -> item_info {
|
2012-04-25 03:16:53 +00:00
|
|
|
expect_keyword(p, "mod");
|
2011-07-27 12:19:39 +00:00
|
|
|
let id = parse_ident(p);
|
2011-05-12 15:24:54 +00:00
|
|
|
expect(p, token::LBRACE);
|
2011-07-27 12:19:39 +00:00
|
|
|
let more_attrs = parse_inner_attrs_and_next(p);
|
2012-05-08 13:37:32 +00:00
|
|
|
let m = parse_native_mod_items(p, more_attrs.next);
|
2011-05-12 15:24:54 +00:00
|
|
|
expect(p, token::RBRACE);
|
2012-05-08 14:07:32 +00:00
|
|
|
(id, item_native_mod(m), some(more_attrs.inner))
|
2011-02-01 18:40:04 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_type_decl(p: parser) -> {lo: uint, ident: ident} {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.last_span.lo;
|
2011-07-27 12:19:39 +00:00
|
|
|
let id = parse_ident(p);
|
|
|
|
ret {lo: lo, ident: id};
|
2011-02-04 14:46:10 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 13:37:32 +00:00
|
|
|
fn parse_item_type(p: parser) -> item_info {
|
2011-07-27 12:19:39 +00:00
|
|
|
let t = parse_type_decl(p);
|
2012-04-19 04:26:25 +00:00
|
|
|
let rp = parse_region_param(p);
|
2011-11-18 11:39:20 +00:00
|
|
|
let tps = parse_ty_params(p);
|
2011-05-12 15:24:54 +00:00
|
|
|
expect(p, token::EQ);
|
2011-08-15 19:06:10 +00:00
|
|
|
let ty = parse_ty(p, false);
|
2011-05-12 15:24:54 +00:00
|
|
|
expect(p, token::SEMI);
|
2012-05-08 14:07:32 +00:00
|
|
|
(t.ident, item_ty(ty, tps, rp), none)
|
2012-04-19 04:26:25 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_region_param(p: parser) -> region_param {
|
2012-04-20 03:05:50 +00:00
|
|
|
if eat(p, token::BINOP(token::SLASH)) {
|
|
|
|
expect(p, token::BINOP(token::AND));
|
2012-05-08 14:07:32 +00:00
|
|
|
rp_self
|
2012-04-20 03:05:50 +00:00
|
|
|
} else {
|
2012-05-08 14:07:32 +00:00
|
|
|
rp_none
|
2012-04-20 03:05:50 +00:00
|
|
|
}
|
2010-11-20 00:34:47 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_item_enum(p: parser, default_vis: visibility) -> item_info {
|
2011-07-27 12:19:39 +00:00
|
|
|
let id = parse_ident(p);
|
2012-04-19 04:26:25 +00:00
|
|
|
let rp = parse_region_param(p);
|
2011-11-18 11:39:20 +00:00
|
|
|
let ty_params = parse_ty_params(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
let mut variants: [variant] = [];
|
2011-07-01 11:03:05 +00:00
|
|
|
// Newtype syntax
|
2012-01-13 08:56:53 +00:00
|
|
|
if p.token == token::EQ {
|
2012-04-27 22:44:40 +00:00
|
|
|
check_restricted_keywords_(p, id);
|
2011-07-01 11:03:05 +00:00
|
|
|
p.bump();
|
2011-08-15 19:06:10 +00:00
|
|
|
let ty = parse_ty(p, false);
|
2011-07-01 11:03:05 +00:00
|
|
|
expect(p, token::SEMI);
|
2011-07-27 12:19:39 +00:00
|
|
|
let variant =
|
|
|
|
spanned(ty.span.lo, ty.span.hi,
|
|
|
|
{name: id,
|
2012-01-26 00:23:43 +00:00
|
|
|
attrs: [],
|
2011-08-19 22:16:48 +00:00
|
|
|
args: [{ty: ty, id: p.get_id()}],
|
2012-01-10 21:50:40 +00:00
|
|
|
id: p.get_id(),
|
2012-05-08 14:06:24 +00:00
|
|
|
disr_expr: none,
|
2012-05-08 14:07:32 +00:00
|
|
|
vis: public});
|
|
|
|
ret (id, item_enum([variant], ty_params, rp), none);
|
2011-07-01 11:03:05 +00:00
|
|
|
}
|
2011-05-12 15:24:54 +00:00
|
|
|
expect(p, token::LBRACE);
|
2012-01-26 00:23:43 +00:00
|
|
|
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut all_nullary = true, have_disr = false;
|
2012-01-18 00:06:32 +00:00
|
|
|
|
2012-01-25 13:10:33 +00:00
|
|
|
while p.token != token::RBRACE {
|
2012-01-26 00:23:43 +00:00
|
|
|
let variant_attrs = parse_outer_attributes(p);
|
2012-01-25 13:10:33 +00:00
|
|
|
let vlo = p.span.lo;
|
2012-05-08 14:06:24 +00:00
|
|
|
let vis = parse_visibility(p, default_vis);
|
2012-01-25 13:10:33 +00:00
|
|
|
let ident = parse_value_ident(p);
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut args = [], disr_expr = none;
|
2012-01-25 13:10:33 +00:00
|
|
|
if p.token == token::LPAREN {
|
|
|
|
all_nullary = false;
|
|
|
|
let arg_tys = parse_seq(token::LPAREN, token::RPAREN,
|
|
|
|
seq_sep(token::COMMA),
|
|
|
|
{|p| parse_ty(p, false)}, p);
|
2012-04-06 18:01:43 +00:00
|
|
|
for arg_tys.node.each {|ty|
|
2012-01-25 13:10:33 +00:00
|
|
|
args += [{ty: ty, id: p.get_id()}];
|
2012-01-18 00:06:32 +00:00
|
|
|
}
|
2012-01-25 13:10:33 +00:00
|
|
|
} else if eat(p, token::EQ) {
|
|
|
|
have_disr = true;
|
|
|
|
disr_expr = some(parse_expr(p));
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-01-25 13:10:33 +00:00
|
|
|
|
2012-01-26 00:23:43 +00:00
|
|
|
let vr = {name: ident, attrs: variant_attrs,
|
|
|
|
args: args, id: p.get_id(),
|
2012-05-08 14:06:24 +00:00
|
|
|
disr_expr: disr_expr, vis: vis};
|
2012-01-25 13:10:33 +00:00
|
|
|
variants += [spanned(vlo, p.last_span.hi, vr)];
|
|
|
|
|
|
|
|
if !eat(p, token::COMMA) { break; }
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-01-25 13:10:33 +00:00
|
|
|
expect(p, token::RBRACE);
|
2012-01-10 21:50:40 +00:00
|
|
|
if (have_disr && !all_nullary) {
|
2012-01-11 01:33:26 +00:00
|
|
|
p.fatal("discriminator values can only be used with a c-like enum");
|
2012-01-10 21:50:40 +00:00
|
|
|
}
|
2012-05-08 14:07:32 +00:00
|
|
|
(id, item_enum(variants, ty_params, rp), none)
|
2010-11-24 19:36:35 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_fn_ty_proto(p: parser) -> proto {
|
2012-01-12 23:38:44 +00:00
|
|
|
alt p.token {
|
2012-01-19 06:37:22 +00:00
|
|
|
token::AT {
|
2012-01-12 19:39:23 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
proto_box
|
2012-01-12 19:39:23 +00:00
|
|
|
}
|
2012-01-19 06:37:22 +00:00
|
|
|
token::TILDE {
|
2012-01-10 14:49:15 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
proto_uniq
|
2012-01-12 19:39:23 +00:00
|
|
|
}
|
2012-01-19 06:37:22 +00:00
|
|
|
token::BINOP(token::AND) {
|
2012-01-12 19:39:23 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
proto_block
|
2012-01-12 19:39:23 +00:00
|
|
|
}
|
|
|
|
_ {
|
2012-05-08 14:07:32 +00:00
|
|
|
proto_any
|
2012-01-12 19:39:23 +00:00
|
|
|
}
|
2011-10-14 21:57:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-12 20:31:45 +00:00
|
|
|
fn fn_expr_lookahead(tok: token::token) -> bool {
|
|
|
|
alt tok {
|
2012-01-19 06:37:22 +00:00
|
|
|
token::LPAREN | token::AT | token::TILDE | token::BINOP(_) {
|
2012-01-12 20:31:45 +00:00
|
|
|
true
|
|
|
|
}
|
|
|
|
_ {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_item(p: parser, +attrs: [attribute], vis: visibility)
|
|
|
|
-> option<@item> {
|
2012-05-08 13:37:32 +00:00
|
|
|
let lo = p.span.lo;
|
|
|
|
let (ident, item_, extra_attrs) = if eat_keyword(p, "const") {
|
|
|
|
parse_item_const(p)
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if is_keyword(p, "fn") && !fn_expr_lookahead(p.look_ahead(1u)) {
|
2011-07-29 13:01:06 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
parse_item_fn(p, impure_fn)
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "pure") {
|
|
|
|
expect_keyword(p, "fn");
|
2012-05-08 14:07:32 +00:00
|
|
|
parse_item_fn(p, pure_fn)
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if is_keyword(p, "unsafe") && p.look_ahead(1u) != token::LBRACE {
|
2011-10-07 04:33:04 +00:00
|
|
|
p.bump();
|
2012-04-25 03:16:53 +00:00
|
|
|
expect_keyword(p, "fn");
|
2012-05-08 14:07:32 +00:00
|
|
|
parse_item_fn(p, unsafe_fn)
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "crust") {
|
|
|
|
expect_keyword(p, "fn");
|
2012-05-08 14:07:32 +00:00
|
|
|
parse_item_fn(p, crust_fn)
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "mod") {
|
2012-05-08 13:37:32 +00:00
|
|
|
parse_item_mod(p)
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "native") {
|
2012-05-08 13:37:32 +00:00
|
|
|
parse_item_native_mod(p)
|
|
|
|
} else if eat_keyword(p, "type") {
|
|
|
|
parse_item_type(p)
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "enum") {
|
2012-05-08 14:06:24 +00:00
|
|
|
parse_item_enum(p, vis)
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "iface") {
|
2012-05-08 13:37:32 +00:00
|
|
|
parse_item_iface(p)
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "impl") {
|
2012-05-08 13:37:32 +00:00
|
|
|
parse_item_impl(p)
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "resource") {
|
2012-05-08 13:37:32 +00:00
|
|
|
parse_item_res(p)
|
2012-04-25 03:16:53 +00:00
|
|
|
} else if eat_keyword(p, "class") {
|
2012-05-08 13:37:32 +00:00
|
|
|
parse_item_class(p)
|
|
|
|
} else { ret none; };
|
2012-05-08 14:06:24 +00:00
|
|
|
some(mk_item(p, lo, p.last_span.hi, ident, item_, vis,
|
|
|
|
alt extra_attrs {
|
|
|
|
some(as) { attrs + as }
|
|
|
|
none { attrs }
|
|
|
|
}))
|
2010-09-21 23:22:32 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_use(p: parser) -> view_item_ {
|
2011-07-27 12:19:39 +00:00
|
|
|
let ident = parse_ident(p);
|
|
|
|
let metadata = parse_optional_meta(p);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret view_item_use(ident, metadata, p.get_id());
|
2010-12-30 16:21:37 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_view_path(p: parser) -> @view_path {
|
2012-02-18 07:05:20 +00:00
|
|
|
let lo = p.span.lo;
|
|
|
|
let first_ident = parse_ident(p);
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut path = [first_ident];
|
2012-02-18 07:05:20 +00:00
|
|
|
#debug("parsed view_path: %s", first_ident);
|
|
|
|
alt p.token {
|
|
|
|
token::EQ {
|
|
|
|
// x = foo::bar
|
|
|
|
p.bump();
|
|
|
|
path = [parse_ident(p)];
|
|
|
|
while p.token == token::MOD_SEP {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
2012-02-18 07:05:20 +00:00
|
|
|
let id = parse_ident(p);
|
|
|
|
path += [id];
|
2011-01-28 16:54:59 +00:00
|
|
|
}
|
2012-04-23 11:04:46 +00:00
|
|
|
let path = @{span: mk_sp(lo, p.span.hi), global: false,
|
2012-04-24 22:52:52 +00:00
|
|
|
idents: path, rp: none, types: []};
|
2012-04-23 11:04:46 +00:00
|
|
|
ret @spanned(lo, p.span.hi,
|
2012-05-08 14:07:32 +00:00
|
|
|
view_path_simple(first_ident, path, p.get_id()));
|
2012-02-18 07:05:20 +00:00
|
|
|
}
|
2011-09-12 10:39:38 +00:00
|
|
|
|
2012-02-18 07:05:20 +00:00
|
|
|
token::MOD_SEP {
|
|
|
|
// foo::bar or foo::{a,b,c} or foo::*
|
|
|
|
while p.token == token::MOD_SEP {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
2011-08-16 22:21:30 +00:00
|
|
|
|
2012-02-18 07:05:20 +00:00
|
|
|
alt p.token {
|
2011-08-19 22:16:48 +00:00
|
|
|
|
2012-02-18 07:05:20 +00:00
|
|
|
token::IDENT(i, _) {
|
|
|
|
p.bump();
|
|
|
|
path += [p.get_str(i)];
|
|
|
|
}
|
2011-09-02 22:34:58 +00:00
|
|
|
|
2012-02-18 07:05:20 +00:00
|
|
|
// foo::bar::{a,b,c}
|
|
|
|
token::LBRACE {
|
|
|
|
let idents =
|
|
|
|
parse_seq(token::LBRACE, token::RBRACE,
|
|
|
|
seq_sep(token::COMMA),
|
|
|
|
parse_path_list_ident, p).node;
|
2012-04-23 11:04:46 +00:00
|
|
|
let path = @{span: mk_sp(lo, p.span.hi),
|
2012-04-24 22:52:52 +00:00
|
|
|
global: false, idents: path,
|
|
|
|
rp: none, types: []};
|
2012-04-23 11:04:46 +00:00
|
|
|
ret @spanned(lo, p.span.hi,
|
2012-05-08 14:07:32 +00:00
|
|
|
view_path_list(path, idents, p.get_id()));
|
2012-02-18 07:05:20 +00:00
|
|
|
}
|
2011-09-12 09:27:30 +00:00
|
|
|
|
2012-02-18 07:05:20 +00:00
|
|
|
// foo::bar::*
|
|
|
|
token::BINOP(token::STAR) {
|
|
|
|
p.bump();
|
2012-04-23 11:04:46 +00:00
|
|
|
let path = @{span: mk_sp(lo, p.span.hi),
|
2012-04-24 22:52:52 +00:00
|
|
|
global: false, idents: path,
|
|
|
|
rp: none, types: []};
|
2012-04-23 11:04:46 +00:00
|
|
|
ret @spanned(lo, p.span.hi,
|
2012-05-08 14:07:32 +00:00
|
|
|
view_path_glob(path, p.get_id()));
|
2012-02-18 07:05:20 +00:00
|
|
|
}
|
2011-09-12 10:39:38 +00:00
|
|
|
|
2012-02-18 07:05:20 +00:00
|
|
|
_ { break; }
|
2011-08-16 22:21:30 +00:00
|
|
|
}
|
2011-01-28 16:54:59 +00:00
|
|
|
}
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-02-18 07:05:20 +00:00
|
|
|
_ { }
|
2011-01-28 16:54:59 +00:00
|
|
|
}
|
2012-02-18 07:05:20 +00:00
|
|
|
let last = path[vec::len(path) - 1u];
|
2012-04-23 11:04:46 +00:00
|
|
|
let path = @{span: mk_sp(lo, p.span.hi), global: false,
|
2012-04-24 22:52:52 +00:00
|
|
|
idents: path, rp: none, types: []};
|
2012-04-23 11:04:46 +00:00
|
|
|
ret @spanned(lo, p.span.hi,
|
2012-05-08 14:07:32 +00:00
|
|
|
view_path_simple(last, path, p.get_id()));
|
2010-12-25 04:25:02 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_view_paths(p: parser) -> [@view_path] {
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut vp = [parse_view_path(p)];
|
2012-02-18 07:05:20 +00:00
|
|
|
while p.token == token::COMMA {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
2012-02-18 07:05:20 +00:00
|
|
|
vp += [parse_view_path(p)];
|
2012-01-21 03:44:38 +00:00
|
|
|
}
|
2012-02-18 07:05:20 +00:00
|
|
|
ret vp;
|
2011-03-02 21:50:42 +00:00
|
|
|
}
|
|
|
|
|
2011-09-12 09:27:30 +00:00
|
|
|
fn is_view_item(p: parser) -> bool {
|
2012-05-08 21:01:38 +00:00
|
|
|
let tok = if !is_keyword(p, "pub") && !is_keyword(p, "priv") { p.token }
|
|
|
|
else { p.look_ahead(1u) };
|
|
|
|
token_is_keyword(p, "use", tok) || token_is_keyword(p, "import", tok) ||
|
|
|
|
token_is_keyword(p, "export", tok)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_view_item(p: parser, +attrs: [attribute]) -> @view_item {
|
|
|
|
let lo = p.span.lo, vis = parse_visibility(p, private);
|
|
|
|
let node = if eat_keyword(p, "use") {
|
|
|
|
parse_use(p)
|
|
|
|
} else if eat_keyword(p, "import") {
|
|
|
|
view_item_import(parse_view_paths(p))
|
|
|
|
} else if eat_keyword(p, "export") {
|
|
|
|
view_item_export(parse_view_paths(p))
|
|
|
|
} else { fail; };
|
|
|
|
expect(p, token::SEMI);
|
|
|
|
@{node: node, attrs: attrs,
|
|
|
|
vis: vis, span: mk_sp(lo, p.last_span.hi)}
|
2012-01-16 00:25:31 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 21:01:38 +00:00
|
|
|
fn parse_view(p: parser, +first_item_attrs: [attribute],
|
|
|
|
only_imports: bool) -> {attrs_remaining: [attribute],
|
|
|
|
view_items: [@view_item]} {
|
|
|
|
let mut attrs = first_item_attrs + parse_outer_attributes(p);
|
|
|
|
let mut items = [];
|
|
|
|
while if only_imports { is_keyword(p, "import") }
|
|
|
|
else { is_view_item(p) } {
|
|
|
|
items += [parse_view_item(p, attrs)];
|
|
|
|
attrs = parse_outer_attributes(p);
|
2012-01-16 01:23:59 +00:00
|
|
|
}
|
2012-05-08 21:01:38 +00:00
|
|
|
{attrs_remaining: attrs, view_items: items}
|
2011-03-07 19:48:43 +00:00
|
|
|
}
|
|
|
|
|
2011-07-12 00:21:02 +00:00
|
|
|
// Parses a source module as a crate
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_crate_mod(p: parser, _cfg: crate_cfg) -> @crate {
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2011-07-27 12:19:39 +00:00
|
|
|
let crate_attrs = parse_inner_attrs_and_next(p);
|
|
|
|
let first_item_outer_attrs = crate_attrs.next;
|
|
|
|
let m = parse_mod_items(p, token::EOF, first_item_outer_attrs);
|
2012-01-13 08:56:53 +00:00
|
|
|
ret @spanned(lo, p.span.lo,
|
2011-08-19 22:16:48 +00:00
|
|
|
{directives: [],
|
2011-07-27 12:19:39 +00:00
|
|
|
module: m,
|
|
|
|
attrs: crate_attrs.inner,
|
2012-01-13 08:56:53 +00:00
|
|
|
config: p.cfg});
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
|
|
|
|
2011-09-12 09:27:30 +00:00
|
|
|
fn parse_str(p: parser) -> str {
|
2012-01-13 08:56:53 +00:00
|
|
|
alt p.token {
|
2011-10-20 01:04:44 +00:00
|
|
|
token::LIT_STR(s) { p.bump(); p.get_str(s) }
|
|
|
|
_ {
|
|
|
|
p.fatal("expected string literal")
|
|
|
|
}
|
2011-06-23 22:42:55 +00:00
|
|
|
}
|
|
|
|
}
|
2011-06-15 18:19:50 +00:00
|
|
|
|
2011-01-11 02:18:16 +00:00
|
|
|
// Logic for parsing crate files (.rc)
|
|
|
|
//
|
|
|
|
// Each crate file is a sequence of directives.
|
|
|
|
//
|
|
|
|
// Each directive imperatively extends its environment with 0 or more items.
|
2012-05-08 14:07:32 +00:00
|
|
|
fn parse_crate_directive(p: parser, first_outer_attr: [attribute]) ->
|
|
|
|
crate_directive {
|
2011-06-29 01:15:39 +00:00
|
|
|
|
|
|
|
// Collect the next attributes
|
2011-07-27 12:19:39 +00:00
|
|
|
let outer_attrs = first_outer_attr + parse_outer_attributes(p);
|
2011-06-29 01:15:39 +00:00
|
|
|
// In a crate file outer attributes are only going to apply to mods
|
2011-08-15 23:38:23 +00:00
|
|
|
let expect_mod = vec::len(outer_attrs) > 0u;
|
2011-06-29 01:15:39 +00:00
|
|
|
|
2012-01-13 08:56:53 +00:00
|
|
|
let lo = p.span.lo;
|
2012-04-25 03:16:53 +00:00
|
|
|
if expect_mod || is_keyword(p, "mod") {
|
|
|
|
expect_keyword(p, "mod");
|
2011-07-27 12:19:39 +00:00
|
|
|
let id = parse_ident(p);
|
2012-01-13 08:56:53 +00:00
|
|
|
alt p.token {
|
2011-07-27 12:19:39 +00:00
|
|
|
// mod x = "foo.rs";
|
2012-01-19 06:37:22 +00:00
|
|
|
token::SEMI {
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut hi = p.span.hi;
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
2012-05-08 14:07:32 +00:00
|
|
|
ret spanned(lo, hi, cdir_src_mod(id, outer_attrs));
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
|
|
|
// mod x = "foo_dir" { ...directives... }
|
2012-01-19 06:37:22 +00:00
|
|
|
token::LBRACE {
|
2011-07-27 12:19:39 +00:00
|
|
|
p.bump();
|
|
|
|
let inner_attrs = parse_inner_attrs_and_next(p);
|
|
|
|
let mod_attrs = outer_attrs + inner_attrs.inner;
|
|
|
|
let next_outer_attr = inner_attrs.next;
|
|
|
|
let cdirs =
|
|
|
|
parse_crate_directives(p, token::RBRACE, next_outer_attr);
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut hi = p.span.hi;
|
2011-07-27 12:19:39 +00:00
|
|
|
expect(p, token::RBRACE);
|
|
|
|
ret spanned(lo, hi,
|
2012-05-08 14:07:32 +00:00
|
|
|
cdir_dir_mod(id, cdirs, mod_attrs));
|
2011-07-27 12:19:39 +00:00
|
|
|
}
|
2012-03-20 14:05:14 +00:00
|
|
|
_ { unexpected(p); }
|
2011-02-25 01:00:24 +00:00
|
|
|
}
|
2011-08-19 22:16:48 +00:00
|
|
|
} else if is_view_item(p) {
|
2012-05-08 21:01:38 +00:00
|
|
|
let vi = parse_view_item(p, outer_attrs);
|
2012-05-08 14:07:32 +00:00
|
|
|
ret spanned(lo, vi.span.hi, cdir_view_item(vi));
|
2011-09-02 22:34:58 +00:00
|
|
|
} else { ret p.fatal("expected crate directive"); }
|
2011-01-11 02:18:16 +00:00
|
|
|
}
|
|
|
|
|
2011-09-12 09:27:30 +00:00
|
|
|
fn parse_crate_directives(p: parser, term: token::token,
|
2012-05-08 14:07:32 +00:00
|
|
|
first_outer_attr: [attribute]) ->
|
|
|
|
[@crate_directive] {
|
2011-06-29 01:15:39 +00:00
|
|
|
|
|
|
|
// This is pretty ugly. If we have an outer attribute then we can't accept
|
|
|
|
// seeing the terminator next, so if we do see it then fail the same way
|
|
|
|
// parse_crate_directive would
|
2012-01-13 08:56:53 +00:00
|
|
|
if vec::len(first_outer_attr) > 0u && p.token == term {
|
2012-04-25 03:16:53 +00:00
|
|
|
expect_keyword(p, "mod");
|
2011-06-29 01:15:39 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:07:32 +00:00
|
|
|
let mut cdirs: [@crate_directive] = [];
|
2012-03-15 13:47:03 +00:00
|
|
|
let mut first_outer_attr = first_outer_attr;
|
2012-01-13 08:56:53 +00:00
|
|
|
while p.token != term {
|
2011-07-27 12:19:39 +00:00
|
|
|
let cdir = @parse_crate_directive(p, first_outer_attr);
|
2011-08-19 22:16:48 +00:00
|
|
|
cdirs += [cdir];
|
2011-11-25 00:17:26 +00:00
|
|
|
first_outer_attr = [];
|
2011-01-11 02:18:16 +00:00
|
|
|
}
|
2011-02-24 20:14:05 +00:00
|
|
|
ret cdirs;
|
2011-01-11 02:18:16 +00:00
|
|
|
}
|
|
|
|
|
2010-08-12 17:29:23 +00:00
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// End:
|
|
|
|
//
|