Simplify parser.

Use 'if let' instead of 'match' where it makes sense.

Use EBNF notation for the grammar rules. This simplifies repetition a lot.
This commit is contained in:
Jakob Stoklund Olesen
2016-04-28 08:06:30 -07:00
parent f1a4b28d3f
commit 8d0311b642
2 changed files with 41 additions and 56 deletions

View File

@@ -413,11 +413,9 @@ calling convention:
.. productionlist:: .. productionlist::
signature : "(" [arglist] ")" ["->" retlist] [call_conv] signature : "(" [arglist] ")" ["->" retlist] [call_conv]
arglist : arg arglist : arg { "," arg }
: arglist "," arg
retlist : arglist retlist : arglist
arg : type arg : type { flag }
: arg flag
flag : "uext" | "sext" | "inreg" flag : "uext" | "sext" | "inreg"
callconv : `string` callconv : `string`

View File

@@ -70,20 +70,20 @@ impl<'a> Parser<'a> {
// Match and consume a token without payload. // Match and consume a token without payload.
fn match_token(&mut self, want: Token<'a>, err_msg: &str) -> Result<Token<'a>> { fn match_token(&mut self, want: Token<'a>, err_msg: &str) -> Result<Token<'a>> {
match self.token() { if self.token() == Some(want) {
Some(ref t) if *t == want => Ok(self.consume()), Ok(self.consume())
_ => Err(self.error(err_msg)), } else {
Err(self.error(err_msg))
} }
} }
// if the next token is a `want`, consume it, otherwise do nothing. // If the next token is a `want`, consume it, otherwise do nothing.
fn optional(&mut self, want: Token<'a>) -> bool { fn optional(&mut self, want: Token<'a>) -> bool {
match self.token() { if self.token() == Some(want) {
Some(t) if t == want => {
self.consume(); self.consume();
true true
} } else {
_ => false, false
} }
} }
@@ -124,23 +124,19 @@ impl<'a> Parser<'a> {
// Parse a function signature. // Parse a function signature.
// //
// signature ::= * "(" arglist ")" ["->" retlist] [call_conv] // signature ::= * "(" [arglist] ")" ["->" retlist] [call_conv]
// callconv ::= string
//
// function ::= "function" * name signature { ... }
// //
fn parse_signature(&mut self) -> Result<types::Signature> { fn parse_signature(&mut self) -> Result<types::Signature> {
let mut sig = types::Signature::new(); let mut sig = types::Signature::new();
try!(self.match_token(Token::LPar, "Expected function signature: '(' args... ')'")); try!(self.match_token(Token::LPar, "Expected function signature: '(' args... ')'"));
// signature ::= "(" * arglist ")" ["->" retlist] [call_conv] // signature ::= "(" * [arglist] ")" ["->" retlist] [call_conv]
if self.token() != Some(Token::RPar) {
sig.argument_types = try!(self.parse_argument_list()); sig.argument_types = try!(self.parse_argument_list());
}
try!(self.match_token(Token::RPar, "Expected ')' after function arguments")); try!(self.match_token(Token::RPar, "Expected ')' after function arguments"));
if self.optional(Token::Arrow) { if self.optional(Token::Arrow) {
sig.return_types = try!(self.parse_argument_list()); sig.return_types = try!(self.parse_argument_list());
if sig.return_types.is_empty() {
return Err(self.error("Missing return type after '->'"));
}
} }
// TBD: calling convention. // TBD: calling convention.
@@ -148,26 +144,19 @@ impl<'a> Parser<'a> {
Ok(sig) Ok(sig)
} }
// Parse (possibly empty) list of function argument / return value types. // Parse list of function argument / return value types.
//
// arglist ::= * arg { "," arg }
// //
// arglist ::= * <empty>
// * arg
// * arglist "," arg
fn parse_argument_list(&mut self) -> Result<Vec<types::ArgumentType>> { fn parse_argument_list(&mut self) -> Result<Vec<types::ArgumentType>> {
let mut list = Vec::new(); let mut list = Vec::new();
// arglist ::= * <empty>
// * arg
match self.token() {
Some(Token::Type(_)) => list.push(try!(self.parse_argument_type())),
_ => return Ok(list),
}
// arglist ::= arg * // arglist ::= * arg { "," arg }
// arglist * "," arg list.push(try!(self.parse_argument_type()));
while self.token() == Some(Token::Comma) {
// arglist ::= arglist * "," arg // arglist ::= arg * { "," arg }
self.consume(); while self.optional(Token::Comma) {
// arglist ::= arglist "," * arg // arglist ::= arg { "," * arg }
list.push(try!(self.parse_argument_type())); list.push(try!(self.parse_argument_type()));
} }
@@ -176,27 +165,25 @@ impl<'a> Parser<'a> {
// Parse a single argument type with flags. // Parse a single argument type with flags.
fn parse_argument_type(&mut self) -> Result<types::ArgumentType> { fn parse_argument_type(&mut self) -> Result<types::ArgumentType> {
// arg ::= * type // arg ::= * type { flag }
// * arg flag let mut arg = if let Some(Token::Type(t)) = self.token() {
let mut arg = match self.token() { types::ArgumentType::new(t)
Some(Token::Type(t)) => types::ArgumentType::new(t), } else {
_ => return Err(self.error("Expected argument type")), return Err(self.error("Expected argument type"));
}; };
loop {
self.consume(); self.consume();
// arg ::= arg * flag
match self.token() { // arg ::= type * { flag }
Some(Token::Identifier(s)) => { while let Some(Token::Identifier(s)) = self.token() {
match s { match s {
"uext" => arg.extension = types::ArgumentExtension::Uext, "uext" => arg.extension = types::ArgumentExtension::Uext,
"sext" => arg.extension = types::ArgumentExtension::Sext, "sext" => arg.extension = types::ArgumentExtension::Sext,
"inreg" => arg.inreg = true, "inreg" => arg.inreg = true,
_ => break, _ => break,
} }
self.consume();
} }
_ => break,
}
}
Ok(arg) Ok(arg)
} }
} }