use intern::{intern, InternedString};
use grammar::parse_tree::*;
use grammar::pattern::*;
use std::iter::once;
use tok::{self, Tok};
use util::strip;
#[LALR]
grammar<'input>(text: &'input str);
pub Grammar: Grammar =
<uses:Use*>
<annotations:Annotation*>
<lo:@L> "grammar" <hi:@R>
<tps:GrammarTypeParameters?>
<parameters:GrammarParameters?>
<where_clauses:"where"?>
";"
<items:GrammarItem*> => {
let where_clauses =
where_clauses.iter()
.flat_map(|wc| wc.iter())
.map(|s| strip(s))
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect();
Grammar { prefix: format!("__"), // adjusted by `parse_grammar`
span: Span(lo, hi),
type_parameters: tps.unwrap_or(vec![]),
parameters: parameters.unwrap_or(vec![]),
where_clauses: where_clauses,
items: uses.into_iter().chain(items).collect(),
annotations: annotations }
};
GrammarTypeParameters: Vec<TypeParameter> =
"<" <Comma<TypeParameter>> ">";
TypeParameter: TypeParameter = {
<l:Lifetime> => TypeParameter::Lifetime(l),
<l:Id> => TypeParameter::Id(l)
};
GrammarParameters: Vec<Parameter> =
"(" <Comma<GrammarParameter>> ")";
GrammarParameter: Parameter =
<id:Id> ":" <ty:TypeRef> => Parameter { name: id, ty: ty };
GrammarItem: GrammarItem = {
Use,
ExternToken,
Nonterminal
};
Use: GrammarItem =
<u:"use"> ";" => GrammarItem::Use(strip(u).to_string());
Nonterminal: GrammarItem =
<annotations:Annotation*>
<p:"pub"?> <lo:@L> <n:NonterminalName> <hi:@R>
<t:(":" <TypeRef>)?> "=" <a:Alternatives> => {
GrammarItem::Nonterminal(NonterminalData { public: p.is_some(),
span: Span(lo, hi),
name: n.0,
annotations: annotations,
args: n.1,
type_decl: t,
alternatives: a })
};
Annotation: Annotation =
"#" "[" <lo:@L> <id:Id> <hi:@R> "]" => {
Annotation { id_span: Span(lo, hi), id: id }
};
NonterminalName: (NonterminalString, Vec<NonterminalString>) = {
<MacroId> "<" <Comma<NotMacroId>> ">",
<n:NotMacroId> => (n, vec![]),
<"Escape"> => (NonterminalString(intern(<>)), vec![]),
};
Alternatives: Vec<Alternative> = {
<a:Alternative> ";" => vec![a],
"{" <Comma<Alternative>> "}" ";",
};
Alternative: Alternative = {
<lo:@L> <s:Symbol+> <c:("if" <Cond>)?> <a:Action?> <hi:@R> => {
Alternative {
span: Span(lo, hi),
expr: ExprSymbol { symbols: s },
condition: c,
action: a
}
},
<lo:@L> <c:("if" <Cond>)?> <a:Action> <hi:@R> => {
Alternative {
span: Span(lo, hi),
expr: ExprSymbol { symbols: vec![] },
condition: c,
action: Some(a)
}
},
};
Action: ActionKind = {
"=>@L" => ActionKind::Lookahead,
"=>@R" => ActionKind::Lookbehind,
<c:"=>"> => ActionKind::User(strip(c).to_string()),
<c:"=>?"> => ActionKind::Fallible(strip(c).to_string()),
};
Cond: Condition =
<lo:@L> <a:NotMacroId> <op:CondOp> <b:StringLiteral> <hi:@R> => {
Condition { span:Span(lo, hi), lhs:a, rhs:b, op:op }
};
CondOp: ConditionOp = {
"==" => ConditionOp::Equals,
"!=" => ConditionOp::NotEquals,
"~~" => ConditionOp::Match,
"!~" => ConditionOp::NotMatch,
};
ExprSymbol: ExprSymbol =
Symbol* => ExprSymbol { symbols: <> };
Symbol: Symbol = {
<lo:@L> "<" @L <l:Id> ":" <s:Symbol0> ">" <hi:@R> =>
Symbol::new(Span(lo, hi), SymbolKind::Name(l, Box::new(s))),
<lo:@L> "<" <s:Symbol0> ">" <hi:@R> =>
Symbol::new(Span(lo, hi), SymbolKind::Choose(Box::new(s))),
Symbol0,
};
Symbol0: Symbol = {
Symbol1,
<lhs:Symbol0> <op:RepeatOp> <hi:@R> =>
Symbol::new(Span(lhs.span.0, hi),
SymbolKind::Repeat(Box::new(RepeatSymbol { symbol: lhs, op: op }))),
};
RepeatOp: RepeatOp = {
"+" => RepeatOp::Plus,
"*" => RepeatOp::Star,
"?" => RepeatOp::Question,
};
Symbol1: Symbol =
<lo:@L> <sk:SymbolKind1> <hi:@R> => Symbol::new(Span(lo, hi), sk);
SymbolKind1: SymbolKind = {
<name:MacroId> "<" <args:Comma<Symbol>> ">" =>
SymbolKind::Macro(MacroSymbol { name: name, args: args }),
QuotedTerminal =>
SymbolKind::Terminal(<>),
"Id" =>
SymbolKind::AmbiguousId(intern(<>)),
Escape =>
SymbolKind::Nonterminal(NonterminalString(<>)),
"(" <ExprSymbol> ")" =>
SymbolKind::Expr(<>),
"@L" =>
SymbolKind::Lookahead,
"@R" =>
SymbolKind::Lookbehind,
"!" =>
SymbolKind::Error,
};
pub TypeRef: TypeRef = {
"(" <Comma<TypeRef>> ")" =>
TypeRef::Tuple(<>),
"#" <Symbol> "#" => {
TypeRef::OfSymbol(<>.kind)
},
"&" <l:Lifetime?> <m:"mut"?> <t:TypeRef> =>
TypeRef::Ref { lifetime: l,
mutable: m.is_some(),
referent: Box::new(t) },
<p:Path> "<" <a:Comma<TypeRefOrLifetime>> ">" =>
TypeRef::Nominal { path: p, types: a },
<p:Path> =>
match p.as_id() {
Some(id) => TypeRef::Id(id),
None => TypeRef::Nominal { path: p, types: vec![] }
},
};
TypeRefOrLifetime: TypeRef = {
TypeRef,
Lifetime => TypeRef::Lifetime(<>),
};
Path: Path =
<a:"::"?> <h:(<Id> "::")*> <t:Id> => {
Path { absolute: a.is_some(),
ids: h.into_iter().chain(once(t)).collect() }
};
ExternToken: GrammarItem = {
<lo:@L> "extern" <hi:@R> "{" <a0:AssociatedType*> <et:EnumToken> <a1:AssociatedType*> "}" => {
GrammarItem::ExternToken(ExternToken {
span: Span(lo, hi),
associated_types: a0.into_iter().chain(a1).collect(),
enum_token: Some(et),
})
},
<lo:@L> "extern" <hi:@R> "{" <a0:AssociatedType*> "}" => {
GrammarItem::ExternToken(ExternToken {
span: Span(lo, hi),
associated_types: a0,
enum_token: None,
})
},
};
EnumToken: EnumToken =
"enum" <lo:@L> <t:TypeRef> <hi:@R> "{"
<c:Comma<Conversion>>
"}" => {
EnumToken {
type_name: t,
type_span: Span(lo, hi),
conversions: c,
}
};
AssociatedType: AssociatedType =
"type" <lo:@L> <n:Id> <hi:@R> "=" <t:TypeRef> ";" => {
AssociatedType { type_span: Span(lo, hi),
type_name: n,
type_ref: t }
};
Conversion: Conversion =
<lo:@L> <from:Terminal> <start:@L> <p:"=>"> <hi:@R> =>? {
let pattern = try!(super::parse_pattern(p, start + 2));
Ok(Conversion { span: Span(lo, hi),
from: from,
to: pattern })
};
pub Pattern: Pattern<TypeRef> =
<lo:@L> <k:PatternKind> <hi:@R> => Pattern { span: Span(lo, hi), kind: k };
PatternKind: PatternKind<TypeRef> = {
<Path> "(" <Comma<Pattern>> ")" =>
PatternKind::Enum(<>),
<p:Path> "{" <a0:(<FieldPattern> ",")*> <a1:FieldPattern?> "}" =>
PatternKind::Struct(p, a0.into_iter().chain(a1).collect(), false),
<p:Path> "{" <a0:(<FieldPattern> ",")*> ".." "}" =>
PatternKind::Struct(p, a0, true),
"_" =>
PatternKind::Underscore,
".." =>
PatternKind::DotDot,
"<" <TypeRef> ">" =>
PatternKind::Choose(<>),
"(" <Comma<Pattern>> ")" =>
PatternKind::Tuple(<>),
<Path> =>
PatternKind::Path(<>),
};
FieldPattern: FieldPattern<TypeRef> =
<lo:@L> <id:Id> <hi:@R> ":" <pat:Pattern> => {
FieldPattern { field_span: Span(lo, hi),
field_name: id,
pattern: pat }
};
MacroId: NonterminalString =
<i:"MacroId"> => NonterminalString(intern(i));
NotMacroId: NonterminalString =
<i:"Id"> => NonterminalString(intern(i));
Id: InternedString = {
<i:"Id"> => intern(i),
<i:"MacroId"> => intern(i),
};
Escape: InternedString =
<i:"Escape"> => intern(i);
Lifetime: InternedString =
<i:"Lifetime"> => intern(i);
Terminal: TerminalString = {
QuotedTerminal,
<i:"Id"> => TerminalString::Bare(intern(i)),
};
QuotedTerminal: TerminalString = {
<s:StringLiteral> => TerminalString::quoted(s),
<s:RegexLiteral> => TerminalString::regex(s),
};
StringLiteral: InternedString =
<s:"StringLiteral"> => intern(s);
RegexLiteral: InternedString =
<s:"RegexLiteral"> => intern(s);
Comma<E>: Vec<E> =
<v0:(<E> ",")*> <e1:E?> =>
v0.into_iter().chain(e1).collect();
extern {
type Location = usize;
type Error = tok::Error;
enum Tok<'input> {
"enum" => Tok::Enum,
"extern" => Tok::Extern,
"grammar" => Tok::Grammar,
"if" => Tok::If,
"mut" => Tok::Mut,
"pub" => Tok::Pub,
"type" => Tok::Type,
"!" => Tok::Bang,
"use" => Tok::Use(<&'input str>),
"where" => Tok::Where(<Vec<&'input str>>),
"Escape" => Tok::Escape(<&'input str>),
"Id" => Tok::Id(<&'input str>),
"MacroId" => Tok::MacroId(<&'input str>),
"Lifetime" => Tok::Lifetime(<&'input str>),
"StringLiteral" => Tok::StringLiteral(<&'input str>),
"RegexLiteral" => Tok::RegexLiteral(<&'input str>),
"&" => Tok::Ampersand,
"!=" => Tok::BangEquals,
"!~" => Tok::BangTilde,
":" => Tok::Colon,
"::" => Tok::ColonColon,
"," => Tok::Comma,
".." => Tok::DotDot,
"=" => Tok::Equals,
"==" => Tok::EqualsEquals,
"=>" => Tok::EqualsGreaterThanCode(<&'input str>),
"=>?" => Tok::EqualsGreaterThanQuestionCode(<&'input str>),
"=>@L" => Tok::EqualsGreaterThanLookahead,
"=>@R" => Tok::EqualsGreaterThanLookbehind,
">" => Tok::GreaterThan,
"#" => Tok::Hash,
"{" => Tok::LeftBrace,
"[" => Tok::LeftBracket,
"(" => Tok::LeftParen,
"<" => Tok::LessThan,
"@L" => Tok::Lookahead,
"@R" => Tok::Lookbehind,
"+" => Tok::Plus,
"?" => Tok::Question,
"}" => Tok::RightBrace,
"]" => Tok::RightBracket,
")" => Tok::RightParen,
";" => Tok::Semi,
"*" => Tok::Star,
"~~" => Tok::TildeTilde,
"_" => Tok::Underscore,
}
}