Begin parser unit tests, add public interface.

The main entry point is Parser::parse().
This commit is contained in:
Jakob Stoklund Olesen
2016-04-28 09:05:11 -07:00
parent 8d0311b642
commit 07afc6e8da

View File

@@ -12,6 +12,7 @@ use cretonne::{types, repr};
pub use lexer::Location; pub use lexer::Location;
/// A parse error is returned when the parse failed. /// A parse error is returned when the parse failed.
#[derive(Debug)]
pub struct Error { pub struct Error {
pub location: Location, pub location: Location,
pub message: String, pub message: String,
@@ -32,6 +33,21 @@ pub struct Parser<'a> {
} }
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
/// Create a new `Parser` which reads `text`. The referenced text must outlive the parser.
pub fn new(text: &'a str) -> Parser {
Parser {
lex: Lexer::new(text),
lex_error: None,
lookahead: None,
location: Location { line_number: 0 },
}
}
/// Parse the entire string into a list of functions.
pub fn parse(text: &'a str) -> Result<Vec<repr::Function>> {
Self::new(text).parse_function_list()
}
// Consume the current lookahead token and return it. // Consume the current lookahead token and return it.
fn consume(&mut self) -> Token<'a> { fn consume(&mut self) -> Token<'a> {
self.lookahead.take().expect("No token to consume") self.lookahead.take().expect("No token to consume")
@@ -62,7 +78,7 @@ impl<'a> Parser<'a> {
message: message:
// If we have a lexer error latched, report that. // If we have a lexer error latched, report that.
match self.lex_error { match self.lex_error {
Some(lexer::Error::InvalidChar) => "Invalid character".to_string(), Some(lexer::Error::InvalidChar) => "invalid character".to_string(),
None => message.to_string(), None => message.to_string(),
} }
} }
@@ -87,12 +103,23 @@ impl<'a> Parser<'a> {
} }
} }
/// Parse a list of function definitions.
///
/// This is the top-level parse function matching the whole contents of a file.
pub fn parse_function_list(&mut self) -> Result<Vec<repr::Function>> {
let mut list = Vec::new();
while self.token().is_some() {
list.push(try!(self.parse_function()));
}
Ok(list)
}
// Parse a whole function definition. // Parse a whole function definition.
// //
// function ::= * "function" name signature { ... } // function ::= * "function" name signature { ... }
// //
fn parse_function(&mut self) -> Result<repr::Function> { fn parse_function(&mut self) -> Result<repr::Function> {
try!(self.match_token(Token::Function, "Expected 'function' keyword")); try!(self.match_token(Token::Function, "expected 'function' keyword"));
// function ::= "function" * name signature { ... } // function ::= "function" * name signature { ... }
let name = try!(self.parse_function_name()); let name = try!(self.parse_function_name());
@@ -102,8 +129,8 @@ impl<'a> Parser<'a> {
let mut func = repr::Function::new(); let mut func = repr::Function::new();
try!(self.match_token(Token::LBrace, "Expected '{' before function body")); try!(self.match_token(Token::LBrace, "expected '{' before function body"));
try!(self.match_token(Token::RBrace, "Expected '}' after function body")); try!(self.match_token(Token::RBrace, "expected '}' after function body"));
Ok(func) Ok(func)
} }
@@ -118,7 +145,7 @@ impl<'a> Parser<'a> {
self.consume(); self.consume();
Ok(s.to_string()) Ok(s.to_string())
} }
_ => Err(self.error("Expected function name")), _ => Err(self.error("expected function name")),
} }
} }
@@ -129,12 +156,12 @@ impl<'a> Parser<'a> {
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) { 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());
} }
@@ -169,7 +196,7 @@ impl<'a> Parser<'a> {
let mut arg = if let Some(Token::Type(t)) = self.token() { let mut arg = if let Some(Token::Type(t)) = self.token() {
types::ArgumentType::new(t) types::ArgumentType::new(t)
} else { } else {
return Err(self.error("Expected argument type")); return Err(self.error("expected argument type"));
}; };
self.consume(); self.consume();
@@ -187,3 +214,24 @@ impl<'a> Parser<'a> {
Ok(arg) Ok(arg)
} }
} }
#[cfg(test)]
mod tests {
use super::*;
use cretonne::types::{self, ArgumentType, ArgumentExtension};
#[test]
fn argument_type() {
let mut p = Parser::new("i32 sext");
let arg = p.parse_argument_type().unwrap();
assert_eq!(arg,
ArgumentType {
value_type: types::I32,
extension: ArgumentExtension::Sext,
inreg: false,
});
let Error { location, message } = p.parse_argument_type().unwrap_err();
assert_eq!(location.line_number, 1);
assert_eq!(message, "expected argument type");
}
}