mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-10-26 15:13:13 +03:00
Clean up AssemblyBlock parser, fix errors
This commit is contained in:
parent
73c761149f
commit
1036113be9
@ -498,7 +498,7 @@ impl ParserContext<'_> {
|
||||
/// - self
|
||||
///
|
||||
/// Returns an expression error if the token cannot be matched.
|
||||
fn parse_primary_expression(&mut self) -> Result<Expression> {
|
||||
pub fn parse_primary_expression(&mut self) -> Result<Expression> {
|
||||
if let Token::LeftParen = self.token.token {
|
||||
return self.parse_tuple_expression();
|
||||
}
|
||||
|
@ -14,8 +14,9 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
// TODO: Consider designing a separate Parser for instructions. This would improve modularity at the
|
||||
// cost of building/managing the new parser.
|
||||
// TODO: We currently rely on the Leo tokenizer and parser to parse the assembly block.
|
||||
// Consider designing a separate Parser for instructions.
|
||||
// This would improve modularity, reduce the likelihood of errors, improve error handling, at the cost of building, linking, and managing the new parser.
|
||||
// TODO: If snarkVM instructions are used directly, then we should directly use the associated instruction parsers.
|
||||
|
||||
use crate::{ParserContext, Token};
|
||||
@ -25,31 +26,40 @@ use leo_ast::{
|
||||
LessThanOrEqual, Mul, Node, Nop, Not, Operand, Or, Sub, Ternary,
|
||||
};
|
||||
use leo_errors::{ParserError, Result};
|
||||
use leo_span::Span;
|
||||
use leo_span::{sym, Span};
|
||||
|
||||
// TODO: Note that this design is a prototype.
|
||||
impl ParserContext<'_> {
|
||||
pub fn parse_instruction(&mut self) -> Result<Instruction> {
|
||||
// Parse the opcode. Since we are using the Leo tokenizer, the opcode will be tokenized as an identifier.
|
||||
let identifier = self.expect_ident()?;
|
||||
match &*identifier.name.as_str() {
|
||||
"add" => self.parse_add_instruction(identifier.span),
|
||||
"and" => self.parse_and_instruction(identifier.span),
|
||||
"div" => self.parse_div_instruction(identifier.span),
|
||||
"gt" => self.parse_greater_than_instruction(identifier.span),
|
||||
"gte" => self.parse_greater_than_or_equal_instruction(identifier.span),
|
||||
"eq" => self.parse_equal_instruction(identifier.span),
|
||||
"neq" => self.parse_not_equal_instruction(identifier.span),
|
||||
"lt" => self.parse_less_than_instruction(identifier.span),
|
||||
"lte" => self.parse_less_than_or_equal_instruction(identifier.span),
|
||||
"mul" => self.parse_mul_instruction(identifier.span),
|
||||
"not" => self.parse_not_instruction(identifier.span),
|
||||
"or" => self.parse_or_instruction(identifier.span),
|
||||
"sub" => self.parse_sub_instruction(identifier.span),
|
||||
"ter" => self.parse_ternary_instruction(identifier.span),
|
||||
match identifier.name {
|
||||
sym::add => self.parse_add_instruction(identifier.span),
|
||||
sym::and => self.parse_and_instruction(identifier.span),
|
||||
sym::div => self.parse_div_instruction(identifier.span),
|
||||
sym::gt => self.parse_greater_than_instruction(identifier.span),
|
||||
sym::gte => self.parse_greater_than_or_equal_instruction(identifier.span),
|
||||
sym::eq => self.parse_equal_instruction(identifier.span),
|
||||
sym::neq => self.parse_not_equal_instruction(identifier.span),
|
||||
sym::lt => self.parse_less_than_instruction(identifier.span),
|
||||
sym::lte => self.parse_less_than_or_equal_instruction(identifier.span),
|
||||
sym::mul => self.parse_mul_instruction(identifier.span),
|
||||
sym::not => self.parse_not_instruction(identifier.span),
|
||||
sym::or => self.parse_or_instruction(identifier.span),
|
||||
sym::sub => self.parse_sub_instruction(identifier.span),
|
||||
sym::ter => self.parse_ternary_instruction(identifier.span),
|
||||
_ => {
|
||||
self.emit_err(ParserError::invalid_opcode_in_assembly_instruction(identifier.span));
|
||||
// TODO: Do we need to eat tokens here?
|
||||
// Attempt to recover the parser by eating tokens until we find a semi-colon or closing bracket.
|
||||
while !(self.check(&Token::Eof) || self.check(&Token::RightCurly) || self.check(&Token::Semicolon)) {
|
||||
self.bump();
|
||||
}
|
||||
if let Ok(span) = self.expect(&Token::Eof) {
|
||||
self.emit_err(ParserError::unexpected_eof(span));
|
||||
} else if let Ok(span) = self.expect(&Token::RightCurly) {
|
||||
self.emit_err(ParserError::unexpected_end_of_assembly_block(span));
|
||||
} else {
|
||||
self.expect(&Token::Semicolon)?;
|
||||
}
|
||||
Ok(Instruction::Nop(Nop { span: identifier.span }))
|
||||
}
|
||||
}
|
||||
@ -253,18 +263,16 @@ impl ParserContext<'_> {
|
||||
}))
|
||||
}
|
||||
|
||||
// TODO: Better error handling.
|
||||
// Separate tokens and symbols for assembly block.
|
||||
pub fn expect_into(&mut self) -> Result<()> {
|
||||
let identifier = self.expect_ident()?;
|
||||
match &*identifier.name.as_str() {
|
||||
"into" => Ok(()),
|
||||
string => Err(ParserError::unexpected(string, "into", identifier.span).into()),
|
||||
match identifier.name {
|
||||
sym::into => Ok(()),
|
||||
symbol => Err(ParserError::unexpected(symbol.as_str(), "`into`", identifier.span).into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_operand(&mut self) -> Result<Operand> {
|
||||
let expression = self.parse_expression()?;
|
||||
let expression = self.parse_primary_expression()?;
|
||||
match expression {
|
||||
Expression::Identifier(identifier) => Ok(Operand::Identifier(identifier)),
|
||||
Expression::Literal(literal) => Ok(Operand::Literal(literal)),
|
||||
|
@ -426,4 +426,12 @@ create_messages!(
|
||||
msg: format!("Invalid operand in assembly block. Operands must be `Identifier`s or `LiteralExpressions`."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when the parser encountered an unexpected end of assembly block.
|
||||
@formatted
|
||||
unexpected_end_of_assembly_block {
|
||||
args: (),
|
||||
msg: "Unexpected end of assembly block.",
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
@ -137,6 +137,9 @@ symbols! {
|
||||
sub_wrapped,
|
||||
xor,
|
||||
|
||||
// ternary operators
|
||||
ter,
|
||||
|
||||
// core circuits
|
||||
BHP256,
|
||||
BHP512,
|
||||
@ -221,6 +224,9 @@ symbols! {
|
||||
state_leaf,
|
||||
public,
|
||||
private,
|
||||
|
||||
// Assembly specific symbols
|
||||
into,
|
||||
}
|
||||
|
||||
/// An interned string.
|
||||
|
@ -14,81 +14,67 @@ outputs:
|
||||
hi: 11
|
||||
- AssemblyBlock:
|
||||
instructions:
|
||||
- opcode: Add
|
||||
operands:
|
||||
- Identifier: "{\"name\":\"r1\",\"span\":\"{\\\"lo\\\":15,\\\"hi\\\":17}\"}"
|
||||
- Identifier: "{\"name\":\"r2\",\"span\":\"{\\\"lo\\\":18,\\\"hi\\\":20}\"}"
|
||||
destinations:
|
||||
- "{\"name\":\"r3\",\"span\":\"{\\\"lo\\\":26,\\\"hi\\\":28}\"}"
|
||||
span:
|
||||
lo: 11
|
||||
hi: 29
|
||||
- Add:
|
||||
first:
|
||||
Identifier: "{\"name\":\"r1\",\"span\":\"{\\\"lo\\\":15,\\\"hi\\\":17}\"}"
|
||||
second:
|
||||
Identifier: "{\"name\":\"r2\",\"span\":\"{\\\"lo\\\":18,\\\"hi\\\":20}\"}"
|
||||
destination: "{\"name\":\"r3\",\"span\":\"{\\\"lo\\\":26,\\\"hi\\\":28}\"}"
|
||||
span:
|
||||
lo: 11
|
||||
hi: 28
|
||||
span:
|
||||
lo: 0
|
||||
hi: 31
|
||||
- AssemblyBlock:
|
||||
instructions:
|
||||
- opcode: Add
|
||||
operands:
|
||||
- Identifier: "{\"name\":\"r1\",\"span\":\"{\\\"lo\\\":15,\\\"hi\\\":17}\"}"
|
||||
- Identifier: "{\"name\":\"r2\",\"span\":\"{\\\"lo\\\":18,\\\"hi\\\":20}\"}"
|
||||
- Identifier: "{\"name\":\"thisistreatedasanidentifier\",\"span\":\"{\\\"lo\\\":21,\\\"hi\\\":48}\"}"
|
||||
- Identifier: "{\"name\":\"r3\",\"span\":\"{\\\"lo\\\":49,\\\"hi\\\":51}\"}"
|
||||
destinations: []
|
||||
span:
|
||||
lo: 11
|
||||
hi: 52
|
||||
span:
|
||||
lo: 0
|
||||
hi: 54
|
||||
- AssemblyBlock:
|
||||
instructions:
|
||||
- opcode: Add
|
||||
operands:
|
||||
- Identifier: "{\"name\":\"r1\",\"span\":\"{\\\"lo\\\":15,\\\"hi\\\":17}\"}"
|
||||
- Identifier: "{\"name\":\"r2\",\"span\":\"{\\\"lo\\\":18,\\\"hi\\\":20}\"}"
|
||||
destinations:
|
||||
- "{\"name\":\"r3\",\"span\":\"{\\\"lo\\\":26,\\\"hi\\\":28}\"}"
|
||||
span:
|
||||
lo: 11
|
||||
hi: 29
|
||||
- opcode: IsEqual
|
||||
operands:
|
||||
- Identifier: "{\"name\":\"r3\",\"span\":\"{\\\"lo\\\":33,\\\"hi\\\":35}\"}"
|
||||
- Literal:
|
||||
- Add:
|
||||
first:
|
||||
Identifier: "{\"name\":\"r1\",\"span\":\"{\\\"lo\\\":15,\\\"hi\\\":17}\"}"
|
||||
second:
|
||||
Identifier: "{\"name\":\"r2\",\"span\":\"{\\\"lo\\\":18,\\\"hi\\\":20}\"}"
|
||||
destination: "{\"name\":\"r3\",\"span\":\"{\\\"lo\\\":26,\\\"hi\\\":28}\"}"
|
||||
span:
|
||||
lo: 11
|
||||
hi: 28
|
||||
- IsEqual:
|
||||
first:
|
||||
Identifier: "{\"name\":\"r3\",\"span\":\"{\\\"lo\\\":33,\\\"hi\\\":35}\"}"
|
||||
second:
|
||||
Literal:
|
||||
Integer:
|
||||
- U8
|
||||
- "0"
|
||||
- span:
|
||||
lo: 36
|
||||
hi: 39
|
||||
destinations:
|
||||
- "{\"name\":\"r4\",\"span\":\"{\\\"lo\\\":45,\\\"hi\\\":47}\"}"
|
||||
span:
|
||||
lo: 30
|
||||
hi: 48
|
||||
- opcode: Ternary
|
||||
operands:
|
||||
- Identifier: "{\"name\":\"r4\",\"span\":\"{\\\"lo\\\":53,\\\"hi\\\":55}\"}"
|
||||
- Literal:
|
||||
destination: "{\"name\":\"r4\",\"span\":\"{\\\"lo\\\":45,\\\"hi\\\":47}\"}"
|
||||
span:
|
||||
lo: 30
|
||||
hi: 47
|
||||
- Ternary:
|
||||
first:
|
||||
Identifier: "{\"name\":\"r4\",\"span\":\"{\\\"lo\\\":53,\\\"hi\\\":55}\"}"
|
||||
second:
|
||||
Literal:
|
||||
Integer:
|
||||
- U8
|
||||
- "1"
|
||||
- span:
|
||||
lo: 56
|
||||
hi: 59
|
||||
- Literal:
|
||||
third:
|
||||
Literal:
|
||||
Integer:
|
||||
- U8
|
||||
- "2"
|
||||
- span:
|
||||
lo: 60
|
||||
hi: 63
|
||||
destinations:
|
||||
- "{\"name\":\"r5\",\"span\":\"{\\\"lo\\\":69,\\\"hi\\\":71}\"}"
|
||||
span:
|
||||
lo: 49
|
||||
hi: 72
|
||||
destination: "{\"name\":\"r5\",\"span\":\"{\\\"lo\\\":69,\\\"hi\\\":71}\"}"
|
||||
span:
|
||||
lo: 49
|
||||
hi: 71
|
||||
span:
|
||||
lo: 0
|
||||
hi: 74
|
||||
|
@ -6,6 +6,7 @@ outputs:
|
||||
- "Error [EPAR0370009]: unexpected string: expected 'ident', got ']'\n --> test:1:10\n |\n 1 | assembly{]\n | ^"
|
||||
- "Error [EPAR0370005]: expected { -- got '['\n --> test:1:9\n |\n 1 | assembly[]\n | ^"
|
||||
- "Error [EPAR0370005]: expected ; -- got '<eof>'\n --> test:1:11\n |\n 1 | assembli {}\n | ^"
|
||||
- "Error [EPAR0370009]: unexpected string: expected 'ident', got '}'\n --> test:3:1\n |\n 3 | }\n | ^"
|
||||
- "Error [EPAR0370005]: expected ; -- got '}'\n --> test:3:1\n |\n 3 | }\n | ^"
|
||||
- "Error [EPAR0370047]: Invalid opcode in assembly block.\n --> test:2:1\n |\n 2 | thisopcodedoesnotexist r1 r2 into r3;\n | ^^^^^^^^^^^^^^^^^^^^^^"
|
||||
- "Error [EPAR0370048]: Invalid operand in assembly block. Operands must be `Identifier`s or `LiteralExpressions`.\n --> test:2:5\n |\n 2 | add r1 (1u8 + 2u8) into r3;\n | ^^^^^^^^^^^^^^"
|
||||
- "Error [EPAR0370005]: expected `into` -- got 'thishouldbeinto'\n --> test:2:11\n |\n 2 | add r1 r2 thishouldbeinto r3;\n | ^^^^^^^^^^^^^^^"
|
||||
- "Error [EPAR0370048]: Invalid operand in assembly block. Operands must be `Identifier`s or `LiteralExpressions`.\n --> test:2:9\n |\n 2 | add r1 (1u8 + 2u8) into r3;\n | ^^^^^^^^^"
|
||||
|
@ -11,9 +11,6 @@ assembly {
|
||||
add r1 r2 into r3;
|
||||
}
|
||||
|
||||
assembly {
|
||||
add r1 r2 thisistreatedasanidentifier r3;
|
||||
}
|
||||
|
||||
assembly {
|
||||
add r1 r2 into r3;
|
||||
|
@ -19,6 +19,10 @@ assembly {
|
||||
thisopcodedoesnotexist r1 r2 into r3;
|
||||
}
|
||||
|
||||
assembly {
|
||||
add r1 r2 thishouldbeinto r3;
|
||||
}
|
||||
|
||||
assembly {
|
||||
add r1 (1u8 + 2u8) into r3;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user