mirror of
https://github.com/fluencelabs/lalrpop
synced 2025-03-16 17:00:53 +00:00
various annoying things to get macros working
This commit is contained in:
parent
bfe72e14fc
commit
a1da099572
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,7 @@ extern token {
|
||||
"+" => Tok::Plus(..),
|
||||
"*" => Tok::Times(..),
|
||||
"/" => Tok::Div(..),
|
||||
"," => Tok::Comma(..),
|
||||
"Num" => Tok::Num(<i32>)
|
||||
}
|
||||
}
|
||||
@ -21,9 +22,15 @@ pub Expr: &'ast Node<'ast> = {
|
||||
Factor;
|
||||
};
|
||||
|
||||
Comma<T>: Vec<T> = {
|
||||
<h:(<T> ",")*> <t:T?> =>
|
||||
h.into_iter().chain(t).collect();
|
||||
};
|
||||
|
||||
Factor = {
|
||||
<l:Factor> "*" <r:Term> => arena.alloc(Node::Binary(Op::Mul, l, r));
|
||||
<l:Factor> "/" <r:Term> => arena.alloc(Node::Binary(Op::Div, l, r));
|
||||
"*" "(" <Comma<Expr>> ")" => arena.alloc(Node::Reduce(Op::Mul, <>));
|
||||
Term;
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@ pub enum Op {
|
||||
pub enum Node<'ast> {
|
||||
Value(i32),
|
||||
Binary(Op, &'ast Node<'ast>, &'ast Node<'ast>),
|
||||
Reduce(Op, Vec<&'ast Node<'ast>>),
|
||||
}
|
||||
|
||||
pub struct Arena<'ast> {
|
||||
|
@ -4,10 +4,6 @@ mod expr_arena_ast;
|
||||
mod sub;
|
||||
mod util;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expr_test1() {
|
||||
util::test(|v| expr::parse_Expr(1, v), "22 - 3", 22 - 3);
|
||||
@ -51,7 +47,7 @@ fn sub_test3() {
|
||||
#[test]
|
||||
fn expr_arena_test1() {
|
||||
use expr_arena_ast::*;
|
||||
let mut arena = Arena::new();
|
||||
let arena = Arena::new();
|
||||
let expected =
|
||||
arena.alloc(Node::Binary(Op::Sub,
|
||||
arena.alloc(Node::Binary(Op::Mul,
|
||||
@ -61,3 +57,16 @@ fn expr_arena_test1() {
|
||||
util::test(|v| expr_arena::parse_Expr(&arena, v), "22 * 3 - 6", expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expr_arena_test2() {
|
||||
use expr_arena_ast::*;
|
||||
let arena = Arena::new();
|
||||
let expected =
|
||||
arena.alloc(Node::Reduce(Op::Mul,
|
||||
vec![arena.alloc(Node::Value(22)),
|
||||
arena.alloc(Node::Value(3)),
|
||||
arena.alloc(Node::Value(6))]));;
|
||||
util::test(|v| expr_arena::parse_Expr(&arena, v), "*(22, 3, 6)", expected);
|
||||
util::test(|v| expr_arena::parse_Expr(&arena, v), "*(22, 3, 6,)", expected);
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@ pub enum Tok {
|
||||
Plus,
|
||||
Times,
|
||||
Div,
|
||||
Comma,
|
||||
}
|
||||
|
||||
// simplest and stupidest possible tokenizer
|
||||
@ -25,6 +26,7 @@ pub fn tokenize(s: &str) -> Vec<Tok> {
|
||||
'-' => tokens.push(Tok::Minus),
|
||||
'+' => tokens.push(Tok::Plus),
|
||||
'*' => tokens.push(Tok::Times),
|
||||
',' => tokens.push(Tok::Comma),
|
||||
'/' => tokens.push(Tok::Div),
|
||||
_ if c.is_digit(10) => {
|
||||
let (tmp, next) = take_while(c, &mut chars, |c| c.is_digit(10));
|
||||
|
@ -135,6 +135,9 @@ fn emit_recursive_ascent(output_path: &Path, grammar: &r::Grammar) -> io::Result
|
||||
let output_file = try!(fs::File::create(output_path));
|
||||
let mut rust = RustWrite::new(output_file);
|
||||
|
||||
// often some of the uses are not used here
|
||||
rust!(rust, "#![allow(unused_imports)]");
|
||||
|
||||
try!(emit_uses(grammar, &mut rust));
|
||||
|
||||
if grammar.start_nonterminals.is_empty() {
|
||||
|
@ -5,10 +5,11 @@ some pre-expansion and so forth before creating the proper AST.
|
||||
|
||||
*/
|
||||
|
||||
use intern::{InternedString};
|
||||
use intern::{intern, InternedString};
|
||||
use grammar::repr::{NominalTypeRepr, TypeRepr};
|
||||
use grammar::pattern::Pattern;
|
||||
use std::fmt::{Debug, Display, Formatter, Error};
|
||||
use std::iter::once;
|
||||
use util::Sep;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@ -49,6 +50,12 @@ pub struct Conversion {
|
||||
pub to: Pattern<TypeRef>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Path {
|
||||
pub absolute: bool,
|
||||
pub ids: Vec<InternedString>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum TypeRef {
|
||||
// (T1, T2)
|
||||
@ -56,7 +63,7 @@ pub enum TypeRef {
|
||||
|
||||
// Foo<'a, 'b, T1, T2>, Foo::Bar, etc
|
||||
Nominal {
|
||||
path: Vec<InternedString>,
|
||||
path: Path,
|
||||
types: Vec<TypeRef>
|
||||
},
|
||||
|
||||
@ -240,6 +247,14 @@ impl Display for TerminalString {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Path {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||
write!(fmt, "{}{}",
|
||||
if self.absolute {"::"} else {""},
|
||||
Sep("::", &self.ids))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for TerminalString {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||
Display::fmt(self, fmt)
|
||||
@ -346,9 +361,9 @@ impl Display for TypeRef {
|
||||
TypeRef::Tuple(ref types) =>
|
||||
write!(fmt, "({})", Sep(", ", types)),
|
||||
TypeRef::Nominal { ref path, ref types } if types.len() == 0 =>
|
||||
write!(fmt, "{}", Sep("::", path)),
|
||||
write!(fmt, "{}", path),
|
||||
TypeRef::Nominal { ref path, ref types } =>
|
||||
write!(fmt, "{}<{}>", Sep("::", path), Sep(", ", types)),
|
||||
write!(fmt, "{}<{}>", path, Sep(", ", types)),
|
||||
TypeRef::Lifetime(ref s) =>
|
||||
write!(fmt, "{}", s),
|
||||
TypeRef::Id(ref s) =>
|
||||
@ -384,7 +399,7 @@ impl TypeRef {
|
||||
TypeRepr::Lifetime(id),
|
||||
TypeRef::Id(id) =>
|
||||
TypeRepr::Nominal(NominalTypeRepr {
|
||||
path: vec![id],
|
||||
path: Path::from_id(id),
|
||||
types: vec![]
|
||||
}),
|
||||
TypeRef::OfSymbol(_) =>
|
||||
@ -396,3 +411,41 @@ impl TypeRef {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Path {
|
||||
pub fn from_id(id: InternedString) -> Path {
|
||||
Path {
|
||||
absolute: false,
|
||||
ids: vec![id]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vec() -> Path {
|
||||
Path {
|
||||
absolute: true,
|
||||
ids: vec![intern("std"), intern("vec"), intern("Vec")]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn option() -> Path {
|
||||
Path {
|
||||
absolute: true,
|
||||
ids: vec![intern("std"), intern("option"), intern("Option")]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_id(&self) -> Option<InternedString> {
|
||||
if !self.absolute && self.ids.len() == 1 {
|
||||
Some(self.ids[0])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append(&self, id: InternedString) -> Path {
|
||||
Path {
|
||||
absolute: self.absolute,
|
||||
ids: self.ids.iter().cloned().chain(once(id)).collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ representations.
|
||||
*/
|
||||
|
||||
use intern::{InternedString};
|
||||
use grammar::parse_tree::Span;
|
||||
use grammar::parse_tree::{Path, Span};
|
||||
use std::fmt::{Display, Formatter, Error};
|
||||
use util::Sep;
|
||||
|
||||
@ -26,9 +26,9 @@ pub struct FieldPattern<T> {
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum PatternKind<T> {
|
||||
Enum(Vec<InternedString>, Vec<Pattern<T>>),
|
||||
Struct(Vec<InternedString>, Vec<FieldPattern<T>>, /* trailing ..? */ bool),
|
||||
Path(Vec<InternedString>),
|
||||
Enum(Path, Vec<Pattern<T>>),
|
||||
Struct(Path, Vec<FieldPattern<T>>, /* trailing ..? */ bool),
|
||||
Path(Path),
|
||||
Tuple(Vec<Pattern<T>>),
|
||||
Underscore,
|
||||
DotDot,
|
||||
@ -96,15 +96,15 @@ impl<T:Display> Display for PatternKind<T> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||
match *self {
|
||||
PatternKind::Path(ref path) =>
|
||||
write!(fmt, "{}", Sep("::", path)),
|
||||
write!(fmt, "{}", path),
|
||||
PatternKind::Enum(ref path, ref pats) =>
|
||||
write!(fmt, "{}({})", Sep("::", path), Sep(", ", pats)),
|
||||
write!(fmt, "{}({})", path, Sep(", ", pats)),
|
||||
PatternKind::Struct(ref path, ref fields, false) =>
|
||||
write!(fmt, "{} {{ {} }}", Sep("::", path), Sep(", ", fields)),
|
||||
write!(fmt, "{} {{ {} }}", path, Sep(", ", fields)),
|
||||
PatternKind::Struct(ref path, ref fields, true) if fields.len() == 0 =>
|
||||
write!(fmt, "{} {{ .. }}", Sep("::", path)),
|
||||
write!(fmt, "{} {{ .. }}", path),
|
||||
PatternKind::Struct(ref path, ref fields, true) =>
|
||||
write!(fmt, "{} {{ {}, .. }}", Sep("::", path), Sep(", ", fields)),
|
||||
write!(fmt, "{} {{ {}, .. }}", path, Sep(", ", fields)),
|
||||
PatternKind::Tuple(ref paths) =>
|
||||
write!(fmt, "({})", Sep(", ", paths)),
|
||||
PatternKind::Underscore =>
|
||||
|
@ -6,12 +6,12 @@
|
||||
|
||||
use intern::{InternedString};
|
||||
use grammar::pattern::{Pattern, PatternKind};
|
||||
use std::iter::once;
|
||||
use std::fmt::{Debug, Display, Formatter, Error};
|
||||
use util::{map, Map, Sep};
|
||||
|
||||
// These concepts we re-use wholesale
|
||||
pub use grammar::parse_tree::{NonterminalString,
|
||||
Path,
|
||||
Span,
|
||||
TerminalString, TypeParameter};
|
||||
|
||||
@ -92,7 +92,7 @@ pub enum TypeRepr {
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct NominalTypeRepr {
|
||||
pub path: Vec<InternedString>,
|
||||
pub path: Path,
|
||||
pub types: Vec<TypeRepr>
|
||||
}
|
||||
|
||||
@ -173,9 +173,9 @@ impl Debug for TypeRepr {
|
||||
impl Display for NominalTypeRepr {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||
if self.types.len() == 0 {
|
||||
write!(fmt, "{}", Sep("::", &self.path))
|
||||
write!(fmt, "{}", self.path)
|
||||
} else {
|
||||
write!(fmt, "{}<{}>", Sep("::", &self.path), Sep(", ", &self.types))
|
||||
write!(fmt, "{}<{}>", self.path, Sep(", ", &self.types))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -253,11 +253,7 @@ impl ActionFnDefn {
|
||||
|
||||
impl Grammar {
|
||||
pub fn default_pattern(&self, id: InternedString) -> Pattern<TypeRepr> {
|
||||
let path: Vec<InternedString> =
|
||||
self.types.terminal_enum_type().path.iter()
|
||||
.cloned()
|
||||
.chain(once(id))
|
||||
.collect();
|
||||
let path = self.types.terminal_enum_type().path.append(id);
|
||||
Pattern {
|
||||
span: self.token_span,
|
||||
kind: PatternKind::Enum(path, vec![
|
||||
|
@ -2,14 +2,11 @@
|
||||
//!
|
||||
//! [recursive ascent]: https://en.wikipedia.org/wiki/Recursive_ascent_parser
|
||||
|
||||
use intern::{InternedString};
|
||||
use grammar::repr::{Grammar, NonterminalString, Symbol, TerminalString, Types};
|
||||
use lr1::{Lookahead, State, StateIndex};
|
||||
use rust::RustWrite;
|
||||
use std::io::{self, Write};
|
||||
use util::Sep;
|
||||
|
||||
pub type Path = Vec<InternedString>;
|
||||
use util::{Escape, Sep};
|
||||
|
||||
pub fn compile<'grammar,W:Write>(
|
||||
grammar: &'grammar Grammar,
|
||||
@ -61,7 +58,10 @@ impl<'ascent,'grammar,W:Write> RecursiveAscent<'ascent,'grammar,W> {
|
||||
rust!(self.out, "mod {}parse{} {{",
|
||||
self.prefix, self.start_symbol);
|
||||
|
||||
rust!(self.out, "#![allow(non_snake_case, unused_mut, unused_variables)]");
|
||||
// these stylistic lints are annoying for the generated code,
|
||||
// which doesn't follow conventions:
|
||||
rust!(self.out, "#![allow(non_snake_case, non_camel_case_types, \
|
||||
unused_mut, unused_variables, unused_imports)]");
|
||||
rust!(self.out, "");
|
||||
|
||||
try!(self.write_uses());
|
||||
@ -96,7 +96,7 @@ impl<'ascent,'grammar,W:Write> RecursiveAscent<'ascent,'grammar,W> {
|
||||
// have to unwrap and rewrap as we pass up the stack, which
|
||||
// seems silly
|
||||
for &nt in self.grammar.productions.keys() {
|
||||
rust!(self.out, "{}({}),", nt, self.types.nonterminal_type(nt));
|
||||
rust!(self.out, "{}({}),", Escape(nt), self.types.nonterminal_type(nt));
|
||||
}
|
||||
|
||||
rust!(self.out, "}}");
|
||||
@ -122,7 +122,7 @@ impl<'ascent,'grammar,W:Write> RecursiveAscent<'ascent,'grammar,W> {
|
||||
self.grammar.user_parameter_refs(), self.prefix, self.prefix);
|
||||
rust!(self.out, "({}lookahead, {}parse{}::{}Nonterminal::{}({}nt)) => \
|
||||
Ok(({}lookahead, {}nt)),",
|
||||
self.prefix, self.prefix, self.start_symbol, self.prefix, self.start_symbol,
|
||||
self.prefix, self.prefix, self.start_symbol, self.prefix, Escape(self.start_symbol),
|
||||
self.prefix, self.prefix, self.prefix);
|
||||
rust!(self.out, "_ => unreachable!(),");
|
||||
rust!(self.out, "}}");
|
||||
@ -241,11 +241,12 @@ impl<'ascent,'grammar,W:Write> RecursiveAscent<'ascent,'grammar,W> {
|
||||
if !transfer_syms.is_empty() {
|
||||
// if we popped anything off of the stack, then this frame is done
|
||||
rust!(self.out, "return Ok(({}lookahead, {}Nonterminal::{}({}nt)));",
|
||||
self.prefix, self.prefix, production.nonterminal, self.prefix);
|
||||
self.prefix, self.prefix, Escape(production.nonterminal), self.prefix);
|
||||
} else {
|
||||
// otherwise, pop back
|
||||
rust!(self.out, "result = ({}lookahead, {}Nonterminal::{}({}nt));",
|
||||
self.prefix, self.prefix, production.nonterminal, self.prefix);
|
||||
rust!(self.out, "{}result = ({}lookahead, {}Nonterminal::{}({}nt));",
|
||||
self.prefix, self.prefix, self.prefix,
|
||||
Escape(production.nonterminal), self.prefix);
|
||||
fallthrough = true;
|
||||
}
|
||||
|
||||
@ -272,7 +273,8 @@ impl<'ascent,'grammar,W:Write> RecursiveAscent<'ascent,'grammar,W> {
|
||||
|
||||
rust!(self.out, "match {}nt {{", self.prefix);
|
||||
for (&nt, &next_index) in &this_state.gotos {
|
||||
rust!(self.out, "{}Nonterminal::{}({}nt) => {{", self.prefix, nt, self.prefix);
|
||||
rust!(self.out, "{}Nonterminal::{}({}nt) => {{",
|
||||
self.prefix, Escape(nt), self.prefix);
|
||||
rust!(self.out, "let {}sym{} = &mut Some({}nt);",
|
||||
self.prefix, this_prefix.len(), self.prefix);
|
||||
let transition = self.transition(this_prefix, next_index, "lookahead", "tokens");
|
||||
|
@ -1,8 +1,15 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use intern::{intern, read, InternedString};
|
||||
use grammar::parse_tree::{Alternative, Condition, ConditionOp, ExprSymbol, Grammar, GrammarItem,
|
||||
MacroSymbol, NonterminalData, NonterminalString, RepeatOp, RepeatSymbol,
|
||||
Span, Symbol, SymbolKind, TypeRef};
|
||||
use grammar::parse_tree::{Alternative,
|
||||
Condition, ConditionOp,
|
||||
ExprSymbol,
|
||||
Grammar, GrammarItem,
|
||||
MacroSymbol,
|
||||
NonterminalData, NonterminalString,
|
||||
Path,
|
||||
RepeatOp, RepeatSymbol,
|
||||
Span, Symbol, SymbolKind,
|
||||
TypeRef};
|
||||
use normalize::{NormResult, NormError};
|
||||
use normalize::norm_util::{self, Symbols};
|
||||
use regex::Regex;
|
||||
@ -212,7 +219,8 @@ impl MacroExpander {
|
||||
TypeRef::Id(id) => {
|
||||
match args.get(&NonterminalString(id)) {
|
||||
Some(sym) => TypeRef::OfSymbol(sym.clone()),
|
||||
None => TypeRef::Nominal { path: vec![id], types: vec![] },
|
||||
None => TypeRef::Nominal { path: Path::from_id(id),
|
||||
types: vec![] },
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -351,7 +359,7 @@ impl MacroExpander {
|
||||
|
||||
match repeat.op {
|
||||
RepeatOp::Star => {
|
||||
let path = vec![intern("std"), intern("vec"), intern("Vec")];
|
||||
let path = Path::vec();
|
||||
let ty_ref = TypeRef::Nominal { path: path, types: vec![base_symbol_ty] };
|
||||
|
||||
Ok(GrammarItem::Nonterminal(NonterminalData {
|
||||
@ -394,7 +402,7 @@ impl MacroExpander {
|
||||
}
|
||||
|
||||
RepeatOp::Plus => {
|
||||
let path = vec![intern("std"), intern("vec"), intern("Vec")];
|
||||
let path = Path::vec();
|
||||
let ty_ref = TypeRef::Nominal { path: path, types: vec![base_symbol_ty] };
|
||||
|
||||
Ok(GrammarItem::Nonterminal(NonterminalData {
|
||||
@ -432,7 +440,7 @@ impl MacroExpander {
|
||||
}
|
||||
|
||||
RepeatOp::Question => {
|
||||
let path = vec![intern("std"), intern("option"), intern("Option")];
|
||||
let path = Path::option();
|
||||
let ty_ref = TypeRef::Nominal { path: path, types: vec![base_symbol_ty] };
|
||||
|
||||
Ok(GrammarItem::Nonterminal(NonterminalData {
|
||||
|
@ -2,9 +2,13 @@ use super::{NormResult, NormError};
|
||||
use super::norm_util::{self, AlternativeAction, Symbols};
|
||||
|
||||
use std::collections::{HashMap};
|
||||
use grammar::parse_tree::{Alternative, EnumToken, Grammar, GrammarItem,
|
||||
use grammar::parse_tree::{Alternative,
|
||||
EnumToken,
|
||||
Grammar, GrammarItem,
|
||||
NonterminalData, NonterminalString,
|
||||
Span, SymbolKind, TypeRef};
|
||||
Path,
|
||||
Span,
|
||||
SymbolKind, TypeRef};
|
||||
use grammar::repr::{NominalTypeRepr, Types, TypeRepr};
|
||||
|
||||
#[cfg(test)]
|
||||
@ -199,7 +203,7 @@ impl<'grammar> TypeInferencer<'grammar> {
|
||||
Ok(TypeRepr::Lifetime(id))
|
||||
}
|
||||
TypeRef::Id(id) => {
|
||||
Ok(TypeRepr::Nominal(NominalTypeRepr { path: vec![id],
|
||||
Ok(TypeRepr::Nominal(NominalTypeRepr { path: Path::from_id(id),
|
||||
types: vec![] }))
|
||||
}
|
||||
TypeRef::Ref { lifetime, mutable, ref referent } => {
|
||||
|
@ -2,16 +2,15 @@ use intern::{intern, InternedString};
|
||||
use grammar::parse_tree::*;
|
||||
use grammar::pattern::*;
|
||||
use rusty_peg;
|
||||
use std::iter;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
fn make_list<T>(head: Vec<(T, &'static str)>,
|
||||
tail: Option<(T, Option<&'static str>)>)
|
||||
tail: Option<T>)
|
||||
-> Vec<T> {
|
||||
head.into_iter().map(|(a,_)| a)
|
||||
.chain(tail.map(|(a, _)| a).into_iter())
|
||||
.chain(tail)
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -32,7 +31,7 @@ rusty_peg! {
|
||||
};
|
||||
|
||||
GRAMMAR_TPS: Vec<TypeParameter> =
|
||||
("<" <h:{TYPE_PARAMETER ","}> <t:[TYPE_PARAMETER [","]]> ">") => make_list(h, t);
|
||||
("<" <h:{TYPE_PARAMETER ","}> <t:[TYPE_PARAMETER]> ">") => make_list(h, t);
|
||||
|
||||
TYPE_PARAMETER: TypeParameter =
|
||||
(LIFETIME_TYPE_PARAMETER / ID_TYPE_PARAMETER);
|
||||
@ -44,13 +43,13 @@ rusty_peg! {
|
||||
(<l:ID>) => TypeParameter::Id(l);
|
||||
|
||||
GRAMMAR_PARAMS: Vec<Parameter> =
|
||||
("(" <h:{GRAMMAR_PARAM ","}> <t:[GRAMMAR_PARAM [","]]> ")") => make_list(h, t);
|
||||
("(" <h:{GRAMMAR_PARAM ","}> <t:[GRAMMAR_PARAM]> ")") => make_list(h, t);
|
||||
|
||||
GRAMMAR_PARAM: Parameter =
|
||||
(<id:ID> ":" <t:TYPE_REF>) => Parameter { name: id, ty: t };
|
||||
|
||||
WHERE_CLAUSES: Vec<String> =
|
||||
("where" <h:{TYPE ","}> <t:[TYPE [","]]>) => make_list(h, t);
|
||||
("where" <h:{TYPE ","}> <t:[TYPE]>) => make_list(h, t);
|
||||
|
||||
GRAMMAR_ITEM: GrammarItem =
|
||||
(EXTERN_TOKEN / NONTERMINAL / USE);
|
||||
@ -83,7 +82,7 @@ rusty_peg! {
|
||||
(<a:ESCAPE>) => (NonterminalString(a), vec![]);
|
||||
|
||||
NONTERMINAL_NAME_MACRO: (NonterminalString, Vec<NonterminalString>) =
|
||||
(<a:NONTERMINAL_ID> "<" <b:{NONTERMINAL_ID ","}> <c:[NONTERMINAL_ID [","]]> ">") => {
|
||||
(<a:NONTERMINAL_ID> "<" <b:{NONTERMINAL_ID ","}> <c:[NONTERMINAL_ID]> ">") => {
|
||||
(a, make_list(b, c))
|
||||
};
|
||||
|
||||
@ -157,7 +156,7 @@ rusty_peg! {
|
||||
(MACRO_SYMBOL / TERMINAL_SYMBOL / NT_SYMBOL / ESCAPE_SYMBOL / PAREN_SYMBOL);
|
||||
|
||||
MACRO_SYMBOL: Symbol =
|
||||
(<lo:POSL> <l:MACRO_ID> <m:{SYMBOL ","}> <n:[SYMBOL [","]]> ">" <hi:POSR>) => {
|
||||
(<lo:POSL> <l:MACRO_ID> <m:{SYMBOL ","}> <n:[SYMBOL]> ">" <hi:POSR>) => {
|
||||
Symbol::new(Span(lo, hi),
|
||||
SymbolKind::Macro(MacroSymbol { name: l,
|
||||
args: make_list(m, n) }))
|
||||
@ -213,14 +212,15 @@ rusty_peg! {
|
||||
|
||||
NOMINAL_TYPE_REF: TypeRef =
|
||||
(<p:PATH> <a:[NOMINAL_TYPE_REF_ARGS]>) => {
|
||||
if p.len() == 1 && a.is_none() {
|
||||
// detect something like `Foo` and treat it specially,
|
||||
// so that macro expansion can pattern match here
|
||||
TypeRef::Id(p.into_iter().next().unwrap())
|
||||
} else {
|
||||
// otherwise, `Vec<..>` or `Foo::Bar` etc expand to
|
||||
// this full path
|
||||
TypeRef::Nominal { path: p, types: a.unwrap_or(vec![]) }
|
||||
match p.as_id() {
|
||||
Some(id) if a.is_none() =>
|
||||
// detect something like `Foo` and treat it specially,
|
||||
// so that macro expansion can pattern match here
|
||||
TypeRef::Id(id),
|
||||
_ =>
|
||||
// otherwise, `Vec<..>` or `Foo::Bar` etc expand to
|
||||
// this full path
|
||||
TypeRef::Nominal { path: p, types: a.unwrap_or(vec![]) }
|
||||
}
|
||||
};
|
||||
|
||||
@ -237,22 +237,18 @@ rusty_peg! {
|
||||
TYPE_REF_COMMA: TypeRef =
|
||||
(<t:TYPE_REF> ",") => t;
|
||||
|
||||
PATH: Vec<InternedString> =
|
||||
(<b:{PATH_BASE}> <c:ID>) => {
|
||||
let mut b = b;
|
||||
b.push(c);
|
||||
b
|
||||
PATH: Path =
|
||||
(<a:["::"]> <h:{ID "::"}> <t:ID>) => {
|
||||
Path { absolute: a.is_some(),
|
||||
ids: make_list(h, Some(t)) }
|
||||
};
|
||||
|
||||
PATH_BASE: InternedString =
|
||||
(<i:ID> "::") => i;
|
||||
|
||||
// TOKEN DEFINITIONS
|
||||
|
||||
EXTERN_TOKEN: GrammarItem =
|
||||
("extern" "token" "{"
|
||||
"enum" <lo:POSL> <t:TYPE_REF> <hi:POSR> "{"
|
||||
<c0:{CONVERSION ","}> <c1:[CONVERSION [","]]>
|
||||
<c0:{CONVERSION ","}> <c1:[CONVERSION]>
|
||||
"}"
|
||||
"}") => {
|
||||
GrammarItem::ExternToken(ExternToken {
|
||||
@ -274,14 +270,14 @@ rusty_peg! {
|
||||
DOTDOT_PATTERN / CHOOSE_PATTERN / TUPLE_PATTERN / PATH_PATTERN);
|
||||
|
||||
ENUM_PATTERN: Pattern<TypeRef> =
|
||||
(<lo:POSL> <p:PATH> "(" <s0:{PATTERN ","}> <s1:[PATTERN [","]]> ")" <hi:POSR>) => {
|
||||
(<lo:POSL> <p:PATH> "(" <s0:{PATTERN ","}> <s1:[PATTERN]> ")" <hi:POSR>) => {
|
||||
Pattern { span: Span(lo, hi),
|
||||
kind: PatternKind::Enum(p, make_list(s0, s1)) }
|
||||
};
|
||||
|
||||
STRUCT_PATTERN0: Pattern<TypeRef> =
|
||||
(<lo:POSL> <p:PATH> "{" <s0:{FIELD_PATTERN ","}>
|
||||
<s1:[FIELD_PATTERN [","]]> "}" <hi:POSR>) => {
|
||||
<s1:[FIELD_PATTERN]> "}" <hi:POSR>) => {
|
||||
Pattern { span: Span(lo, hi),
|
||||
kind: PatternKind::Struct(p,
|
||||
make_list(s0, s1),
|
||||
@ -322,17 +318,14 @@ rusty_peg! {
|
||||
};
|
||||
|
||||
TUPLE_PATTERN: Pattern<TypeRef> =
|
||||
(<lo:POSL> "(" <p0:{PATTERN ","}> <p1:[PATTERN [","]]> ")" <hi:POSR>) => {
|
||||
(<lo:POSL> "(" <p0:{PATTERN ","}> <p1:[PATTERN]> ")" <hi:POSR>) => {
|
||||
Pattern { span: Span(lo, hi),
|
||||
kind: PatternKind::Tuple(make_list(p0, p1)) }
|
||||
};
|
||||
|
||||
PATH_PATTERN: Pattern<TypeRef> =
|
||||
(<lo:POSL> <id0:ID> <id1:{"::" ID}> <hi:POSR>) => {
|
||||
let path = iter::once(id0).chain(id1.into_iter().map(|pair| pair.1))
|
||||
.collect();
|
||||
Pattern { span: Span(lo, hi),
|
||||
kind: PatternKind::Path(path) }
|
||||
(<lo:POSL> <p:PATH> <hi:POSR>) => {
|
||||
Pattern { span: Span(lo, hi), kind: PatternKind::Path(p) }
|
||||
};
|
||||
|
||||
// IDENTIFIERS, LIFETIMES
|
||||
|
@ -19,6 +19,23 @@ impl<'a,S:Display> Display for Sep<&'a Vec<S>> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Escape<S>(pub S);
|
||||
|
||||
impl<S:Display> Display for Escape<S> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||
let tmp = format!("{}", self.0);
|
||||
for c in tmp.chars() {
|
||||
match c {
|
||||
'a' ... 'z' | '_' | '0' ... '9' | 'A' ... 'Z' =>
|
||||
try!(write!(fmt, "{}", c)),
|
||||
_ =>
|
||||
try!(write!(fmt, "_")), // um, obviously not the best escaping :)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Prefix<S>(pub &'static str, pub S);
|
||||
|
||||
impl<'a,S:Display> Display for Prefix<&'a [S]> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user