// See also: file:///usr/share/doc/python/html/reference/grammar.html?highlight=grammar
use super::ast;
use super::lexer;
use std::iter::FromIterator;
grammar;
pub Program: ast::Program = {
=> ast::Program { statements: Vec::from_iter(lines.into_iter().filter_map(|e| e)) },
};
// A file line either has a declaration, or an empty newline:
FileLine: Option = {
=> Some(s),
"\n" => None,
};
Suite: Vec = {
=> vec![s],
"\n" indent dedent => s,
};
pub Statement: ast::Statement = {
SimpleStatement,
CompoundStatement,
};
SimpleStatement: ast::Statement = {
"\n" => s,
};
SmallStatement: ast::Statement = {
// => ast::Statement::Expression { expression: e },
ExpressionStatement,
"pass" => ast::Statement::Pass,
FlowStatement,
ImportStatement,
AssertStatement,
};
ExpressionStatement: ast::Statement = {
=> {
//match e2 {
// None => ast::Statement::Expression { expression: e },
// Some(e3) => ast::Statement::Expression { expression: e },
//}
if e2.len() > 0 {
// Dealing with assignment here
// TODO: for rhs in e2 {
let rhs = e2.into_iter().next().unwrap();
// ast::Expression::Tuple { elements: e2.into_iter().next().unwrap()
let v = rhs.into_iter().next().unwrap();
let lhs = ast::Statement::Assign { targets: e, value: v };
lhs
} else {
if e.len() > 1 {
panic!("Not good?");
// ast::Statement::Expression { expression: e[0] }
} else {
ast::Statement::Expression { expression: e.into_iter().next().unwrap() }
}
}
},
};
AssignSuffix: Vec = {
"=" => e,
};
FlowStatement: ast::Statement = {
"break" => ast::Statement::Break,
"continue" => ast::Statement::Continue,
"return" => ast::Statement::Return { value: t},
// raise
// yield
};
ImportStatement: ast::Statement = {
"import" => ast::Statement::Import { name: n },
};
DottedName: String = {
=> n,
};
AssertStatement: ast::Statement = {
"assert" => ast::Statement::Assert {
test: t,
msg: match m {
Some(e) => Some(e.1),
None => None,
}
},
};
CompoundStatement: ast::Statement = {
IfStatement,
WhileStatement,
ForStatement,
WithStatement,
FuncDef,
ClassDef,
};
IfStatement: ast::Statement = {
"if" ":" => ast::Statement::If { test: e, body: s },
};
WhileStatement: ast::Statement = {
"while" ":" => ast::Statement::While { test: e, body: s },
};
ForStatement: ast::Statement = {
"for" "in" ":" => ast::Statement::For { target: e, iter: t, body: s, or_else: None },
};
WithStatement: ast::Statement = {
"with" "as" ":" => ast::Statement::With { items: t, body: s },
};
FuncDef: ast::Statement = {
"def" "(" ")" ":" => ast::Statement::FunctionDef { name: i, body: s },
};
ClassDef: ast::Statement = {
"class" ":" => ast::Statement::ClassDef { name: n },
};
Test: ast::Expression = {
=> e,
};
OrTest: ast::Expression = {
=> e,
};
AndTest: ast::Expression = {
=> e,
};
NotTest: ast::Expression = {
=> e,
};
Comparison: ast::Expression = {
=> ast::Expression::Compare { a: Box::new(e1), op: op, b: Box::new(e2) },
=> e,
};
CompOp: ast::Comparison = {
"==" => ast::Comparison::Equal,
"!=" => ast::Comparison::NotEqual,
"<" => ast::Comparison::Less,
"<=" => ast::Comparison::LessOrEqual,
">" => ast::Comparison::Greater,
">=" => ast::Comparison::GreaterOrEqual,
"in" => ast::Comparison::In,
"not" "in" => ast::Comparison::NotIn,
"is" => ast::Comparison::Is,
"is" "not" => ast::Comparison::IsNot,
};
pub Expression: ast::Expression = {
"|" => ast::Expression::Binop { a: Box::new(e1), op: ast::Operator::BitOr, b: Box::new(e2) },
=> e,
};
XorExpression: ast::Expression = {
"^" => ast::Expression::Binop { a: Box::new(e1), op: ast::Operator::BitXor, b: Box::new(e2) },
=> e,
};
AndExpression: ast::Expression = {
"&" => ast::Expression::Binop { a: Box::new(e1), op: ast::Operator::BitAnd, b: Box::new(e2) },
=> e,
};
ArithmaticExpression: ast::Expression = {
=> ast::Expression::Binop { a: Box::new(a), op: op, b: Box::new(b) },
Term,
};
AddOp: ast::Operator = {
"+" => ast::Operator::Add,
"-" => ast::Operator::Sub,
};
Term: ast::Expression = {
=> ast::Expression::Binop { a: Box::new(a), op: op, b: Box::new(b) },
Factor,
};
MulOp: ast::Operator = {
"*" => ast::Operator::Mult,
"/" => ast::Operator::Div,
"//" => ast::Operator::FloorDiv,
"%" => ast::Operator::Mod,
"@" => ast::Operator::MatMult,
};
Factor: ast::Expression = {
"+" => e,
"-" => ast::Expression::Unop { a: Box::new(e), op: ast::UnaryOperator::Neg },
=> e,
};
Power: ast::Expression = {
=> e,
};
AtomExpr: ast::Expression = {
=> e,
"(" ")" => ast::Expression::Call { function: Box::new(f), args: a },
"[" "]" => ast::Expression::Binop { a: Box::new(e), op: ast::Operator::Subscript, b: Box::new(s) },
"." => ast::Expression::Attribute { value: Box::new(e), name: n },
};
Subscript: ast::Expression = {
=> e,
":" => {
let s1 = match e1 {
None => ast::Expression::None,
Some(e) => e,
};
let s2 = match e2 {
None => ast::Expression::None,
Some(e) => e,
};
ast::Expression::Slice { elements: vec![s1, s2] }
}
};
Atom: ast::Expression = {
=> ast::Expression::String { value: s },
=> ast::Expression::Number { value: n },
=> ast::Expression::Identifier { name: i },
"[" "]" => ast::Expression::List { elements: e },
"(" ")" => e,
"True" => ast::Expression::True,
"False" => ast::Expression::False,
"None" => ast::Expression::None,
};
ExpressionList: Vec = {
> => e,
};
TestList: Vec = {
=> {
let mut l = vec![e1];
l.extend(e2.into_iter().map(|x| x.1));
l
}
};
FunctionArguments: Vec = {
> => e,
};
Comma: Vec = {
",")*> => {
let mut items = items;
items.extend(last);
items
}
};
Number: i32 = => s;
String: String = {
=> s,
};
Identifier: String = => s;
// Hook external lexer:
extern {
type Location = usize;
type Error = lexer::LexicalError;
enum lexer::Tok {
indent => lexer::Tok::Indent,
dedent => lexer::Tok::Dedent,
"+" => lexer::Tok::Plus,
"-" => lexer::Tok::Minus,
":" => lexer::Tok::Colon,
"." => lexer::Tok::Dot,
"," => lexer::Tok::Comma,
"*" => lexer::Tok::Star,
"&" => lexer::Tok::Amper,
"@" => lexer::Tok::At,
"%" => lexer::Tok::Percent,
"//" => lexer::Tok::DoubleSlash,
"^" => lexer::Tok::CircumFlex,
"|" => lexer::Tok::Vbar,
"/" => lexer::Tok::Slash,
"(" => lexer::Tok::Lpar,
")" => lexer::Tok::Rpar,
"[" => lexer::Tok::Lsqb,
"]" => lexer::Tok::Rsqb,
"=" => lexer::Tok::Equal,
"+=" => lexer::Tok::PlusEqual,
"-=" => lexer::Tok::MinusEqual,
"==" => lexer::Tok::EqEqual,
"!=" => lexer::Tok::NotEqual,
"<" => lexer::Tok::Less,
"<=" => lexer::Tok::LessEqual,
">" => lexer::Tok::Greater,
">=" => lexer::Tok::GreaterEqual,
"as" => lexer::Tok::As,
"assert" => lexer::Tok::Assert,
"break" => lexer::Tok::Break,
"class" => lexer::Tok::Class,
"continue" => lexer::Tok::Break,
"def" => lexer::Tok::Def,
"for" => lexer::Tok::For,
"if" => lexer::Tok::If,
"in" => lexer::Tok::In,
"is" => lexer::Tok::Is,
"import" => lexer::Tok::Import,
"not" => lexer::Tok::Not,
"pass" => lexer::Tok::Pass,
"return" => lexer::Tok::Return,
"while" => lexer::Tok::While,
"with" => lexer::Tok::With,
"True" => lexer::Tok::True,
"False" => lexer::Tok::False,
"None" => lexer::Tok::None,
number => lexer::Tok::Number { value: },
string => lexer::Tok::String { value: },
name => lexer::Tok::Name { name: },
"\n" => lexer::Tok::Newline,
}
}