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:
@@ -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`
|
||||||
|
|
||||||
|
|||||||
@@ -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]
|
||||||
sig.argument_types = try!(self.parse_argument_list());
|
if self.token() != Some(Token::RPar) {
|
||||||
|
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
|
// arg ::= type * { flag }
|
||||||
match self.token() {
|
while let Some(Token::Identifier(s)) = self.token() {
|
||||||
Some(Token::Identifier(s)) => {
|
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,
|
_ => break,
|
||||||
}
|
}
|
||||||
|
self.consume();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(arg)
|
Ok(arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user