Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
134 lines (121 sloc) 3.72 KB
//* vim: set ft=rust: */
use crate::program::posix::{ast, lex};
grammar<'input>(text: &'input str);
extern {
type Location = usize;
type Error = lex::Error;
enum lex::Token<'input> {
" " => lex::Token::Space,
"\t" => lex::Token::Tab,
"\n" => lex::Token::Linefeed,
";" => lex::Token::Semi,
"&" => lex::Token::Amper,
"{" => lex::Token::LBrace,
"}" => lex::Token::RBrace,
"(" => lex::Token::LParen,
")" => lex::Token::RParen,
"`" => lex::Token::Backtick,
"!" => lex::Token::Bang,
"|" => lex::Token::Pipe,
"$" => lex::Token::Dollar,
"=" => lex::Token::Equals,
"\\" => lex::Token::Backslash,
"\"" => lex::Token::DoubleQuote,
"'" => lex::Token::SingleQuote,
">" => lex::Token::RCaret,
"<" => lex::Token::LCaret,
"&&" => lex::Token::And,
"||" => lex::Token::Or,
"if" => lex::Token::If,
"then" => lex::Token::Then,
"else" => lex::Token::Else,
"elif" => lex::Token::Elif,
"fi" => lex::Token::Fi,
"WORD" => lex::Token::Word(<&'input str>),
"{#!" => lex::Token::Shebang(<&'input str>),
"TEXT" => lex::Token::Text(<&'input str>),
}
}
pub Program: ast::Program = {
<p: Program> "\n" <l: Jobs> => p.append(&l),
<p: Program> "\n" => p,
<p: Program> ";" <g: Jobs> => p.append(&g),
<p: Program> ";" => p,
Jobs => <>,
}
Jobs: ast::Program = {
<cs: Command> "&" <j: Jobs> => {
j.insert(&ast::Command::Background(box cs))
},
Job => ast::Program(vec![box <>]),
}
Job: ast::Command = {
<cs: Command> "&" => {
ast::Command::Background(box cs)
},
Command => <>,
}
Compound: ast::Command = {
<cs: Command> ";" <c: Compound> => {
match c {
c @ ast::Command::Compound(_) => c.insert(&cs),
c => ast::Command::Compound(vec![box cs, box c]),
}
},
<cs: Command> ";" => {
ast::Command::Compound(vec![box cs])
},
}
pub Command: ast::Command = {
// TODO #15: Hopefully in fixing #8 and #10 this can play nicely.
// NOTE: This can be successfully complied, but will break a doc tests.
<s: "{#!"> <t: "TEXT"> "}" => {
let i = ast::Interpreter::Other(s.into());
ast::Command::Shebang(i, t.into())
},
"(" <p: Program> ")" => {
ast::Command::Subshell(box p)
},
"{" <c: Compound> "}" => c,
"if" <cond: Compound> "then" <then: Compound> <els: Else> "fi" => {
let left = ast::Command::And(box cond, box then);
ast::Command::Or(box left, box els)
},
"if" <cond: Compound> "then" <then: Compound> "fi" => {
ast::Command::And(box cond, box then)
},
<cs: Command> "&&" <p: Pipeline> => {
ast::Command::And(box cs, box p)
},
<cs: Command> "||" <p: Pipeline> => {
ast::Command::Or(box cs, box p)
},
Pipeline => <>,
}
Else: ast::Command = {
"elif" <elif: Compound> "then" <then: Compound> => {
ast::Command::And(box elif, box then)
},
"elif" <elif: Compound> "then" <then: Compound> <els: Else> => {
let left = ast::Command::And(box elif, box then);
ast::Command::Or(box left, box els)
},
"else" <els: Compound> => els,
}
Pipeline: ast::Command = {
"!" <ps: PipelineSeq> => {
ast::Command::Not(box ps)
},
<ps: PipelineSeq> => ps,
}
PipelineSeq: ast::Command = {
<ps: PipelineSeq> "|" "\n"* <c: Simple> => {
ast::Command::Pipeline(box ps, box c)
},
<c: Simple> => c,
}
Simple: ast::Command = {
"WORD"+ => ast::Command::Simple(<>.iter().map(|w| {
ast::Word(w.to_string())
}).collect())
}