|
@ -33,6 +33,23 @@ impl Display for Error { |
|
|
|
|
|
|
|
|
pub type Result<T> = result::Result<T, Error>; |
|
|
pub type Result<T> = result::Result<T, Error>; |
|
|
|
|
|
|
|
|
|
|
|
// Create an `Err` variant of `Result<X>` from a location and `format!` args.
|
|
|
|
|
|
macro_rules! err { |
|
|
|
|
|
( $loc:expr, $msg:expr ) => { |
|
|
|
|
|
Err(Error { |
|
|
|
|
|
location: $loc.clone(), |
|
|
|
|
|
message: String::from($msg), |
|
|
|
|
|
}) |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
( $loc:expr, $fmt:expr, $( $arg:expr ),+ ) => { |
|
|
|
|
|
Err(Error { |
|
|
|
|
|
location: $loc.clone(), |
|
|
|
|
|
message: format!( $fmt, $( $arg ),+ ), |
|
|
|
|
|
}) |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
pub struct Parser<'a> { |
|
|
pub struct Parser<'a> { |
|
|
lex: Lexer<'a>, |
|
|
lex: Lexer<'a>, |
|
|
|
|
|
|
|
@ -42,7 +59,7 @@ pub struct Parser<'a> { |
|
|
lookahead: Option<Token<'a>>, |
|
|
lookahead: Option<Token<'a>>, |
|
|
|
|
|
|
|
|
// Location of lookahead.
|
|
|
// Location of lookahead.
|
|
|
location: Location, |
|
|
loc: Location, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Context for resolving references when parsing a single function.
|
|
|
// Context for resolving references when parsing a single function.
|
|
@ -69,10 +86,7 @@ impl Context { |
|
|
// Allocate a new stack slot and add a mapping number -> StackSlot.
|
|
|
// Allocate a new stack slot and add a mapping number -> StackSlot.
|
|
|
fn add_ss(&mut self, number: u32, data: StackSlotData, loc: &Location) -> Result<()> { |
|
|
fn add_ss(&mut self, number: u32, data: StackSlotData, loc: &Location) -> Result<()> { |
|
|
if self.stack_slots.insert(number, self.function.make_stack_slot(data)).is_some() { |
|
|
if self.stack_slots.insert(number, self.function.make_stack_slot(data)).is_some() { |
|
|
Err(Error { |
|
|
err!(loc, "duplicate stack slot: ss{}", number) |
|
|
location: loc.clone(), |
|
|
|
|
|
message: format!("duplicate stack slot: ss{}", number), |
|
|
|
|
|
}) |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
Ok(()) |
|
|
Ok(()) |
|
|
} |
|
|
} |
|
@ -82,10 +96,7 @@ impl Context { |
|
|
fn add_ebb(&mut self, src_ebb: Ebb, loc: &Location) -> Result<Ebb> { |
|
|
fn add_ebb(&mut self, src_ebb: Ebb, loc: &Location) -> Result<Ebb> { |
|
|
let ebb = self.function.make_ebb(); |
|
|
let ebb = self.function.make_ebb(); |
|
|
if self.ebbs.insert(src_ebb, ebb).is_some() { |
|
|
if self.ebbs.insert(src_ebb, ebb).is_some() { |
|
|
Err(Error { |
|
|
err!(loc, "duplicate EBB: {}", src_ebb) |
|
|
location: loc.clone(), |
|
|
|
|
|
message: format!("duplicate EBB: {}", src_ebb), |
|
|
|
|
|
}) |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
Ok(ebb) |
|
|
Ok(ebb) |
|
|
} |
|
|
} |
|
@ -94,10 +105,7 @@ impl Context { |
|
|
// Add a value mapping src_val -> data.
|
|
|
// Add a value mapping src_val -> data.
|
|
|
fn add_value(&mut self, src_val: Value, data: Value, loc: &Location) -> Result<()> { |
|
|
fn add_value(&mut self, src_val: Value, data: Value, loc: &Location) -> Result<()> { |
|
|
if self.values.insert(src_val, data).is_some() { |
|
|
if self.values.insert(src_val, data).is_some() { |
|
|
Err(Error { |
|
|
err!(loc, "duplicate value: {}", src_val) |
|
|
location: loc.clone(), |
|
|
|
|
|
message: format!("duplicate value: {}", src_val), |
|
|
|
|
|
}) |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
Ok(()) |
|
|
Ok(()) |
|
|
} |
|
|
} |
|
@ -111,7 +119,7 @@ impl<'a> Parser<'a> { |
|
|
lex: Lexer::new(text), |
|
|
lex: Lexer::new(text), |
|
|
lex_error: None, |
|
|
lex_error: None, |
|
|
lookahead: None, |
|
|
lookahead: None, |
|
|
location: Location { line_number: 0 }, |
|
|
loc: Location { line_number: 0 }, |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -131,11 +139,11 @@ impl<'a> Parser<'a> { |
|
|
match self.lex.next() { |
|
|
match self.lex.next() { |
|
|
Some(Ok(lexer::LocatedToken { token, location })) => { |
|
|
Some(Ok(lexer::LocatedToken { token, location })) => { |
|
|
self.lookahead = Some(token); |
|
|
self.lookahead = Some(token); |
|
|
self.location = location; |
|
|
self.loc = location; |
|
|
} |
|
|
} |
|
|
Some(Err(lexer::LocatedError { error, location })) => { |
|
|
Some(Err(lexer::LocatedError { error, location })) => { |
|
|
self.lex_error = Some(error); |
|
|
self.lex_error = Some(error); |
|
|
self.location = location; |
|
|
self.loc = location; |
|
|
} |
|
|
} |
|
|
None => {} |
|
|
None => {} |
|
|
} |
|
|
} |
|
@ -143,29 +151,12 @@ impl<'a> Parser<'a> { |
|
|
return self.lookahead; |
|
|
return self.lookahead; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Generate an error.
|
|
|
|
|
|
fn error_string(&self, message: String) -> Error { |
|
|
|
|
|
Error { |
|
|
|
|
|
location: self.location, |
|
|
|
|
|
message: |
|
|
|
|
|
// If we have a lexer error latched, report that.
|
|
|
|
|
|
match self.lex_error { |
|
|
|
|
|
Some(lexer::Error::InvalidChar) => "invalid character".to_string(), |
|
|
|
|
|
None => message, |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn error(&self, message: &str) -> Error { |
|
|
|
|
|
self.error_string(message.to_string()) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 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>> { |
|
|
if self.token() == Some(want) { |
|
|
if self.token() == Some(want) { |
|
|
Ok(self.consume()) |
|
|
Ok(self.consume()) |
|
|
} else { |
|
|
} else { |
|
|
Err(self.error(err_msg)) |
|
|
err!(self.loc, err_msg) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -185,7 +176,7 @@ impl<'a> Parser<'a> { |
|
|
if self.token() == Some(Token::Identifier(want)) { |
|
|
if self.token() == Some(Token::Identifier(want)) { |
|
|
Ok(self.consume()) |
|
|
Ok(self.consume()) |
|
|
} else { |
|
|
} else { |
|
|
Err(self.error(err_msg)) |
|
|
err!(self.loc, err_msg) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -195,7 +186,7 @@ impl<'a> Parser<'a> { |
|
|
self.consume(); |
|
|
self.consume(); |
|
|
Ok(t) |
|
|
Ok(t) |
|
|
} else { |
|
|
} else { |
|
|
Err(self.error(err_msg)) |
|
|
err!(self.loc, err_msg) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -205,7 +196,7 @@ impl<'a> Parser<'a> { |
|
|
self.consume(); |
|
|
self.consume(); |
|
|
Ok(ss) |
|
|
Ok(ss) |
|
|
} else { |
|
|
} else { |
|
|
Err(self.error(err_msg)) |
|
|
err!(self.loc, err_msg) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -215,7 +206,7 @@ impl<'a> Parser<'a> { |
|
|
self.consume(); |
|
|
self.consume(); |
|
|
Ok(ebb) |
|
|
Ok(ebb) |
|
|
} else { |
|
|
} else { |
|
|
Err(self.error(err_msg)) |
|
|
err!(self.loc, err_msg) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -226,7 +217,14 @@ impl<'a> Parser<'a> { |
|
|
self.consume(); |
|
|
self.consume(); |
|
|
Ok(v) |
|
|
Ok(v) |
|
|
} else { |
|
|
} else { |
|
|
Err(self.error(err_msg)) |
|
|
err!(self.loc, err_msg) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn error(&self, message: &str) -> Error { |
|
|
|
|
|
Error { |
|
|
|
|
|
location: self.loc.clone(), |
|
|
|
|
|
message: message.to_string(), |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -238,7 +236,7 @@ impl<'a> Parser<'a> { |
|
|
// Parse it as an Imm64 to check for overflow and other issues.
|
|
|
// Parse it as an Imm64 to check for overflow and other issues.
|
|
|
text.parse().map_err(|e| self.error(e)) |
|
|
text.parse().map_err(|e| self.error(e)) |
|
|
} else { |
|
|
} else { |
|
|
Err(self.error(err_msg)) |
|
|
err!(self.loc, err_msg) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -250,7 +248,7 @@ impl<'a> Parser<'a> { |
|
|
// Parse it as an Ieee32 to check for the right number of digits and other issues.
|
|
|
// Parse it as an Ieee32 to check for the right number of digits and other issues.
|
|
|
text.parse().map_err(|e| self.error(e)) |
|
|
text.parse().map_err(|e| self.error(e)) |
|
|
} else { |
|
|
} else { |
|
|
Err(self.error(err_msg)) |
|
|
err!(self.loc, err_msg) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -262,7 +260,7 @@ impl<'a> Parser<'a> { |
|
|
// Parse it as an Ieee64 to check for the right number of digits and other issues.
|
|
|
// Parse it as an Ieee64 to check for the right number of digits and other issues.
|
|
|
text.parse().map_err(|e| self.error(e)) |
|
|
text.parse().map_err(|e| self.error(e)) |
|
|
} else { |
|
|
} else { |
|
|
Err(self.error(err_msg)) |
|
|
err!(self.loc, err_msg) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -323,7 +321,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.loc, "expected function name"), |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -400,7 +398,7 @@ impl<'a> Parser<'a> { |
|
|
try!(match self.token() { |
|
|
try!(match self.token() { |
|
|
Some(Token::StackSlot(..)) => { |
|
|
Some(Token::StackSlot(..)) => { |
|
|
self.parse_stack_slot_decl() |
|
|
self.parse_stack_slot_decl() |
|
|
.and_then(|(num, dat)| ctx.add_ss(num, dat, &self.location)) |
|
|
.and_then(|(num, dat)| ctx.add_ss(num, dat, &self.loc)) |
|
|
} |
|
|
} |
|
|
// More to come..
|
|
|
// More to come..
|
|
|
_ => return Ok(()), |
|
|
_ => return Ok(()), |
|
@ -419,7 +417,7 @@ impl<'a> Parser<'a> { |
|
|
// stack-slot-decl ::= StackSlot(ss) "=" "stack_slot" * Bytes {"," stack-slot-flag}
|
|
|
// stack-slot-decl ::= StackSlot(ss) "=" "stack_slot" * Bytes {"," stack-slot-flag}
|
|
|
let bytes = try!(self.match_imm64("expected byte-size in stack_slot decl")).to_bits(); |
|
|
let bytes = try!(self.match_imm64("expected byte-size in stack_slot decl")).to_bits(); |
|
|
if bytes > u32::MAX as u64 { |
|
|
if bytes > u32::MAX as u64 { |
|
|
return Err(self.error("stack slot too large")); |
|
|
return err!(self.loc, "stack slot too large"); |
|
|
} |
|
|
} |
|
|
let data = StackSlotData::new(bytes as u32); |
|
|
let data = StackSlotData::new(bytes as u32); |
|
|
|
|
|
|
|
@ -446,11 +444,11 @@ impl<'a> Parser<'a> { |
|
|
fn parse_extended_basic_block(&mut self, ctx: &mut Context) -> Result<()> { |
|
|
fn parse_extended_basic_block(&mut self, ctx: &mut Context) -> Result<()> { |
|
|
let is_entry = self.optional(Token::Entry); |
|
|
let is_entry = self.optional(Token::Entry); |
|
|
let ebb_num = try!(self.match_ebb("expected EBB header")); |
|
|
let ebb_num = try!(self.match_ebb("expected EBB header")); |
|
|
let ebb = try!(ctx.add_ebb(ebb_num, &self.location)); |
|
|
let ebb = try!(ctx.add_ebb(ebb_num, &self.loc)); |
|
|
|
|
|
|
|
|
if is_entry { |
|
|
if is_entry { |
|
|
if ctx.function.entry_block != NO_EBB { |
|
|
if ctx.function.entry_block != NO_EBB { |
|
|
return Err(self.error("multiple entry blocks in function")); |
|
|
return err!(self.loc, "multiple entry blocks in function"); |
|
|
} |
|
|
} |
|
|
ctx.function.entry_block = ebb; |
|
|
ctx.function.entry_block = ebb; |
|
|
} |
|
|
} |
|
@ -503,7 +501,7 @@ impl<'a> Parser<'a> { |
|
|
fn parse_ebb_arg(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> { |
|
|
fn parse_ebb_arg(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> { |
|
|
// ebb-arg ::= * Value(vx) ":" Type(t)
|
|
|
// ebb-arg ::= * Value(vx) ":" Type(t)
|
|
|
let vx = try!(self.match_value("EBB argument must be a value")); |
|
|
let vx = try!(self.match_value("EBB argument must be a value")); |
|
|
let vx_location = self.location; |
|
|
let vx_location = self.loc; |
|
|
// ebb-arg ::= Value(vx) * ":" Type(t)
|
|
|
// ebb-arg ::= Value(vx) * ":" Type(t)
|
|
|
try!(self.match_token(Token::Colon, "expected ':' after EBB argument")); |
|
|
try!(self.match_token(Token::Colon, "expected ':' after EBB argument")); |
|
|
// ebb-arg ::= Value(vx) ":" * Type(t)
|
|
|
// ebb-arg ::= Value(vx) ":" * Type(t)
|
|
@ -541,10 +539,10 @@ impl<'a> Parser<'a> { |
|
|
let opcode = if let Some(Token::Identifier(text)) = self.token() { |
|
|
let opcode = if let Some(Token::Identifier(text)) = self.token() { |
|
|
match text.parse() { |
|
|
match text.parse() { |
|
|
Ok(opc) => opc, |
|
|
Ok(opc) => opc, |
|
|
Err(msg) => return Err(self.error(msg)), |
|
|
Err(msg) => return err!(self.loc, msg), |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
return Err(self.error("expected instruction opcode")); |
|
|
return err!(self.loc, "expected instruction opcode"); |
|
|
}; |
|
|
}; |
|
|
self.consume(); |
|
|
self.consume(); |
|
|
|
|
|
|
|
@ -570,10 +568,10 @@ impl<'a> Parser<'a> { |
|
|
ctx.function.append_inst(ebb, inst); |
|
|
ctx.function.append_inst(ebb, inst); |
|
|
|
|
|
|
|
|
if results.len() != num_results { |
|
|
if results.len() != num_results { |
|
|
let m = format!("instruction produces {} result values, {} given", |
|
|
return err!(self.loc, |
|
|
num_results, |
|
|
"instruction produces {} result values, {} given", |
|
|
results.len()); |
|
|
num_results, |
|
|
return Err(self.error_string(m)); |
|
|
results.len()); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Now map the source result values to the just created instruction results.
|
|
|
// Now map the source result values to the just created instruction results.
|
|
@ -614,14 +612,15 @@ impl<'a> Parser<'a> { |
|
|
ctx.function.value_type(match ctx.values.get(&ctrl_src_value) { |
|
|
ctx.function.value_type(match ctx.values.get(&ctrl_src_value) { |
|
|
Some(&v) => v, |
|
|
Some(&v) => v, |
|
|
None => { |
|
|
None => { |
|
|
let m = format!("cannot determine type of operand {}", ctrl_src_value); |
|
|
return err!(self.loc, |
|
|
return Err(self.error_string(m)); |
|
|
"cannot determine type of operand {}", |
|
|
|
|
|
ctrl_src_value); |
|
|
} |
|
|
} |
|
|
}) |
|
|
}) |
|
|
} else if constraints.is_polymorphic() { |
|
|
} else if constraints.is_polymorphic() { |
|
|
// This opcode does not support type inference, so the explicit type variable
|
|
|
// This opcode does not support type inference, so the explicit type variable
|
|
|
// is required.
|
|
|
// is required.
|
|
|
return Err(self.error("type variable required for polymorphic opcode")); |
|
|
return err!(self.loc, "type variable required for polymorphic opcode"); |
|
|
} else { |
|
|
} else { |
|
|
// This is a non-polymorphic opcode. No typevar needed.
|
|
|
// This is a non-polymorphic opcode. No typevar needed.
|
|
|
VOID |
|
|
VOID |
|
@ -635,13 +634,15 @@ impl<'a> Parser<'a> { |
|
|
if let Some(typeset) = constraints.ctrl_typeset() { |
|
|
if let Some(typeset) = constraints.ctrl_typeset() { |
|
|
// This is a polymorphic opcode.
|
|
|
// This is a polymorphic opcode.
|
|
|
if !typeset.contains(ctrl_type) { |
|
|
if !typeset.contains(ctrl_type) { |
|
|
let m = format!("{} is not a valid typevar for {}", ctrl_type, opcode); |
|
|
return err!(self.loc, |
|
|
return Err(self.error_string(m)); |
|
|
"{} is not a valid typevar for {}", |
|
|
|
|
|
ctrl_type, |
|
|
|
|
|
opcode); |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
// Treat it as a syntax error to speficy a typevar on a non-polymorphic opcode.
|
|
|
// Treat it as a syntax error to speficy a typevar on a non-polymorphic opcode.
|
|
|
if ctrl_type != VOID { |
|
|
if ctrl_type != VOID { |
|
|
return Err(self.error_string(format!("{} does not take a typevar", opcode))); |
|
|
return err!(self.loc, "{} does not take a typevar", opcode); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -659,7 +660,7 @@ impl<'a> Parser<'a> { |
|
|
{ |
|
|
{ |
|
|
for (src, val) in results.zip(new_results) { |
|
|
for (src, val) in results.zip(new_results) { |
|
|
if values.insert(src, val).is_some() { |
|
|
if values.insert(src, val).is_some() { |
|
|
return Err(self.error_string(format!("duplicate result value: {}", src))); |
|
|
return err!(self.loc, "duplicate result value: {}", src); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
Ok(()) |
|
|
Ok(()) |
|
|