- implementation of <var> <op> = <expr> type statements such as `x +=
5` - implementation of logical and shift operations in parser and codegen. - implementation of sizeof keyword as unary operator in progress (non functional) - implementation of prefix and postfix inc/dec operators - array access by index (implemented, untested as arrays aren't implemented yet). essentially just a pointer write with offset. - struct/member access (parsing implemented, untested.)
This commit is contained in:
@@ -9,8 +9,8 @@ use crate::backend::dsa::registers::Register;
|
||||
use crate::{block, comment, dsa};
|
||||
|
||||
use crate::model::{
|
||||
BinaryOperator, Call, CompilerError, ConstExpr, Declaration, Dependency, Expression,
|
||||
Program, Statement, TypeId, UnaryOperator, Variable,
|
||||
AssignmentOperator, BinaryOperator, Call, CompilerError, ConstExpr, Declaration,
|
||||
Dependency, Expression, Program, Statement, TypeId, UnaryOperator, Variable,
|
||||
};
|
||||
|
||||
pub struct CodeGenerator {
|
||||
@@ -271,24 +271,106 @@ impl CodeGenerator {
|
||||
self.allocator.free_temp(ptr_reg);
|
||||
}
|
||||
|
||||
Statement::Assign { varname, value } => {
|
||||
Statement::Assign {
|
||||
varname,
|
||||
value,
|
||||
operator,
|
||||
} => {
|
||||
// Evaluate expression
|
||||
let (result_reg, expr_code) =
|
||||
self.generate_expression(value, true, func_body)?;
|
||||
code.extend(expr_code);
|
||||
|
||||
if *operator == AssignmentOperator::Assign {
|
||||
// Check if this is a global variable
|
||||
if self.is_global(varname) {
|
||||
// Store to global label
|
||||
code.push(format!("\tstw {}, {}", result_reg, varname));
|
||||
} else {
|
||||
// Store result in local variable
|
||||
let store_code = self.allocator.store_var(varname, &result_reg);
|
||||
code.extend(store_code);
|
||||
}
|
||||
|
||||
// Free temporary register
|
||||
self.allocator.free_temp(result_reg);
|
||||
|
||||
return Ok(code);
|
||||
}
|
||||
|
||||
// for more complex assignment cases we need an intermediate register.
|
||||
let (temp_reg, temp_code) = self.allocator.alloc_temp()?;
|
||||
code.extend(temp_code);
|
||||
|
||||
// fetch the value of the variable
|
||||
let (var_reg, var_code) = if self.is_global(varname) {
|
||||
(temp_reg, vec![format!("\tldw {}, {}", varname, temp_reg)])
|
||||
} else {
|
||||
self.allocator.load_var(varname)?
|
||||
};
|
||||
code.extend(var_code);
|
||||
|
||||
let assign_code = match operator {
|
||||
AssignmentOperator::Assign => {
|
||||
unreachable!("assignment was already checked earlier.")
|
||||
}
|
||||
AssignmentOperator::AddAssign => {
|
||||
format!("\tadd {var_reg}, {result_reg}, {temp_reg}")
|
||||
}
|
||||
AssignmentOperator::SubAssign => {
|
||||
format!("\tsub {var_reg}, {result_reg}, {temp_reg}")
|
||||
}
|
||||
AssignmentOperator::MulAssign => {
|
||||
return Err(CompilerError::Unimplemented(format!(
|
||||
"TODO: implement multiplication for assignment"
|
||||
)));
|
||||
}
|
||||
AssignmentOperator::DivAssign => {
|
||||
return Err(CompilerError::Unimplemented(format!(
|
||||
"TODO: write proper div function for DSA"
|
||||
)));
|
||||
}
|
||||
AssignmentOperator::ModAssign => {
|
||||
format!("\tmod {var_reg}, {result_reg}, {temp_reg}")
|
||||
}
|
||||
AssignmentOperator::AndAssign => {
|
||||
format!("\tand {var_reg}, {result_reg}, {temp_reg}")
|
||||
}
|
||||
AssignmentOperator::OrAssign => {
|
||||
format!("\tor {var_reg}, {result_reg}, {temp_reg}")
|
||||
}
|
||||
AssignmentOperator::XorAssign => {
|
||||
format!("\txor {var_reg}, {result_reg}, {temp_reg}")
|
||||
}
|
||||
AssignmentOperator::LeftShiftAssign => {
|
||||
// this is only useful if we optimise out the register allocation
|
||||
// inside value. if let Expression::Number
|
||||
// { value, .. } = *value { format!("\
|
||||
// tshl {var_reg}, {value}, {temp_reg}") }
|
||||
format!("\tshl {var_reg}, {result_reg}, 0, {temp_reg}")
|
||||
}
|
||||
AssignmentOperator::RightShiftAssign => {
|
||||
// this is only useful if we optimise out the register allocation
|
||||
// if let Expression::Number { value, .. } = *value {
|
||||
// format!("\tshr {var_reg}, {value}, {temp_reg}")
|
||||
// }
|
||||
format!("\tshr {var_reg}, {result_reg}, 0, {temp_reg}")
|
||||
}
|
||||
};
|
||||
code.push(assign_code);
|
||||
|
||||
// Check if this is a global variable
|
||||
if self.is_global(varname) {
|
||||
// Store to global label
|
||||
code.push(format!("\tstw {}, {}", result_reg, varname));
|
||||
code.push(format!("\tstw {}, {}", temp_reg, varname));
|
||||
} else {
|
||||
// Store result in local variable
|
||||
let store_code = self.allocator.store_var(varname, &result_reg);
|
||||
let store_code = self.allocator.store_var(varname, &temp_reg);
|
||||
code.extend(store_code);
|
||||
}
|
||||
|
||||
// Free temporary register
|
||||
self.allocator.free_temp(result_reg);
|
||||
self.allocator.free_temp(temp_reg);
|
||||
}
|
||||
|
||||
Statement::Return(expr) => {
|
||||
@@ -414,16 +496,17 @@ impl CodeGenerator {
|
||||
let mut code = Vec::new();
|
||||
|
||||
match expr {
|
||||
Expression::StringLiteral(value) => {
|
||||
Expression::Empty => Ok((Register::Null, code)),
|
||||
|
||||
Expression::Number { value, .. } => {
|
||||
let (reg, alloc_code) = self.allocator.alloc_temp()?;
|
||||
code.extend(alloc_code);
|
||||
|
||||
// write string into memory
|
||||
let uuid = self.get_unique_label();
|
||||
func_body.insert(0, format!("db str_{uuid}: \"{value}\""));
|
||||
|
||||
// Load pointer to string
|
||||
code.push(format!("\tlwi str_{uuid}, {reg}"));
|
||||
// Load immediate value
|
||||
code.push(format!("\tlli {}, {}", value & 0xFFFF, reg));
|
||||
if *value > 0xFFFF || *value < 0 {
|
||||
code.push(format!("\tlui {}, {}", (value >> 16) & 0xFFFF, reg));
|
||||
}
|
||||
|
||||
Ok((reg, code))
|
||||
}
|
||||
@@ -438,19 +521,22 @@ impl CodeGenerator {
|
||||
Ok((reg, code))
|
||||
}
|
||||
|
||||
Expression::Number { value, .. } => {
|
||||
Expression::StringLiteral(value) => {
|
||||
let (reg, alloc_code) = self.allocator.alloc_temp()?;
|
||||
code.extend(alloc_code);
|
||||
|
||||
// Load immediate value
|
||||
code.push(format!("\tlli {}, {}", value & 0xFFFF, reg));
|
||||
if *value > 0xFFFF || *value < 0 {
|
||||
code.push(format!("\tlui {}, {}", (value >> 16) & 0xFFFF, reg));
|
||||
}
|
||||
// write string into memory
|
||||
let uuid = self.get_unique_label();
|
||||
func_body.insert(0, format!("db str_{uuid}: \"{value}\""));
|
||||
|
||||
// Load pointer to string
|
||||
code.push(format!("\tlwi str_{uuid}, {reg}"));
|
||||
|
||||
Ok((reg, code))
|
||||
}
|
||||
|
||||
Expression::ArrayLiteral { elements, type_id } => todo!(),
|
||||
|
||||
Expression::Variable { name, .. } => {
|
||||
if self.is_global(&name.name) {
|
||||
// Allocate a temporary register for the global
|
||||
@@ -489,16 +575,14 @@ impl CodeGenerator {
|
||||
// Generate operation
|
||||
match op {
|
||||
BinaryOperator::Add => {
|
||||
code.push(format!(
|
||||
"\tadd {}, {}, {}",
|
||||
left_reg, right_reg, result_reg
|
||||
));
|
||||
code.push(
|
||||
format!("\tadd {left_reg}, {right_reg}, {result_reg}",),
|
||||
);
|
||||
}
|
||||
BinaryOperator::Sub => {
|
||||
code.push(format!(
|
||||
"\tsub {}, {}, {}",
|
||||
left_reg, right_reg, result_reg
|
||||
));
|
||||
code.push(
|
||||
format!("\tsub {left_reg}, {right_reg}, {result_reg}",),
|
||||
);
|
||||
}
|
||||
BinaryOperator::Mul => {
|
||||
self.include("maths", "./lib/maths/core.dsa");
|
||||
@@ -509,6 +593,53 @@ impl CodeGenerator {
|
||||
code.push(format!("\tpop {}", result_reg));
|
||||
code.push("\tpop zero".to_string());
|
||||
}
|
||||
BinaryOperator::Div => {
|
||||
return Err(CompilerError::Unimplemented(format!(
|
||||
"TODO: write proper div function for DSA"
|
||||
)));
|
||||
// self.include("maths", "./lib/maths/core.dsa");
|
||||
// // Call divide function
|
||||
// code.push(format!("\tpush {}", right_reg));
|
||||
// code.push(format!("\tpush {}", left_reg));
|
||||
// code.push("\tcall maths::divide".to_string());
|
||||
// code.push(format!("\tpop {}", result_reg));
|
||||
// code.push("\tpop zero".to_string());
|
||||
}
|
||||
BinaryOperator::Mod => {
|
||||
return Err(CompilerError::Unimplemented(format!(
|
||||
"TODO: write proper mod function for DSA"
|
||||
)));
|
||||
// self.include("maths", "./lib/maths/core.dsa");
|
||||
// // Call modulo function
|
||||
// code.push(format!("\tpush {}", right_reg));
|
||||
// code.push(format!("\tpush {}", left_reg));
|
||||
// code.push("\tcall maths::modulo".to_string());
|
||||
// code.push(format!("\tpop {}", result_reg));
|
||||
// code.push("\tpop zero".to_string());
|
||||
}
|
||||
BinaryOperator::BitwiseAnd => {
|
||||
code.push(format!("\tand {left_reg}, {right_reg}, {result_reg}"));
|
||||
}
|
||||
BinaryOperator::BitwiseOr => {
|
||||
code.push(format!("\tor {left_reg}, {right_reg}, {result_reg}"));
|
||||
}
|
||||
BinaryOperator::BitwiseXor => {
|
||||
code.push(format!("\txor {left_reg}, {right_reg}, {result_reg}"));
|
||||
}
|
||||
BinaryOperator::LogicalAnd => {
|
||||
return Err(CompilerError::Unimplemented(format!(
|
||||
"assembler/ISA does not yet support logical and!"
|
||||
)));
|
||||
}
|
||||
BinaryOperator::LogicalOr => {
|
||||
return Err(CompilerError::Unimplemented(format!(
|
||||
"assembler/ISA does not yet support logical or!"
|
||||
)));
|
||||
}
|
||||
BinaryOperator::LeftShift => code
|
||||
.push(format!("\tshl {left_reg}, {right_reg}, 0, {result_reg}")),
|
||||
BinaryOperator::RightShift => code
|
||||
.push(format!("\tshr {left_reg}, {right_reg}, 0, {result_reg}")),
|
||||
// Comparison operators - return 1 (true) or 0 (false)
|
||||
BinaryOperator::Equal => {
|
||||
code.push(format!("\tcmp {}, {}", left_reg, right_reg));
|
||||
@@ -557,8 +688,7 @@ impl CodeGenerator {
|
||||
code.push(format!("\tjge {}", end_label));
|
||||
code.push(format!("\tlli 8, {}", result_reg));
|
||||
code.push(format!("{}:", end_label));
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
} // _ => unimplemented!(),
|
||||
}
|
||||
|
||||
// Free operand registers (allocator will protect variables)
|
||||
@@ -568,6 +698,105 @@ impl CodeGenerator {
|
||||
Ok((result_reg, code))
|
||||
}
|
||||
|
||||
Expression::UnaryPostfix { op, operand, .. } => {
|
||||
let (operand_reg, operand_code) =
|
||||
self.generate_expression(operand, true, func_body)?;
|
||||
code.extend(operand_code);
|
||||
|
||||
let (result_reg, result_alloc) = self.allocator.alloc_temp()?;
|
||||
code.extend(result_alloc);
|
||||
|
||||
match op {
|
||||
UnaryOperator::Increment => {
|
||||
// prefix increment
|
||||
// code.push(format!("\taddi {}, 1, {}", operand_reg,
|
||||
// operand_reg));
|
||||
code.push(format!("\tmov {}, {}", operand_reg, result_reg));
|
||||
}
|
||||
UnaryOperator::Decrement => {
|
||||
// prefix decrement
|
||||
// code.push(format!("\tsubi {}, 1, {}", operand_reg,
|
||||
// operand_reg));
|
||||
code.push(format!("\tmov {}, {}", operand_reg, result_reg));
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilerError::Generic(format!(
|
||||
"{op} is prefix only!"
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
self.allocator.free_temp(operand_reg);
|
||||
Ok((result_reg, code))
|
||||
}
|
||||
|
||||
Expression::Unary { op, operand, .. } => {
|
||||
let (operand_reg, operand_code) =
|
||||
self.generate_expression(operand, true, func_body)?;
|
||||
code.extend(operand_code);
|
||||
|
||||
let (result_reg, result_alloc) = self.allocator.alloc_temp()?;
|
||||
code.extend(result_alloc);
|
||||
|
||||
match op {
|
||||
UnaryOperator::Minus => {
|
||||
// Negate: result = 0 - operand
|
||||
code.push(format!("\tsub zero, {}, {}", operand_reg, result_reg));
|
||||
}
|
||||
UnaryOperator::Plus => {
|
||||
// Just move
|
||||
code.push(format!("\tmov {}, {}", operand_reg, result_reg));
|
||||
}
|
||||
UnaryOperator::Dereference => {
|
||||
code.push(format!("\tldw {}, {}", operand_reg, result_reg));
|
||||
}
|
||||
UnaryOperator::AddressOf => {
|
||||
// ensure the referenced variable is on the stack and return its
|
||||
// address.
|
||||
let (offset, alloc_code) =
|
||||
self.allocator.free_register(&operand_reg)?;
|
||||
code.extend(alloc_code);
|
||||
code.push(format!(
|
||||
"\taddi spr, {}, {}",
|
||||
offset - self.allocator.get_stack_offset(),
|
||||
result_reg
|
||||
));
|
||||
}
|
||||
UnaryOperator::SizeOf => {
|
||||
if let Ok(id) = operand.type_id() {
|
||||
let size = id.size();
|
||||
code.push(format!("\tmov {}, {}", size, result_reg));
|
||||
}
|
||||
}
|
||||
UnaryOperator::Increment => {
|
||||
// prefix increment
|
||||
// code.push(format!("\tmov {}, {}", operand_reg, result_reg));
|
||||
code.push(format!("\taddi {}, 1, {}", operand_reg, result_reg));
|
||||
}
|
||||
UnaryOperator::Decrement => {
|
||||
// prefix decrement
|
||||
// code.push(format!("\tmov {}, {}", operand_reg, result_reg));
|
||||
code.push(format!("\tsubi {}, 1, {}", operand_reg, result_reg));
|
||||
}
|
||||
UnaryOperator::BitwiseNot => {
|
||||
code.push(format!("\tnot {}, {}", operand_reg, result_reg));
|
||||
}
|
||||
UnaryOperator::LogicalNot => {
|
||||
return Err(CompilerError::Unimplemented(format!(
|
||||
"Assembler/ISA does not yet support logical not"
|
||||
)));
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilerError::Generic(format!(
|
||||
"{op} is postfix only!"
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
self.allocator.free_temp(operand_reg);
|
||||
Ok((result_reg, code))
|
||||
}
|
||||
|
||||
Expression::Call {
|
||||
func: Call { name, args },
|
||||
..
|
||||
@@ -642,69 +871,52 @@ impl CodeGenerator {
|
||||
Ok((result_reg, code))
|
||||
}
|
||||
|
||||
Expression::Unary { op, operand, .. } => {
|
||||
let (operand_reg, operand_code) =
|
||||
self.generate_expression(operand, true, func_body)?;
|
||||
code.extend(operand_code);
|
||||
Expression::IndexAccess {
|
||||
expr,
|
||||
index,
|
||||
type_id,
|
||||
} => {
|
||||
let (expr_reg, expr_alloc) =
|
||||
self.generate_expression(expr, true, func_body)?;
|
||||
code.extend(expr_alloc);
|
||||
|
||||
let (index_reg, index_alloc) =
|
||||
self.generate_expression(index, true, func_body)?;
|
||||
code.extend(index_alloc);
|
||||
|
||||
let (result_reg, result_alloc) = self.allocator.alloc_temp()?;
|
||||
code.extend(result_alloc);
|
||||
|
||||
match op {
|
||||
UnaryOperator::Minus => {
|
||||
// Negate: result = 0 - operand
|
||||
code.push(format!("\tsub zero, {}, {}", operand_reg, result_reg));
|
||||
}
|
||||
UnaryOperator::Plus => {
|
||||
// Just move
|
||||
code.push(format!("\tmov {}, {}", operand_reg, result_reg));
|
||||
}
|
||||
UnaryOperator::Dereference => {
|
||||
code.push(format!("\tldw {}, {}", operand_reg, result_reg));
|
||||
}
|
||||
UnaryOperator::AddressOf => {
|
||||
// ensure the referenced variable is on the stack and return its
|
||||
// address.
|
||||
let (offset, alloc_code) =
|
||||
self.allocator.free_register(&operand_reg)?;
|
||||
code.extend(alloc_code);
|
||||
code.push(format!(
|
||||
"\taddi spr, {}, {}",
|
||||
offset - self.allocator.get_stack_offset(),
|
||||
result_reg
|
||||
));
|
||||
}
|
||||
UnaryOperator::SizeOf => {
|
||||
if let Ok(id) = operand.type_id() {
|
||||
let size = id.size();
|
||||
code.push(format!("\tmov {}, {}", size, result_reg));
|
||||
}
|
||||
}
|
||||
UnaryOperator::CastAs => {} /* this should be removed once the */
|
||||
// semantic analyser can handle it!
|
||||
UnaryOperator::Increment => {
|
||||
// prefix increment
|
||||
code.push(format!("\tmov {}, {}", operand_reg, result_reg));
|
||||
code.push(format!("\taddi {}, {}, 1", operand_reg, operand_reg));
|
||||
}
|
||||
UnaryOperator::Decrement => {
|
||||
// prefix decrement
|
||||
code.push(format!("\tmov {}, {}", operand_reg, result_reg));
|
||||
code.push(format!("\tsubi {}, {}, 1", operand_reg, operand_reg));
|
||||
}
|
||||
UnaryOperator::BitwiseNot => {
|
||||
code.push(format!("\tnot {}, {}", operand_reg, result_reg));
|
||||
}
|
||||
UnaryOperator::LogicalNot => unimplemented!(),
|
||||
}
|
||||
// add the expr pointer to the index to get the final address.
|
||||
code.push(format!("\tadd {expr_reg} {index_reg} {result_reg}"));
|
||||
// load the value at the address.
|
||||
code.push(format!("\tldw {result_reg} {result_reg}"));
|
||||
|
||||
self.allocator.free_temp(expr_reg);
|
||||
self.allocator.free_temp(index_reg);
|
||||
|
||||
self.allocator.free_temp(operand_reg);
|
||||
Ok((result_reg, code))
|
||||
}
|
||||
Expression::MemberAccess {
|
||||
expr,
|
||||
field_name,
|
||||
type_id,
|
||||
} => Err(CompilerError::Unimplemented(format!(
|
||||
"Structs are not yet implemented!"
|
||||
))),
|
||||
|
||||
Expression::Empty => Ok((Register::Null, code)),
|
||||
Expression::TypeCast {
|
||||
expr,
|
||||
target_type,
|
||||
type_id,
|
||||
} => {
|
||||
let (expr_reg, expr_code) =
|
||||
self.generate_expression(expr, true, func_body)?;
|
||||
|
||||
_ => unimplemented!(),
|
||||
// not sure if we actually need to do anything here.
|
||||
// for now we just return the previous expression.
|
||||
Ok((expr_reg, expr_code))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use super::lexer::Token;
|
||||
use crate::model::{
|
||||
BinaryOperator, Block, Call, CompilerError, ConstExpr, Declaration, Dependency,
|
||||
Expression, Program, Statement, TypeId, UnaryOperator, Variable,
|
||||
AssignmentOperator, BinaryOperator, Block, Call, CompilerError, ConstExpr,
|
||||
Declaration, Dependency, Expression, Program, Statement, TypeId, UnaryOperator,
|
||||
Variable,
|
||||
};
|
||||
use crate::{expect_tt, expect_value};
|
||||
use std::ops::{ControlFlow, FromResidual, Try};
|
||||
@@ -328,7 +329,26 @@ impl Parser {
|
||||
}
|
||||
|
||||
self.next()?;
|
||||
let _ = expect_tt!(self.next()?, Assign)?;
|
||||
let operator = match self.peek_next()? {
|
||||
Token::Assign => AssignmentOperator::Assign,
|
||||
Token::PlusEqual => AssignmentOperator::AddAssign,
|
||||
Token::MinusEqual => AssignmentOperator::SubAssign,
|
||||
Token::StarEqual => AssignmentOperator::MulAssign,
|
||||
Token::SlashEqual => AssignmentOperator::DivAssign,
|
||||
Token::PercentEqual => AssignmentOperator::ModAssign,
|
||||
Token::AndEqual => AssignmentOperator::AndAssign,
|
||||
Token::OrEqual => AssignmentOperator::OrAssign,
|
||||
Token::XorEqual => AssignmentOperator::XorAssign,
|
||||
Token::ShlEqual => AssignmentOperator::LeftShiftAssign,
|
||||
Token::ShrEqual => AssignmentOperator::RightShiftAssign,
|
||||
_ => {
|
||||
return ParseResult::Reject(CompilerError::UnexpectedToken(
|
||||
self.peek_next()?.tt().to_string(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
self.next()?;
|
||||
|
||||
let value = self.parse_expression()?;
|
||||
|
||||
@@ -336,6 +356,7 @@ impl Parser {
|
||||
|
||||
return ParseResult::Accept(Statement::Assign {
|
||||
varname: varname.name,
|
||||
operator,
|
||||
value,
|
||||
});
|
||||
}
|
||||
@@ -346,32 +367,132 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn parse_expression(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||
self.parse_comparison()
|
||||
self.parse_logical_or()
|
||||
}
|
||||
|
||||
fn parse_logical_or(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||
let left = self.parse_logical_and()?;
|
||||
|
||||
let op = match self.peek_next()? {
|
||||
Token::Ampersand => BinaryOperator::LogicalOr,
|
||||
_ => return ParseResult::Accept(left),
|
||||
};
|
||||
|
||||
self.next()?;
|
||||
ParseResult::Accept(Expression::Binary {
|
||||
op,
|
||||
left: Box::new(left),
|
||||
right: Box::new(self.parse_logical_or()?),
|
||||
type_id: Some(TypeId::U32),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_logical_and(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||
let left = self.parse_bitwise_or()?;
|
||||
|
||||
let op = match self.peek_next()? {
|
||||
Token::Ampersand => BinaryOperator::LogicalAnd,
|
||||
_ => return ParseResult::Accept(left),
|
||||
};
|
||||
|
||||
self.next()?;
|
||||
ParseResult::Accept(Expression::Binary {
|
||||
op,
|
||||
left: Box::new(left),
|
||||
right: Box::new(self.parse_logical_and()?),
|
||||
type_id: Some(TypeId::U32),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_bitwise_or(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||
let left = self.parse_bitwise_xor()?;
|
||||
|
||||
let op = match self.peek_next()? {
|
||||
Token::Ampersand => BinaryOperator::BitwiseOr,
|
||||
_ => return ParseResult::Accept(left),
|
||||
};
|
||||
|
||||
self.next()?;
|
||||
ParseResult::Accept(Expression::Binary {
|
||||
op,
|
||||
left: Box::new(left),
|
||||
right: Box::new(self.parse_bitwise_or()?),
|
||||
type_id: Some(TypeId::U32),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_bitwise_xor(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||
let left = self.parse_bitwise_and()?;
|
||||
|
||||
let op = match self.peek_next()? {
|
||||
Token::Ampersand => BinaryOperator::BitwiseXor,
|
||||
_ => return ParseResult::Accept(left),
|
||||
};
|
||||
|
||||
self.next()?;
|
||||
ParseResult::Accept(Expression::Binary {
|
||||
op,
|
||||
left: Box::new(left),
|
||||
right: Box::new(self.parse_bitwise_xor()?),
|
||||
type_id: Some(TypeId::U32),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_bitwise_and(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||
let left = self.parse_comparison()?;
|
||||
|
||||
let op = match self.peek_next()? {
|
||||
Token::Ampersand => BinaryOperator::BitwiseAnd,
|
||||
_ => return ParseResult::Accept(left),
|
||||
};
|
||||
|
||||
self.next()?;
|
||||
ParseResult::Accept(Expression::Binary {
|
||||
op,
|
||||
left: Box::new(left),
|
||||
right: Box::new(self.parse_bitwise_and()?),
|
||||
type_id: Some(TypeId::U32),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_comparison(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||
let mut expr = self.parse_additive()?;
|
||||
let left = self.parse_shift()?;
|
||||
|
||||
while let Some(op) = match self.peek_next()? {
|
||||
Token::EqualEqual => Some(BinaryOperator::Equal),
|
||||
Token::BangEqual => Some(BinaryOperator::NotEqual),
|
||||
Token::Less => Some(BinaryOperator::LessThan),
|
||||
Token::Greater => Some(BinaryOperator::GreaterThan),
|
||||
Token::LessEqual => Some(BinaryOperator::LessOrEqual),
|
||||
Token::GreaterEqual => Some(BinaryOperator::GreaterOrEqual),
|
||||
_ => None,
|
||||
} {
|
||||
self.next()?;
|
||||
let right = Box::new(self.parse_additive()?);
|
||||
expr = Expression::Binary {
|
||||
op,
|
||||
left: Box::new(expr),
|
||||
right,
|
||||
type_id: Some(TypeId::Bool),
|
||||
};
|
||||
}
|
||||
let op = match self.peek_next()? {
|
||||
Token::EqualEqual => BinaryOperator::Equal,
|
||||
Token::BangEqual => BinaryOperator::NotEqual,
|
||||
Token::Less => BinaryOperator::LessThan,
|
||||
Token::Greater => BinaryOperator::GreaterThan,
|
||||
Token::LessEqual => BinaryOperator::LessOrEqual,
|
||||
Token::GreaterEqual => BinaryOperator::GreaterOrEqual,
|
||||
_ => return ParseResult::Accept(left),
|
||||
};
|
||||
|
||||
ParseResult::Accept(expr)
|
||||
self.next()?;
|
||||
ParseResult::Accept(Expression::Binary {
|
||||
op,
|
||||
left: Box::new(left),
|
||||
right: Box::new(self.parse_comparison()?),
|
||||
type_id: Some(TypeId::Bool),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_shift(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||
let left = self.parse_additive()?;
|
||||
|
||||
let op = match self.peek_next()? {
|
||||
Token::LeftShift => BinaryOperator::LeftShift,
|
||||
Token::RightShift => BinaryOperator::RightShift,
|
||||
_ => return ParseResult::Accept(left),
|
||||
};
|
||||
|
||||
self.next()?;
|
||||
ParseResult::Accept(Expression::Binary {
|
||||
op,
|
||||
left: Box::new(left),
|
||||
right: Box::new(self.parse_shift()?),
|
||||
type_id: Some(TypeId::U32),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_additive(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||
|
||||
+17
-2
@@ -11,6 +11,7 @@ pub enum CompilerError {
|
||||
Generic(String),
|
||||
UnknownType,
|
||||
TypeMismatch(TypeId, TypeId),
|
||||
Unimplemented(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
@@ -130,6 +131,7 @@ pub enum Statement {
|
||||
},
|
||||
Assign {
|
||||
varname: String,
|
||||
operator: AssignmentOperator,
|
||||
value: Expression,
|
||||
},
|
||||
PtrWrite {
|
||||
@@ -308,6 +310,21 @@ impl Expression {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum AssignmentOperator {
|
||||
Assign,
|
||||
AddAssign,
|
||||
SubAssign,
|
||||
MulAssign,
|
||||
DivAssign,
|
||||
ModAssign,
|
||||
AndAssign,
|
||||
OrAssign,
|
||||
XorAssign,
|
||||
LeftShiftAssign,
|
||||
RightShiftAssign,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum BinaryOperator {
|
||||
@@ -371,7 +388,6 @@ pub enum UnaryOperator {
|
||||
Minus,
|
||||
AddressOf,
|
||||
Dereference,
|
||||
CastAs,
|
||||
BitwiseNot,
|
||||
LogicalNot,
|
||||
Increment,
|
||||
@@ -388,7 +404,6 @@ impl fmt::Display for UnaryOperator {
|
||||
Self::Minus => write!(f, "-"),
|
||||
Self::Dereference => write!(f, "*"),
|
||||
Self::AddressOf => write!(f, "&"),
|
||||
Self::CastAs => write!(f, "as"),
|
||||
Self::BitwiseNot => write!(f, "~"),
|
||||
Self::LogicalNot => write!(f, "!"),
|
||||
Self::SizeOf => write!(f, "sizeof"),
|
||||
|
||||
Reference in New Issue
Block a user