Make parser compatible with new assembly AST

This commit is contained in:
Pranav Gaddamadugu 2022-06-30 14:46:49 -07:00
parent 3d95d67d78
commit 73c761149f
3 changed files with 290 additions and 93 deletions

View File

@ -24,11 +24,14 @@ pub trait InstructionReconstructor {
// TODO: Remove the associated type if it is not needed.
type AdditionalOutput: Default;
fn reconstruct_literal(&mut self, input: LiteralExpression) -> (LiteralExpression, Self::AdditionalOutput) {
fn reconstruct_instruction_literal(
&mut self,
input: LiteralExpression,
) -> (LiteralExpression, Self::AdditionalOutput) {
(input, Default::default())
}
fn reconstruct_identifier(&mut self, input: Identifier) -> (Identifier, Self::AdditionalOutput) {
fn reconstruct_instruction_identifier(&mut self, input: Identifier) -> (Identifier, Self::AdditionalOutput) {
(input, Default::default())
}
@ -36,11 +39,11 @@ pub trait InstructionReconstructor {
match input {
Operand::Invalid => (Operand::Invalid, Default::default()),
Operand::Identifier(operand) => (
Operand::Identifier(self.reconstruct_identifier(operand).0),
Operand::Identifier(self.reconstruct_instruction_identifier(operand).0),
Default::default(),
),
Operand::Literal(operand) => (
Operand::Literal(self.reconstruct_literal(operand).0),
Operand::Literal(self.reconstruct_instruction_literal(operand).0),
Default::default(),
),
}
@ -71,7 +74,7 @@ pub trait InstructionReconstructor {
Instruction::Add(Add {
first: self.reconstruct_operand(input.first).0,
second: self.reconstruct_operand(input.second).0,
destination: self.reconstruct_identifier(input.destination).0,
destination: self.reconstruct_instruction_identifier(input.destination).0,
span: input.span,
}),
Default::default(),
@ -83,7 +86,7 @@ pub trait InstructionReconstructor {
Instruction::And(And {
first: self.reconstruct_operand(input.first).0,
second: self.reconstruct_operand(input.second).0,
destination: self.reconstruct_identifier(input.destination).0,
destination: self.reconstruct_instruction_identifier(input.destination).0,
span: input.span,
}),
Default::default(),
@ -95,7 +98,7 @@ pub trait InstructionReconstructor {
Instruction::Div(Div {
first: self.reconstruct_operand(input.first).0,
second: self.reconstruct_operand(input.second).0,
destination: self.reconstruct_identifier(input.destination).0,
destination: self.reconstruct_instruction_identifier(input.destination).0,
span: input.span,
}),
Default::default(),
@ -107,7 +110,7 @@ pub trait InstructionReconstructor {
Instruction::GreaterThan(GreaterThan {
first: self.reconstruct_operand(input.first).0,
second: self.reconstruct_operand(input.second).0,
destination: self.reconstruct_identifier(input.destination).0,
destination: self.reconstruct_instruction_identifier(input.destination).0,
span: input.span,
}),
Default::default(),
@ -122,7 +125,7 @@ pub trait InstructionReconstructor {
Instruction::GreaterThanOrEqual(GreaterThanOrEqual {
first: self.reconstruct_operand(input.first).0,
second: self.reconstruct_operand(input.second).0,
destination: self.reconstruct_identifier(input.destination).0,
destination: self.reconstruct_instruction_identifier(input.destination).0,
span: input.span,
}),
Default::default(),
@ -134,7 +137,7 @@ pub trait InstructionReconstructor {
Instruction::IsEqual(IsEqual {
first: self.reconstruct_operand(input.first).0,
second: self.reconstruct_operand(input.second).0,
destination: self.reconstruct_identifier(input.destination).0,
destination: self.reconstruct_instruction_identifier(input.destination).0,
span: input.span,
}),
Default::default(),
@ -146,7 +149,7 @@ pub trait InstructionReconstructor {
Instruction::IsNotEqual(IsNotEqual {
first: self.reconstruct_operand(input.first).0,
second: self.reconstruct_operand(input.second).0,
destination: self.reconstruct_identifier(input.destination).0,
destination: self.reconstruct_instruction_identifier(input.destination).0,
span: input.span,
}),
Default::default(),
@ -158,7 +161,7 @@ pub trait InstructionReconstructor {
Instruction::LessThan(LessThan {
first: self.reconstruct_operand(input.first).0,
second: self.reconstruct_operand(input.second).0,
destination: self.reconstruct_identifier(input.destination).0,
destination: self.reconstruct_instruction_identifier(input.destination).0,
span: input.span,
}),
Default::default(),
@ -173,7 +176,7 @@ pub trait InstructionReconstructor {
Instruction::LessThanOrEqual(LessThanOrEqual {
first: self.reconstruct_operand(input.first).0,
second: self.reconstruct_operand(input.second).0,
destination: self.reconstruct_identifier(input.destination).0,
destination: self.reconstruct_instruction_identifier(input.destination).0,
span: input.span,
}),
Default::default(),
@ -185,7 +188,7 @@ pub trait InstructionReconstructor {
Instruction::Mul(Mul {
first: self.reconstruct_operand(input.first).0,
second: self.reconstruct_operand(input.second).0,
destination: self.reconstruct_identifier(input.destination).0,
destination: self.reconstruct_instruction_identifier(input.destination).0,
span: input.span,
}),
Default::default(),
@ -200,7 +203,7 @@ pub trait InstructionReconstructor {
(
Instruction::Not(Not {
operand: self.reconstruct_operand(input.operand).0,
destination: self.reconstruct_identifier(input.destination).0,
destination: self.reconstruct_instruction_identifier(input.destination).0,
span: input.span,
}),
Default::default(),
@ -212,7 +215,7 @@ pub trait InstructionReconstructor {
Instruction::Or(Or {
first: self.reconstruct_operand(input.first).0,
second: self.reconstruct_operand(input.second).0,
destination: self.reconstruct_identifier(input.destination).0,
destination: self.reconstruct_instruction_identifier(input.destination).0,
span: input.span,
}),
Default::default(),
@ -224,7 +227,7 @@ pub trait InstructionReconstructor {
Instruction::Sub(Sub {
first: self.reconstruct_operand(input.first).0,
second: self.reconstruct_operand(input.second).0,
destination: self.reconstruct_identifier(input.destination).0,
destination: self.reconstruct_instruction_identifier(input.destination).0,
span: input.span,
}),
Default::default(),
@ -237,7 +240,7 @@ pub trait InstructionReconstructor {
first: self.reconstruct_operand(input.first).0,
second: self.reconstruct_operand(input.second).0,
third: self.reconstruct_operand(input.third).0,
destination: self.reconstruct_identifier(input.destination).0,
destination: self.reconstruct_instruction_identifier(input.destination).0,
span: input.span,
}),
Default::default(),

View File

@ -25,7 +25,7 @@ pub trait InstructionVisitor<'a> {
type AdditionalInput: Default;
type Output: Default;
fn visit_literal(
fn visit_instruction_literal(
&mut self,
_input: &'a LiteralExpression,
_additional_input: &Self::AdditionalInput,
@ -33,7 +33,11 @@ pub trait InstructionVisitor<'a> {
Default::default()
}
fn visit_identifier(&mut self, _input: &'a Identifier, _additional_input: &Self::AdditionalInput) -> Self::Output {
fn visit_instruction_identifier(
&mut self,
_input: &'a Identifier,
_additional_input: &Self::AdditionalInput,
) -> Self::Output {
Default::default()
}
@ -44,8 +48,8 @@ pub trait InstructionVisitor<'a> {
fn visit_operand(&mut self, input: &'a Operand, additional: &Self::AdditionalInput) -> Self::Output {
match input {
Operand::Invalid => self.visit_invalid_operand(additional),
Operand::Identifier(operand) => self.visit_identifier(operand, additional),
Operand::Literal(operand) => self.visit_literal(operand, additional),
Operand::Identifier(operand) => self.visit_instruction_identifier(operand, additional),
Operand::Literal(operand) => self.visit_instruction_literal(operand, additional),
}
}
@ -72,21 +76,21 @@ pub trait InstructionVisitor<'a> {
fn visit_add_instruction(&mut self, input: &'a Add, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_operand(&input.first, additional);
self.visit_operand(&input.second, additional);
self.visit_identifier(&input.destination, additional);
self.visit_instruction_identifier(&input.destination, additional);
Default::default()
}
fn visit_and_instruction(&mut self, input: &'a And, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_operand(&input.first, additional);
self.visit_operand(&input.second, additional);
self.visit_identifier(&input.destination, additional);
self.visit_instruction_identifier(&input.destination, additional);
Default::default()
}
fn visit_div_instruction(&mut self, input: &'a Div, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_operand(&input.first, additional);
self.visit_operand(&input.second, additional);
self.visit_identifier(&input.destination, additional);
self.visit_instruction_identifier(&input.destination, additional);
Default::default()
}
@ -97,7 +101,7 @@ pub trait InstructionVisitor<'a> {
) -> Self::Output {
self.visit_operand(&input.first, additional);
self.visit_operand(&input.second, additional);
self.visit_identifier(&input.destination, additional);
self.visit_instruction_identifier(&input.destination, additional);
Default::default()
}
@ -108,14 +112,14 @@ pub trait InstructionVisitor<'a> {
) -> Self::Output {
self.visit_operand(&input.first, additional);
self.visit_operand(&input.second, additional);
self.visit_identifier(&input.destination, additional);
self.visit_instruction_identifier(&input.destination, additional);
Default::default()
}
fn visit_is_equal_instruction(&mut self, input: &'a IsEqual, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_operand(&input.first, additional);
self.visit_operand(&input.second, additional);
self.visit_identifier(&input.destination, additional);
self.visit_instruction_identifier(&input.destination, additional);
Default::default()
}
@ -126,14 +130,14 @@ pub trait InstructionVisitor<'a> {
) -> Self::Output {
self.visit_operand(&input.first, additional);
self.visit_operand(&input.second, additional);
self.visit_identifier(&input.destination, additional);
self.visit_instruction_identifier(&input.destination, additional);
Default::default()
}
fn visit_less_than_instruction(&mut self, input: &'a LessThan, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_operand(&input.first, additional);
self.visit_operand(&input.second, additional);
self.visit_identifier(&input.destination, additional);
self.visit_instruction_identifier(&input.destination, additional);
Default::default()
}
@ -144,14 +148,14 @@ pub trait InstructionVisitor<'a> {
) -> Self::Output {
self.visit_operand(&input.first, additional);
self.visit_operand(&input.second, additional);
self.visit_identifier(&input.destination, additional);
self.visit_instruction_identifier(&input.destination, additional);
Default::default()
}
fn visit_mul_instruction(&mut self, input: &'a Mul, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_operand(&input.first, additional);
self.visit_operand(&input.second, additional);
self.visit_identifier(&input.destination, additional);
self.visit_instruction_identifier(&input.destination, additional);
Default::default()
}
@ -161,21 +165,21 @@ pub trait InstructionVisitor<'a> {
fn visit_not_instruction(&mut self, input: &'a Not, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_operand(&input.operand, additional);
self.visit_identifier(&input.destination, additional);
self.visit_instruction_identifier(&input.destination, additional);
Default::default()
}
fn visit_or_instruction(&mut self, input: &'a Or, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_operand(&input.first, additional);
self.visit_operand(&input.second, additional);
self.visit_identifier(&input.destination, additional);
self.visit_instruction_identifier(&input.destination, additional);
Default::default()
}
fn visit_sub_instruction(&mut self, input: &'a Sub, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_operand(&input.first, additional);
self.visit_operand(&input.second, additional);
self.visit_identifier(&input.destination, additional);
self.visit_instruction_identifier(&input.destination, additional);
Default::default()
}
@ -183,7 +187,7 @@ pub trait InstructionVisitor<'a> {
self.visit_operand(&input.first, additional);
self.visit_operand(&input.second, additional);
self.visit_operand(&input.third, additional);
self.visit_identifier(&input.destination, additional);
self.visit_instruction_identifier(&input.destination, additional);
Default::default()
}
}

View File

@ -19,75 +19,265 @@
// TODO: If snarkVM instructions are used directly, then we should directly use the associated instruction parsers.
use crate::{ParserContext, Token};
use std::process::id;
use leo_ast::{Expression, Instruction, Node, Opcode, Operand};
use leo_ast::{
Add, And, Div, Expression, GreaterThan, GreaterThanOrEqual, Instruction, IsEqual, IsNotEqual, LessThan,
LessThanOrEqual, Mul, Node, Nop, Not, Operand, Or, Sub, Ternary,
};
use leo_errors::{ParserError, Result};
use leo_span::Symbol;
use leo_span::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 opcode_identifer = self.expect_ident()?;
let opcode = match &*opcode_identifer.name.as_str() {
"add" => Opcode::Add,
"and" => Opcode::And,
"div" => Opcode::Div,
"gt" => Opcode::GreaterThan,
"gte" => Opcode::GreaterThanOrEqual,
"eq" => Opcode::IsEqual,
"neq" => Opcode::IsNotEqual,
"lt" => Opcode::LessThan,
"lte" => Opcode::LessThanOrEqual,
"mul" => Opcode::Mul,
"not" => Opcode::Not,
"or" => Opcode::Or,
"sub" => Opcode::Sub,
"ter" => Opcode::Ternary,
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),
_ => {
self.emit_err(ParserError::invalid_opcode_in_assembly_instruction(
opcode_identifer.span,
));
Opcode::Invalid
self.emit_err(ParserError::invalid_opcode_in_assembly_instruction(identifier.span));
// TODO: Do we need to eat tokens here?
Ok(Instruction::Nop(Nop { span: identifier.span }))
}
};
// Parse arguments.
let mut operands = Vec::new();
while !self.check(&Token::Semicolon) {
let expression = self.parse_expression()?;
match expression {
Expression::Identifier(identifier) => match &*identifier.name.as_str() {
"into" => break,
_ => operands.push(Operand::Identifier(identifier)),
},
Expression::Literal(literal) => operands.push(Operand::Literal(literal)),
Expression::Access(..)
| Expression::Binary(..)
| Expression::Call(..)
| Expression::CircuitInit(..)
| Expression::Err(..)
| Expression::Ternary(..)
| Expression::Unary(..) => {
self.emit_err(ParserError::invalid_operand_in_assembly_instruction(expression.span()));
}
};
}
}
// If the next token is the `into` keyword, then we need to parse destinations.
let mut destinations = Vec::new();
while !self.check(&Token::Semicolon) {
destinations.push(self.expect_ident()?)
// TODO: Consider a macro to simplify boilerplate code.
pub fn parse_add_instruction(&mut self, start: Span) -> Result<Instruction> {
let first = self.parse_operand()?;
let second = self.parse_operand()?;
self.expect_into()?;
let destination = self.expect_ident()?;
self.expect(&Token::Semicolon)?;
Ok(Instruction::Add(Add {
first,
second,
destination,
span: start + destination.span,
}))
}
pub fn parse_and_instruction(&mut self, start: Span) -> Result<Instruction> {
let first = self.parse_operand()?;
let second = self.parse_operand()?;
self.expect_into()?;
let destination = self.expect_ident()?;
self.expect(&Token::Semicolon)?;
Ok(Instruction::And(And {
first,
second,
destination,
span: start + destination.span,
}))
}
pub fn parse_div_instruction(&mut self, start: Span) -> Result<Instruction> {
let first = self.parse_operand()?;
let second = self.parse_operand()?;
self.expect_into()?;
let destination = self.expect_ident()?;
self.expect(&Token::Semicolon)?;
Ok(Instruction::Div(Div {
first,
second,
destination,
span: start + destination.span,
}))
}
pub fn parse_greater_than_instruction(&mut self, start: Span) -> Result<Instruction> {
let first = self.parse_operand()?;
let second = self.parse_operand()?;
self.expect_into()?;
let destination = self.expect_ident()?;
self.expect(&Token::Semicolon)?;
Ok(Instruction::GreaterThan(GreaterThan {
first,
second,
destination,
span: start + destination.span,
}))
}
pub fn parse_greater_than_or_equal_instruction(&mut self, start: Span) -> Result<Instruction> {
let first = self.parse_operand()?;
let second = self.parse_operand()?;
self.expect_into()?;
let destination = self.expect_ident()?;
self.expect(&Token::Semicolon)?;
Ok(Instruction::GreaterThanOrEqual(GreaterThanOrEqual {
first,
second,
destination,
span: start + destination.span,
}))
}
pub fn parse_equal_instruction(&mut self, start: Span) -> Result<Instruction> {
let first = self.parse_operand()?;
let second = self.parse_operand()?;
self.expect_into()?;
let destination = self.expect_ident()?;
self.expect(&Token::Semicolon)?;
Ok(Instruction::IsEqual(IsEqual {
first,
second,
destination,
span: start + destination.span,
}))
}
pub fn parse_not_equal_instruction(&mut self, start: Span) -> Result<Instruction> {
let first = self.parse_operand()?;
let second = self.parse_operand()?;
self.expect_into()?;
let destination = self.expect_ident()?;
self.expect(&Token::Semicolon)?;
Ok(Instruction::IsNotEqual(IsNotEqual {
first,
second,
destination,
span: start + destination.span,
}))
}
pub fn parse_less_than_instruction(&mut self, start: Span) -> Result<Instruction> {
let first = self.parse_operand()?;
let second = self.parse_operand()?;
self.expect_into()?;
let destination = self.expect_ident()?;
self.expect(&Token::Semicolon)?;
Ok(Instruction::LessThan(LessThan {
first,
second,
destination,
span: start + destination.span,
}))
}
pub fn parse_less_than_or_equal_instruction(&mut self, start: Span) -> Result<Instruction> {
let first = self.parse_operand()?;
let second = self.parse_operand()?;
self.expect_into()?;
let destination = self.expect_ident()?;
self.expect(&Token::Semicolon)?;
Ok(Instruction::LessThanOrEqual(LessThanOrEqual {
first,
second,
destination,
span: start + destination.span,
}))
}
pub fn parse_mul_instruction(&mut self, start: Span) -> Result<Instruction> {
let first = self.parse_operand()?;
let second = self.parse_operand()?;
self.expect_into()?;
let destination = self.expect_ident()?;
self.expect(&Token::Semicolon)?;
Ok(Instruction::Mul(Mul {
first,
second,
destination,
span: start + destination.span,
}))
}
pub fn parse_not_instruction(&mut self, start: Span) -> Result<Instruction> {
let operand = self.parse_operand()?;
self.expect_into()?;
let destination = self.expect_ident()?;
self.expect(&Token::Semicolon)?;
Ok(Instruction::Not(Not {
operand,
destination,
span: start + destination.span,
}))
}
pub fn parse_or_instruction(&mut self, start: Span) -> Result<Instruction> {
let first = self.parse_operand()?;
let second = self.parse_operand()?;
self.expect_into()?;
let destination = self.expect_ident()?;
self.expect(&Token::Semicolon)?;
Ok(Instruction::Or(Or {
first,
second,
destination,
span: start + destination.span,
}))
}
pub fn parse_sub_instruction(&mut self, start: Span) -> Result<Instruction> {
let first = self.parse_operand()?;
let second = self.parse_operand()?;
self.expect_into()?;
let destination = self.expect_ident()?;
self.expect(&Token::Semicolon)?;
Ok(Instruction::Sub(Sub {
first,
second,
destination,
span: start + destination.span,
}))
}
pub fn parse_ternary_instruction(&mut self, start: Span) -> Result<Instruction> {
let first = self.parse_operand()?;
let second = self.parse_operand()?;
let third = self.parse_operand()?;
self.expect_into()?;
let destination = self.expect_ident()?;
self.expect(&Token::Semicolon)?;
Ok(Instruction::Ternary(Ternary {
first,
second,
third,
destination,
span: start + destination.span,
}))
}
// 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()),
}
}
let end_span = self.expect(&Token::Semicolon)?;
Ok(Instruction {
opcode,
operands,
destinations,
span: opcode_identifer.span + end_span,
})
pub fn parse_operand(&mut self) -> Result<Operand> {
let expression = self.parse_expression()?;
match expression {
Expression::Identifier(identifier) => Ok(Operand::Identifier(identifier)),
Expression::Literal(literal) => Ok(Operand::Literal(literal)),
Expression::Access(..)
| Expression::Binary(..)
| Expression::Call(..)
| Expression::CircuitInit(..)
| Expression::Err(..)
| Expression::Ternary(..)
| Expression::Unary(..) => {
self.emit_err(ParserError::invalid_operand_in_assembly_instruction(expression.span()));
Ok(Operand::Invalid)
}
}
}
}