mirror of
https://github.com/fluencelabs/lalrpop
synced 2025-04-27 04:02:13 +00:00
add LALRPOP grammar written in itself; generates quite a lot of output
though -- probably need to shift to a less naive LR(1) generation algorithm
This commit is contained in:
parent
bd006f8c27
commit
3c67e3c8c5
328
lalrpop/src/newparser.lalrpop
Normal file
328
lalrpop/src/newparser.lalrpop
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
use intern::{intern, InternedString};
|
||||||
|
use grammar::parse_tree::*;
|
||||||
|
use grammar::pattern::*;
|
||||||
|
use std::iter::once;
|
||||||
|
use tok::{self, Tok};
|
||||||
|
|
||||||
|
grammar<'input>(text: &'input str);
|
||||||
|
|
||||||
|
pub Grammar: Grammar =
|
||||||
|
<uses:Use*> <lo:@L> "grammar" <hi:@R>
|
||||||
|
<tps:GrammarTypeParameters?>
|
||||||
|
<parameters:GrammarParameters?>
|
||||||
|
<where_clauses:"where"?>
|
||||||
|
";"
|
||||||
|
<items:GrammarItem*> => {
|
||||||
|
Grammar { span: Span(lo, hi),
|
||||||
|
type_parameters: tps.unwrap_or(vec![]),
|
||||||
|
parameters: parameters.unwrap_or(vec![]),
|
||||||
|
where_clauses: where_clauses.unwrap_or(vec![]),
|
||||||
|
items: uses.into_iter().chain(i).collect() }
|
||||||
|
};
|
||||||
|
|
||||||
|
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(u);
|
||||||
|
|
||||||
|
Nonterminal: GrammarItem =
|
||||||
|
<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,
|
||||||
|
args: n.1,
|
||||||
|
type_decl: t,
|
||||||
|
alternatives: a })
|
||||||
|
};
|
||||||
|
|
||||||
|
NonterminalName: (NonterminalString, Vec<NonterminalString>) = {
|
||||||
|
<MacroId> "<" <Comma<NonterminalId>> ">";
|
||||||
|
<NonterminalId>;
|
||||||
|
<"Escape"> => (NonterminalString(intern(<>)), vec![]);
|
||||||
|
};
|
||||||
|
|
||||||
|
Alternatives: Vec<Alternative> = {
|
||||||
|
<a:Alternative> => vec![a];
|
||||||
|
"{" <Alternative*> "}" ";";
|
||||||
|
};
|
||||||
|
|
||||||
|
Alternative: Alternative =
|
||||||
|
<lo:@L> <s:Symbol*> <c:("if" <Cond>)?> <a:Action?> ";" <hi:@R> => {
|
||||||
|
Alternative {
|
||||||
|
span: Span(lo, hi),
|
||||||
|
expr: s,
|
||||||
|
condition: c,
|
||||||
|
action: a
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Action: ActionKind = {
|
||||||
|
"=>@L" => ActionKind::Lookahead;
|
||||||
|
"=>@R" => ActionKind::Lookbehind;
|
||||||
|
<c:"=>"> => ActionKind::Code(c.to_string());
|
||||||
|
<c:"=>?"> => ActionKind::Fallible(c.to_string());
|
||||||
|
};
|
||||||
|
|
||||||
|
Cond: Condition =
|
||||||
|
<lo:@L> <a:NonterminalId> <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;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 });
|
||||||
|
|
||||||
|
Terminal =>
|
||||||
|
SymbolKind::Terminal(<>);
|
||||||
|
|
||||||
|
NonterminalId =>
|
||||||
|
SymbolKind::Nonterminal(<>);
|
||||||
|
|
||||||
|
Escape =>
|
||||||
|
SymbolKind::Nonterminal(NonterminalString(<>));
|
||||||
|
|
||||||
|
"(" <Symbol*> ")" =>
|
||||||
|
SymbolKind::Expr(<>);
|
||||||
|
|
||||||
|
"@L" =>
|
||||||
|
SymbolKind::Lookahead;
|
||||||
|
|
||||||
|
"@R" =>
|
||||||
|
SymbolKind::Lookbehind;
|
||||||
|
};
|
||||||
|
|
||||||
|
TypeRef: TypeRef = {
|
||||||
|
"(" <Comma<TypeRef>> ")" =>
|
||||||
|
TypeRef::Tuple(<>);
|
||||||
|
|
||||||
|
<e:Escape> =>? {
|
||||||
|
panic!("parse escape symbol")
|
||||||
|
};
|
||||||
|
|
||||||
|
"&" <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 => TypeRef1::Lifetime(<>);
|
||||||
|
};
|
||||||
|
|
||||||
|
Path: Path =
|
||||||
|
<a:"::"?> <h:(<Id> "::")*> <t:Id> => {
|
||||||
|
Path { absolute: a.is_some(),
|
||||||
|
ids: h.into_iter().chain(once(t)).collect() }
|
||||||
|
};
|
||||||
|
|
||||||
|
ExternToken: GrammarItem =
|
||||||
|
<lo0:@L> "extern" "token" <hi0:@R> "{"
|
||||||
|
<a0:AssociatedType*>
|
||||||
|
"enum" <lo:@L> <t:TypeRef> <hi:@R> "{"
|
||||||
|
<c:Comma<Conversion>>
|
||||||
|
"}"
|
||||||
|
<a1:AssociatedType*>
|
||||||
|
"}" => {
|
||||||
|
GrammarItem::ExternToken(ExternToken {
|
||||||
|
span: Span(lo0, hi0),
|
||||||
|
associated_types: a0.into_iter().chain(a1).collect(),
|
||||||
|
enum_token: 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> <p:"=>"> <hi:@R> =>? {
|
||||||
|
let pattern = try!(parse_pattern(p));
|
||||||
|
Conversion { span: Span(lo, hi), from: from, to: pattern }
|
||||||
|
};
|
||||||
|
|
||||||
|
pub Pattern: Pattern =
|
||||||
|
<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<TypeRef>> ")" =>
|
||||||
|
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));
|
||||||
|
|
||||||
|
NonterminalId: NonterminalString =
|
||||||
|
<i:Id> => NonterminalString(i);
|
||||||
|
|
||||||
|
Id: InternedString =
|
||||||
|
<i:"Id"> => intern(i);
|
||||||
|
|
||||||
|
Escape: InternedString =
|
||||||
|
<i:"Escape"> => intern(i);
|
||||||
|
|
||||||
|
Lifetime: InternedString =
|
||||||
|
<i:"Lifetime"> => intern(i);
|
||||||
|
|
||||||
|
Terminal: TerminalString =
|
||||||
|
<s:StringLiteral> => TerminalString(s);
|
||||||
|
|
||||||
|
StringLiteral: InternedString =
|
||||||
|
<s:"StringLiteral"> => intern(s);
|
||||||
|
|
||||||
|
Comma<E>: Vec<E> =
|
||||||
|
<v0:(<E> ",")*> <e1:E?> =>
|
||||||
|
v0.into_iter().chain(e1).collect();
|
||||||
|
|
||||||
|
extern token {
|
||||||
|
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(..),
|
||||||
|
"token" => Tok::Token(..),
|
||||||
|
"type" => Tok::Type(..),
|
||||||
|
"use" => Tok::Use(..),
|
||||||
|
"where" => Tok::Where(..),
|
||||||
|
|
||||||
|
"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>),
|
||||||
|
|
||||||
|
"&" => 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::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(..),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user