feat(parser,ir,backend): Support array

This commit is contained in:
2026-05-31 22:06:09 +08:00
parent c42575c1c6
commit 669c415bd7
13 changed files with 575 additions and 130 deletions
+25 -3
View File
@@ -2,7 +2,7 @@ use petgraph::dot::{Config, Dot};
use petgraph::graph::{Graph, NodeIndex}; use petgraph::graph::{Graph, NodeIndex};
use crate::ast::types::{ use crate::ast::types::{
BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt, GlobalDeclStmt, IfStmt, Param, ReturnStmt, Statement, VarDeclStmt, VarDeclStmtValue, WhileStmt ArrayDimension, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt, GlobalDeclStmt, IfStmt, Param, ReturnStmt, Statement, VarDeclStmt, VarDeclStmtValue, WhileStmt
}; };
pub type AstGraph = Graph<String, String>; pub type AstGraph = Graph<String, String>;
@@ -73,7 +73,19 @@ impl AstGraphBuilder {
} }
fn add_var_decl_value(&mut self, parent: NodeIndex, value: &VarDeclStmtValue) -> NodeIndex { fn add_var_decl_value(&mut self, parent: NodeIndex, value: &VarDeclStmtValue) -> NodeIndex {
self.child(parent, value.to_string()) let node = self.child(parent, value.to_string());
for dimension in &value.dimensions {
self.add_array_dimension(node, dimension);
}
node
}
fn add_array_dimension(&mut self, parent: NodeIndex, dimension: &ArrayDimension) -> NodeIndex {
let node = self.child(parent, dimension.to_string());
if let Some(value) = &dimension.value {
self.add_expr(node, value);
}
node
} }
fn add_func_decl(&mut self, parent: NodeIndex, func_decl: &FuncDeclStmt) -> NodeIndex { fn add_func_decl(&mut self, parent: NodeIndex, func_decl: &FuncDeclStmt) -> NodeIndex {
@@ -87,7 +99,11 @@ impl AstGraphBuilder {
} }
fn add_param(&mut self, parent: NodeIndex, param: &Param) -> NodeIndex { fn add_param(&mut self, parent: NodeIndex, param: &Param) -> NodeIndex {
self.child(parent, param.to_string()) let node = self.child(parent, param.to_string());
for dimension in &param.dimensions {
self.add_array_dimension(node, dimension);
}
node
} }
fn add_block_stmt(&mut self, parent: NodeIndex, block_stmt: &BlockStmt) -> NodeIndex { fn add_block_stmt(&mut self, parent: NodeIndex, block_stmt: &BlockStmt) -> NodeIndex {
@@ -153,6 +169,12 @@ impl AstGraphBuilder {
fn add_expr(&mut self, parent: NodeIndex, expr: &Expr) -> NodeIndex { fn add_expr(&mut self, parent: NodeIndex, expr: &Expr) -> NodeIndex {
match &expr.value { match &expr.value {
ExprValue::IntLit(_) | ExprValue::Var(_) => self.child(parent, expr.value.to_string()), ExprValue::IntLit(_) | ExprValue::Var(_) => self.child(parent, expr.value.to_string()),
ExprValue::ArrayAccess { array, index } => {
let node = self.child(parent, expr.value.to_string());
self.add_expr(node, array);
self.add_expr(node, index);
node
}
ExprValue::BinaryOp { lhs, op: _, rhs } => { ExprValue::BinaryOp { lhs, op: _, rhs } => {
let node = self.child(parent, expr.value.to_string()); let node = self.child(parent, expr.value.to_string());
self.add_expr(node, lhs); self.add_expr(node, lhs);
+17
View File
@@ -17,7 +17,12 @@ pub struct VarDeclStmt {
pub struct VarDeclStmtValue { pub struct VarDeclStmtValue {
pub name: String, pub name: String,
pub name_span: Span, pub name_span: Span,
pub dimensions: Vec<ArrayDimension>,
}
pub struct ArrayDimension {
pub value: Option<Expr>,
pub span: Span,
} }
pub struct FuncDeclStmt { pub struct FuncDeclStmt {
@@ -89,6 +94,10 @@ pub struct Expr {
pub enum ExprValue { pub enum ExprValue {
IntLit(i64), IntLit(i64),
Var(String), Var(String),
ArrayAccess {
array: Box<Expr>,
index: Box<Expr>,
},
BinaryOp { BinaryOp {
lhs: Box<Expr>, lhs: Box<Expr>,
op: BinaryOp, op: BinaryOp,
@@ -159,6 +168,7 @@ impl From<TypeIdent> for Type {
pub struct Param { pub struct Param {
pub name: String, pub name: String,
pub param_type: Type, pub param_type: Type,
pub dimensions: Vec<ArrayDimension>,
pub name_span: Span, pub name_span: Span,
pub type_span: Span, pub type_span: Span,
} }
@@ -190,6 +200,12 @@ impl fmt::Display for VarDeclStmtValue {
} }
} }
impl fmt::Display for ArrayDimension {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ArrayDimension")
}
}
impl fmt::Display for FuncDeclStmt { impl fmt::Display for FuncDeclStmt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.return_type, self.name) write!(f, "{} {}", self.return_type, self.name)
@@ -256,6 +272,7 @@ impl fmt::Display for ExprValue {
match self { match self {
ExprValue::IntLit(value) => write!(f, "IntLit({})", value), ExprValue::IntLit(value) => write!(f, "IntLit({})", value),
ExprValue::Var(name) => write!(f, "Var({})", name), ExprValue::Var(name) => write!(f, "Var({})", name),
ExprValue::ArrayAccess { .. } => write!(f, "ArrayAccess"),
ExprValue::BinaryOp { op, .. } => write!(f, "BinaryOp({})", op), ExprValue::BinaryOp { op, .. } => write!(f, "BinaryOp({})", op),
ExprValue::FuncCall(name, _) => write!(f, "FuncCall({})", name), ExprValue::FuncCall(name, _) => write!(f, "FuncCall({})", name),
ExprValue::Assign { .. } => write!(f, "Assign"), ExprValue::Assign { .. } => write!(f, "Assign"),
+51 -8
View File
@@ -1,6 +1,6 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use crate::{backend::{arm_instr::{ARMInstr, AddInstr, BInstr, BlInstr, CmpInstr, ConditionCode, LoadInstr, LoadPseudoInstr, MoveInstr, MulInstr, PopInstr, PushInstr, RegisterOrImm, RsbInstr, SDivInstr, StoreInstr, SubInstr}, register_allocator::{REG_R0, REG_R1, REG_R2, REG_R3, Register, RegisterAlloc, RegisterAllocator}, types::ARMAsmVar}, ir::types::{Function, IRInstr, MoveRValue, Variable, VariableOrIntLit, VariableType}}; use crate::{backend::{arm_instr::{ARMInstr, AddInstr, BInstr, BlInstr, CmpInstr, ConditionCode, LoadInstr, LoadPseudoInstr, MoveInstr, MulInstr, PopInstr, PushInstr, RegisterOrImm, RsbInstr, SDivInstr, StoreInstr, SubInstr}, register_allocator::{REG_FP, REG_R0, REG_R1, REG_R2, REG_R3, Register, RegisterAlloc, RegisterAllocator}, types::ARMAsmVar}, ir::types::{Function, IRInstr, MoveRValue, Variable, VariableOrIntLit, VariableType}};
use crate::ir::types::BinaryOp as IRBinaryOp; use crate::ir::types::BinaryOp as IRBinaryOp;
use crate::ir::types::CmpOp as IRCmpOp; use crate::ir::types::CmpOp as IRCmpOp;
use crate::ir::types::UnaryOp as IRUnaryOp; use crate::ir::types::UnaryOp as IRUnaryOp;
@@ -19,7 +19,7 @@ const ARG_REGS: [Register; 4] = [REG_R0, REG_R1, REG_R2, REG_R3];
fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_index_to_stack_offset: &BTreeMap<usize, usize>, instrs: &mut Vec<ARMInstr>) -> RegisterAlloc { fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_index_to_stack_offset: &BTreeMap<usize, usize>, instrs: &mut Vec<ARMInstr>) -> RegisterAlloc {
match variable.var_type { match variable.var_type {
VariableType::Global => { VariableType::Global => {
let var_alloc = reg_allocator.alloc(variable).expect("Ran out of registers"); let var_alloc = reg_allocator.alloc(variable.clone()).expect("Ran out of registers");
let var_reg = var_alloc.reg; let var_reg = var_alloc.reg;
// if !var_alloc.is_reused { // if !var_alloc.is_reused {
let address_alloc = reg_allocator.alloc_any().expect("Ran out of registers"); let address_alloc = reg_allocator.alloc_any().expect("Ran out of registers");
@@ -39,7 +39,7 @@ fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_
}, },
_ => { _ => {
let stack_offset = var_index_to_stack_offset.get(&variable.index).expect("Variable not declared"); let stack_offset = var_index_to_stack_offset.get(&variable.index).expect("Variable not declared");
let var_alloc = reg_allocator.alloc(variable).expect("Ran out of registers"); let var_alloc = reg_allocator.alloc(variable.clone()).expect("Ran out of registers");
// if !var_alloc.is_reused { // if !var_alloc.is_reused {
instrs.push(LoadInstr::new_stack(var_alloc.reg, *stack_offset as i32)); instrs.push(LoadInstr::new_stack(var_alloc.reg, *stack_offset as i32));
// } // }
@@ -134,6 +134,10 @@ impl Generator {
}, },
IRInstr::FuncCall(func, args, ret) => self.emit_func_call(func, args, ret, &var_index_to_stack_offset), IRInstr::FuncCall(func, args, ret) => self.emit_func_call(func, args, ret, &var_index_to_stack_offset),
IRInstr::Move(dest, src) => self.emit_move(dest, src, &var_index_to_stack_offset), IRInstr::Move(dest, src) => self.emit_move(dest, src, &var_index_to_stack_offset),
IRInstr::Load(dest, addr) => self.emit_load(dest, addr, &var_index_to_stack_offset),
IRInstr::Store(addr, value) => self.emit_store(addr, value, &var_index_to_stack_offset),
IRInstr::GetAddr(dest, var) => self.emit_get_addr(dest, var, &var_index_to_stack_offset),
IRInstr::GetElementPtr(dest, base, index, elem_size) => self.emit_get_element_ptr(dest, base, index, elem_size, &var_index_to_stack_offset),
IRInstr::Declare(variable) => { IRInstr::Declare(variable) => {
assert!(!encounter_entry, "Variable declarations must come before entry instruction"); assert!(!encounter_entry, "Variable declarations must come before entry instruction");
let size = variable.data_type.size_in_bytes(); let size = variable.data_type.size_in_bytes();
@@ -163,7 +167,7 @@ impl Generator {
} }
fn emit_unary(&mut self, dest: Variable, unary_op: IRUnaryOp, variable: Variable, var_index_to_stack_offset: &BTreeMap<usize, usize>) { fn emit_unary(&mut self, dest: Variable, unary_op: IRUnaryOp, variable: Variable, var_index_to_stack_offset: &BTreeMap<usize, usize>) {
let variable_alloc = load_variable(variable, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); let variable_alloc = load_variable(variable, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
let dest_alloc = self.register_allocator.alloc(dest).expect("Ran out of registers"); let dest_alloc = self.register_allocator.alloc(dest.clone()).expect("Ran out of registers");
match unary_op { match unary_op {
IRUnaryOp::Neg => { IRUnaryOp::Neg => {
self.instrs.push(RsbInstr::new(dest_alloc.reg, variable_alloc.reg, RegisterOrImm::Imm(0))); self.instrs.push(RsbInstr::new(dest_alloc.reg, variable_alloc.reg, RegisterOrImm::Imm(0)));
@@ -193,7 +197,7 @@ impl Generator {
alloc alloc
}, },
}; };
let variable_alloc = self.register_allocator.alloc(variable).expect("Ran out of registers"); let variable_alloc = self.register_allocator.alloc(variable.clone()).expect("Ran out of registers");
let variable_reg = variable_alloc.reg; let variable_reg = variable_alloc.reg;
self.instrs.push(CmpInstr::new(left_alloc.reg, RegisterOrImm::Reg(right_alloc.reg))); self.instrs.push(CmpInstr::new(left_alloc.reg, RegisterOrImm::Reg(right_alloc.reg)));
self.instrs.push(MoveInstr::new_uncond(variable_reg, RegisterOrImm::Imm(0))); self.instrs.push(MoveInstr::new_uncond(variable_reg, RegisterOrImm::Imm(0)));
@@ -221,7 +225,7 @@ impl Generator {
self.instrs.push(PopInstr::new_pop_caller_save()); self.instrs.push(PopInstr::new_pop_caller_save());
} }
fn emit_move(&mut self, dest: Variable, src: MoveRValue, var_index_to_stack_offset: &BTreeMap<usize, usize>) { fn emit_move(&mut self, dest: Variable, src: MoveRValue, var_index_to_stack_offset: &BTreeMap<usize, usize>) {
let dest_alloc = self.register_allocator.alloc(dest).expect("Ran out of registers"); let dest_alloc = self.register_allocator.alloc(dest.clone()).expect("Ran out of registers");
let dest_register = dest_alloc.reg; let dest_register = dest_alloc.reg;
match src { match src {
MoveRValue::Var(variable) => { MoveRValue::Var(variable) => {
@@ -232,11 +236,50 @@ impl Generator {
}; };
save_variable(dest, dest_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); save_variable(dest, dest_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
} }
fn emit_get_addr(&mut self, dest: Variable, var: Variable, var_index_to_stack_offset: &BTreeMap<usize, usize>) {
let dest_alloc = self.register_allocator.alloc(dest.clone()).expect("Ran out of registers");
match var.var_type {
VariableType::Global => {
self.instrs.push(LoadPseudoInstr::new(dest_alloc.reg, format!("global_var_{}", var.index)));
}
_ => {
let stack_offset = var_index_to_stack_offset.get(&var.index).expect("Variable not declared");
self.instrs.push(SubInstr::new(dest_alloc.reg, REG_FP, RegisterOrImm::Imm(*stack_offset as i32)));
}
}
save_variable(dest, dest_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
}
fn emit_get_element_ptr(&mut self, dest: Variable, base: Variable, index: Variable, elem_size: usize, var_index_to_stack_offset: &BTreeMap<usize, usize>) {
let base_alloc = load_variable(base, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
let index_alloc = load_variable(index, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
let scaled_alloc = self.register_allocator.alloc_any().expect("Ran out of registers");
self.instrs.push(MoveInstr::new_uncond(scaled_alloc.reg, RegisterOrImm::Imm(elem_size as i32)));
self.instrs.push(MulInstr::new(scaled_alloc.reg, index_alloc.reg, RegisterOrImm::Reg(scaled_alloc.reg)));
let dest_alloc = self.register_allocator.alloc(dest.clone()).expect("Ran out of registers");
self.instrs.push(AddInstr::new(dest_alloc.reg, base_alloc.reg, RegisterOrImm::Reg(scaled_alloc.reg)));
save_variable(dest, dest_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
}
fn emit_load(&mut self, dest: Variable, addr: Variable, var_index_to_stack_offset: &BTreeMap<usize, usize>) {
let addr_alloc = load_variable(addr, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
let dest_alloc = self.register_allocator.alloc(dest.clone()).expect("Ran out of registers");
self.instrs.push(LoadInstr::new(dest_alloc.reg, addr_alloc.reg, None));
save_variable(dest, dest_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
}
fn emit_store(&mut self, addr: Variable, value: Variable, var_index_to_stack_offset: &BTreeMap<usize, usize>) {
let addr_alloc = load_variable(addr, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
let value_alloc = load_variable(value, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
self.instrs.push(StoreInstr::new(value_alloc.reg, addr_alloc.reg, None));
}
fn emit_binary(&mut self, dest: Variable, left: Variable, op: IRBinaryOp, right: Variable, var_index_to_stack_offset: &BTreeMap<usize, usize>) { fn emit_binary(&mut self, dest: Variable, left: Variable, op: IRBinaryOp, right: Variable, var_index_to_stack_offset: &BTreeMap<usize, usize>) {
let dest_alloc = self.register_allocator.alloc(dest).expect("Ran out of registers"); let dest_alloc = self.register_allocator.alloc(dest.clone()).expect("Ran out of registers");
let dest_reg = dest_alloc.reg; let dest_reg = dest_alloc.reg;
// should consider left == right // should consider left == right
let left_alloc = load_variable(left, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); let left_alloc = load_variable(left.clone(), &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
let (_right_alloc, right_reg) = if left != right { let (_right_alloc, right_reg) = if left != right {
let right_alloc = load_variable(right, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); let right_alloc = load_variable(right, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
let right_reg = right_alloc.reg; let right_reg = right_alloc.reg;
+5 -5
View File
@@ -84,7 +84,7 @@ impl RegisterAllocatorInner {
*use_kind = RegisterUseKind::Free; *use_kind = RegisterUseKind::Free;
}, },
RegisterUseKind::UsedByVariable(var) => { RegisterUseKind::UsedByVariable(var) => {
*use_kind = RegisterUseKind::AllocatedToVariable(*var); *use_kind = RegisterUseKind::AllocatedToVariable(var.clone());
}, },
_ => panic!("Trying to mark a register as unused that is not in use"), _ => panic!("Trying to mark a register as unused that is not in use"),
} }
@@ -139,8 +139,8 @@ impl RegisterAllocator {
continue; continue;
} }
if let RegisterUseKind::Free = use_kind { if let RegisterUseKind::Free = use_kind {
*use_kind = RegisterUseKind::UsedByVariable(var); *use_kind = RegisterUseKind::UsedByVariable(var.clone());
inner.variable_to_register.insert(var, reg); inner.variable_to_register.insert(var.clone(), reg);
return Some(RegisterAlloc { return Some(RegisterAlloc {
allocator: Rc::downgrade(&self.inner), allocator: Rc::downgrade(&self.inner),
reg, reg,
@@ -156,8 +156,8 @@ impl RegisterAllocator {
} }
if let RegisterUseKind::AllocatedToVariable(ori_var) = use_kind { if let RegisterUseKind::AllocatedToVariable(ori_var) = use_kind {
assert!(variable_to_register.remove(&ori_var).is_some()); assert!(variable_to_register.remove(&ori_var).is_some());
*use_kind = RegisterUseKind::UsedByVariable(var); *use_kind = RegisterUseKind::UsedByVariable(var.clone());
variable_to_register.insert(var, reg); variable_to_register.insert(var.clone(), reg);
return Some(RegisterAlloc { return Some(RegisterAlloc {
allocator: Rc::downgrade(&self.inner), allocator: Rc::downgrade(&self.inner),
reg, reg,
+3 -1
View File
@@ -17,7 +17,7 @@ pub struct Lexer {
const WHITESPACE_CHARS: &[char] = &[' ', '\t', '\n', '\r']; const WHITESPACE_CHARS: &[char] = &[' ', '\t', '\n', '\r'];
const DELIMITER_CHARS: &[char] = &[ const DELIMITER_CHARS: &[char] = &[
'+', '-', '*', '/', '%', '=', '!', '<', '>', '(', ')', ',', ';', '{', '|', '&' '+', '-', '*', '/', '%', '=', '!', '<', '>', '(', ')', '[', ']', ',', ';', '{', '|', '&'
]; ];
struct Cursor { struct Cursor {
chars: Vec<char>, chars: Vec<char>,
@@ -248,6 +248,8 @@ fn parse_delimiter(
')' => TokenValue::RParen, ')' => TokenValue::RParen,
'{' => TokenValue::LBrace, '{' => TokenValue::LBrace,
'}' => TokenValue::RBrace, '}' => TokenValue::RBrace,
'[' => TokenValue::LBracket,
']' => TokenValue::RBracket,
_ => return Err(LexParseError::NotMatched), _ => return Err(LexParseError::NotMatched),
}; };
str_iter.advance(1); str_iter.advance(1);
+100 -27
View File
@@ -1,6 +1,6 @@
use crate::{ use crate::{
ast::types::{ ast::types::{
BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt, GlobalDeclStmt, IfElseBranch, IfStmt, Param, ReturnStmt, Statement, UnaryOp, VarDeclStmt, VarDeclStmtValue, WhileStmt ArrayDimension, BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt, GlobalDeclStmt, IfElseBranch, IfStmt, Param, ReturnStmt, Statement, UnaryOp, VarDeclStmt, VarDeclStmtValue, WhileStmt
}, },
diagnostic::{Diagnositics, span::Span}, diagnostic::{Diagnositics, span::Span},
frontend::{ frontend::{
@@ -259,6 +259,7 @@ impl Parser {
Ok(Param { Ok(Param {
param_type: param_type.into(), param_type: param_type.into(),
name, name,
dimensions: self.parse_array_dimensions(true)?,
name_span, name_span,
type_span, type_span,
}) })
@@ -300,7 +301,8 @@ impl Parser {
} }
} }
}; };
values.push(VarDeclStmtValue { name, name_span }); let dimensions = self.parse_array_dimensions(false)?;
values.push(VarDeclStmtValue { name, name_span, dimensions });
let mut last_name = true; // indicate whether the last parsed token is a variable name let mut last_name = true; // indicate whether the last parsed token is a variable name
while let Some(t) = self.peek() { while let Some(t) = self.peek() {
if matches!(t.value, TokenValue::Semicolon) { // statement end if matches!(t.value, TokenValue::Semicolon) { // statement end
@@ -319,7 +321,8 @@ impl Parser {
} }
if let Some(ident) = self.peek().unwrap().value.as_ident() { if let Some(ident) = self.peek().unwrap().value.as_ident() {
let span = self.next().unwrap().span; let span = self.next().unwrap().span;
values.push(VarDeclStmtValue { name: ident, name_span: span }); let dimensions = self.parse_array_dimensions(false)?;
values.push(VarDeclStmtValue { name: ident, name_span: span, dimensions });
last_name = true; last_name = true;
} else { } else {
let token = self.next().unwrap().clone(); let token = self.next().unwrap().clone();
@@ -334,6 +337,50 @@ impl Parser {
Ok(VarDeclStmt { values, type_span, data_type: var_type.into() }) Ok(VarDeclStmt { values, type_span, data_type: var_type.into() })
} }
fn parse_array_dimensions(&mut self, allow_empty_first: bool) -> Result<Vec<ArrayDimension>, ParseProcessError> {
let mut dimensions = vec![];
while self.peek().is_some_and(|t| t.value == TokenValue::LBracket) {
let start_span = self.next().unwrap().span;
let value = if self.peek().is_some_and(|t| t.value == TokenValue::RBracket) {
if !allow_empty_first || !dimensions.is_empty() {
let span = self.peek().unwrap().span;
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(TokenValue::RBracket, "array dimension expression"),
span,
);
return Err(ParseProcessError::ErrorInMatch);
}
None
} else {
Some(self.parse_expr()?)
};
let end_span = match self.peek() {
Some(t) if t.value == TokenValue::RBracket => {
let span = t.span;
self.advance(1);
span
}
Some(_) => {
let token = self.next().unwrap().clone();
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(token.value, "`]`"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
None => {
self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("`]`"), start_span);
return Err(ParseProcessError::ErrorInMatch);
}
};
dimensions.push(ArrayDimension {
value,
span: Span::from_two(start_span, end_span),
});
}
Ok(dimensions)
}
fn parse_block_stmt(&mut self, parse_type: ParseType) -> Result<BlockStmt, ParseProcessError> { fn parse_block_stmt(&mut self, parse_type: ParseType) -> Result<BlockStmt, ParseProcessError> {
assert!(self.peek().is_some()); assert!(self.peek().is_some());
if self if self
@@ -598,7 +645,7 @@ impl Parser {
// } // }
// } // }
// } // }
fn parse_primary(&mut self) -> Result<Expr, ParseProcessError> { fn parse_primary_atom(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some()); assert!(self.peek().is_some());
let token = self.next().unwrap().clone(); let token = self.next().unwrap().clone();
match token.value { match token.value {
@@ -712,6 +759,47 @@ impl Parser {
} }
} }
} }
fn parse_primary(&mut self) -> Result<Expr, ParseProcessError> {
let mut expr = self.parse_primary_atom()?;
while self.peek().is_some_and(|t| t.value == TokenValue::LBracket) {
let start_span = expr.span;
self.advance(1);
let index = match self.peek() {
Some(_) => self.parse_expr()?,
None => {
self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("array index expression"), start_span);
return Err(ParseProcessError::ErrorInMatch);
}
};
let end_span = match self.peek() {
Some(t) if t.value == TokenValue::RBracket => {
let span = t.span;
self.advance(1);
span
}
Some(_) => {
let token = self.next().unwrap().clone();
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(token.value, "`]`"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
None => {
self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("`]`"), index.span);
return Err(ParseProcessError::ErrorInMatch);
}
};
expr = Expr {
value: ExprValue::ArrayAccess {
array: Box::new(expr),
index: Box::new(index),
},
span: Span::from_two(start_span, end_span),
};
}
Ok(expr)
}
fn parse_unary(&mut self) -> Result<Expr, ParseProcessError> { fn parse_unary(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some()); assert!(self.peek().is_some());
let token = self.peek().unwrap().clone(); let token = self.peek().unwrap().clone();
@@ -937,40 +1025,21 @@ impl Parser {
} }
fn parse_assign(&mut self) -> Result<Expr, ParseProcessError> { fn parse_assign(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some()); assert!(self.peek().is_some());
let is_assign = matches!( let lvalue = self.parse_logical_or()?;
(self.tokens.get(self.pos), self.tokens.get(self.pos + 1)), if !self.peek().is_some_and(|t| t.value == TokenValue::Equal) {
( return Ok(lvalue);
Some(Token {
value: TokenValue::Ident(_),
..
}),
Some(Token {
value: TokenValue::Equal,
..
})
)
);
if !is_assign {
return self.parse_logical_or();
} }
let lvalue_token = self.next().unwrap().clone();
let name = lvalue_token.value.as_ident().unwrap();
self.advance(1); self.advance(1);
let rvalue = match self.peek() { let rvalue = match self.peek() {
Some(_) => self.parse_assign()?, Some(_) => self.parse_assign()?,
None => { None => {
self.diagnostics.add_from_frontend_error( self.diagnostics.add_from_frontend_error(
ParseError::ExpectButEof("expression"), ParseError::ExpectButEof("expression"),
lvalue_token.span, lvalue.span,
); );
return Err(ParseProcessError::ErrorInMatch); return Err(ParseProcessError::ErrorInMatch);
} }
}; };
let lvalue = Expr {
value: ExprValue::Var(name),
span: lvalue_token.span,
};
let span = Span::from_two(lvalue.span, rvalue.span); let span = Span::from_two(lvalue.span, rvalue.span);
Ok(Expr { Ok(Expr {
value: ExprValue::Assign { value: ExprValue::Assign {
@@ -1100,4 +1169,8 @@ mod tests {
fn test_func() { fn test_func() {
test_case("12-13,58-60"); test_case("12-13,58-60");
} }
#[test]
fn test_array() {
test_case("4-7,11,42,71,74-78,82,84,86,90,95,96,100,101,103");
}
} }
+4
View File
@@ -21,6 +21,7 @@ pub enum TokenValue {
LParen, RParen, LParen, RParen,
LBrace, RBrace, LBrace, RBrace,
LBracket, RBracket,
Comma, Semicolon, Comma, Semicolon,
If, Else, While, Return, Break, Continue, If, Else, While, Return, Break, Continue,
@@ -69,6 +70,8 @@ impl std::fmt::Display for TokenValue {
TokenValue::RParen => write!(f, "`)`"), TokenValue::RParen => write!(f, "`)`"),
TokenValue::LBrace => write!(f, "`{{`"), TokenValue::LBrace => write!(f, "`{{`"),
TokenValue::RBrace => write!(f, "`}}`"), TokenValue::RBrace => write!(f, "`}}`"),
TokenValue::LBracket => write!(f, "`[`"),
TokenValue::RBracket => write!(f, "`]`"),
TokenValue::Comma => write!(f, "`,`"), TokenValue::Comma => write!(f, "`,`"),
TokenValue::Semicolon => write!(f, "`;`"), TokenValue::Semicolon => write!(f, "`;`"),
TokenValue::If => write!(f, "if"), TokenValue::If => write!(f, "if"),
@@ -94,6 +97,7 @@ pub enum TokenKind {
LParen, RParen, LParen, RParen,
LBrace, RBrace, LBrace, RBrace,
LBracket, RBracket,
Comma, Semicolon, Comma, Semicolon,
If, Else, While, Return, Break, Continue, If, Else, While, Return, Break, Continue,
+111 -44
View File
@@ -1,6 +1,6 @@
use std::{collections::BTreeMap, vec}; use std::{collections::BTreeMap, vec};
use crate::{ir::types::{BinaryOp, CmpOp, Function, IRInstr, IRType, MoveRValue, UnaryOp, Variable, VariableOrIntLit, VariableType}, sema::{analyzer::Analyzer as SemaAnalyzer, hir::{HirBlockStmt, HirBreakStmt, HirCompileUnit, HirContinueStmt, HirExpr, HirExprValue, HirFuncDeclStmt, HirGlobalDeclStmt, HirIfElseBranch, HirIfStmt, HirReturnStmt, HirStatement, HirVarDeclStmt, HirWhileStmt}, symbol::{FunctionId, SymbolId}}}; use crate::{ir::types::{CmpOp, Function, IRInstr, IRType, MoveRValue, UnaryOp, Variable, VariableOrIntLit, VariableType}, sema::{analyzer::Analyzer as SemaAnalyzer, hir::{HirBlockStmt, HirBreakStmt, HirCompileUnit, HirContinueStmt, HirExpr, HirExprValue, HirFuncDeclStmt, HirGlobalDeclStmt, HirIfElseBranch, HirIfStmt, HirReturnStmt, HirStatement, HirVarDeclStmt, HirWhileStmt}, symbol::{FunctionId, SymbolId}}};
use crate::ast::types::BinaryOp as AstBinaryOp; use crate::ast::types::BinaryOp as AstBinaryOp;
use crate::ast::types::UnaryOp as AstUnaryOp; use crate::ast::types::UnaryOp as AstUnaryOp;
pub struct Generator<'a> { pub struct Generator<'a> {
@@ -41,8 +41,8 @@ impl<'a> Generator<'a> {
let sig = self.sema.get_function_sig(function_id); let sig = self.sema.get_function_sig(function_id);
Function { Function {
name: sig.name.clone(), name: sig.name.clone(),
parameter_types: sig.parameter_types.iter().map(|ty| (*ty).into()).collect(), parameter_types: sig.parameter_types.iter().map(|ty| ty.clone().into()).collect(),
return_type: sig.return_type.into(), return_type: sig.return_type.clone().into(),
} }
} }
@@ -66,7 +66,7 @@ impl<'a> Generator<'a> {
let mut instrs = vec![]; let mut instrs = vec![];
let var_type = if is_global { VariableType::Global } else { VariableType::Local }; let var_type = if is_global { VariableType::Global } else { VariableType::Local };
for value in var_decl.values { for value in var_decl.values {
let var = self.var_manager.declare_symbol(value.symbol, var_type, var_decl.data_type.into()); let var = self.var_manager.declare_symbol(value.symbol, var_type, self.sema.get_symbol_type(value.symbol).into());
if is_global { if is_global {
instrs.push(IRInstr::Declare(var)); instrs.push(IRInstr::Declare(var));
} }
@@ -77,10 +77,10 @@ impl<'a> Generator<'a> {
fn generate_func_decl(&mut self, func_decl: HirFuncDeclStmt) -> Vec<IRInstr> { fn generate_func_decl(&mut self, func_decl: HirFuncDeclStmt) -> Vec<IRInstr> {
let parameters: Vec<Variable> = func_decl.params.iter() let parameters: Vec<Variable> = func_decl.params.iter()
.map(|param| self.var_manager.declare_symbol(param.symbol, VariableType::Local, param.param_type.into())) .map(|param| self.var_manager.declare_symbol(param.symbol, VariableType::Local, param.param_type.clone().into()))
.collect(); .collect();
let temp_parameters = parameters.iter().enumerate() let temp_parameters = parameters.iter().enumerate()
.map(|(i, param)| self.var_manager.declare_param_temp(param.data_type, i)) .map(|(i, param)| self.var_manager.declare_param_temp(param.data_type.clone(), i))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut body_instrs = vec![]; let mut body_instrs = vec![];
self.func_exit = Some((self.request_label(), { self.func_exit = Some((self.request_label(), {
@@ -100,7 +100,7 @@ impl<'a> Generator<'a> {
} }
body_instrs.push(IRInstr::Entry); body_instrs.push(IRInstr::Entry);
parameters.iter().zip(temp_parameters.iter()).for_each(|(param, temp_param)| { parameters.iter().zip(temp_parameters.iter()).for_each(|(param, temp_param)| {
body_instrs.push(IRInstr::Move(*param, MoveRValue::Var(*temp_param))); body_instrs.push(IRInstr::Move(param.clone(), MoveRValue::Var(temp_param.clone())));
}); });
body_instrs.extend(block_instrs); body_instrs.extend(block_instrs);
let func_exit = self.func_exit.take().unwrap(); let func_exit = self.func_exit.take().unwrap();
@@ -108,7 +108,7 @@ impl<'a> Generator<'a> {
body_instrs.push(IRInstr::Exit(func_exit.1)); body_instrs.push(IRInstr::Exit(func_exit.1));
self.var_manager.clear_local_counter(); self.var_manager.clear_local_counter();
let mut func = self.ir_function(func_decl.sig.id); let mut func = self.ir_function(func_decl.sig.id);
func.parameter_types = temp_parameters.iter().map(|v| v.data_type).collect(); func.parameter_types = temp_parameters.iter().map(|v| v.data_type.clone()).collect();
vec![IRInstr::DefineFunc(func, temp_parameters, body_instrs)] vec![IRInstr::DefineFunc(func, temp_parameters, body_instrs)]
} }
fn generate_block_stmt(&mut self, block_stmt: HirBlockStmt) -> Vec<IRInstr> { fn generate_block_stmt(&mut self, block_stmt: HirBlockStmt) -> Vec<IRInstr> {
@@ -149,7 +149,7 @@ impl<'a> Generator<'a> {
fn generate_return_stmt(&mut self, return_stmt: HirReturnStmt) -> Vec<IRInstr> { fn generate_return_stmt(&mut self, return_stmt: HirReturnStmt) -> Vec<IRInstr> {
let mut instrs = vec![]; let mut instrs = vec![];
let func_exit = self.func_exit.unwrap(); let func_exit = self.func_exit.clone().unwrap();
match return_stmt.value { match return_stmt.value {
Some(expr) => { Some(expr) => {
self.current_exit_label.push(None); self.current_exit_label.push(None);
@@ -269,26 +269,49 @@ impl<'a> Generator<'a> {
HirExprValue::IntLit(i) => { HirExprValue::IntLit(i) => {
// TODO: convert check // TODO: convert check
let var = self.var_manager.declare_temp(IRType::I32); let var = self.var_manager.declare_temp(IRType::I32);
(vec![IRInstr::Move(var, MoveRValue::ConstInt(i as i32))], Some(var)) (vec![IRInstr::Move(var.clone(), MoveRValue::ConstInt(i as i32))], Some(var))
}, },
HirExprValue::Var(symbol) => { HirExprValue::Var(symbol) => {
let var = self.var_manager.get_symbol(symbol).unwrap(); let var = self.var_manager.get_symbol(symbol).unwrap();
(vec![], Some(var)) if var.data_type.is_array() {
let ptr_ty = var.data_type.decay_to_ptr().unwrap();
let dest = self.var_manager.declare_temp(ptr_ty);
(vec![IRInstr::GetAddr(dest.clone(), var)], Some(dest))
} else {
(vec![], Some(var))
}
}, },
HirExprValue::Assign { lvalue, rvalue } => { HirExprValue::Assign { lvalue, rvalue } => {
let var = if let HirExprValue::Var(symbol) = lvalue.value { let lvalue_ty: IRType = lvalue.ty.clone().into();
self.var_manager.get_symbol(symbol).unwrap()
} else {
return None;
};
self.current_exit_label.push(None); self.current_exit_label.push(None);
let (mut instrs, rvalue_var) = self.generate_expr(*rvalue)?; let (mut instrs, rvalue_var) = self.generate_expr(*rvalue)?;
self.current_exit_label.pop(); self.current_exit_label.pop();
instrs.push(IRInstr::Move(var, MoveRValue::Var(rvalue_var.unwrap()))); let (lvalue_instrs, target, is_addr) = self.generate_lvalue(*lvalue)?;
let temp_var = self.var_manager.declare_temp(var.data_type); instrs.extend(lvalue_instrs);
instrs.push(IRInstr::Move(temp_var, MoveRValue::Var(var))); if is_addr {
instrs.push(IRInstr::Store(target.clone(), rvalue_var.unwrap()));
} else {
instrs.push(IRInstr::Move(target.clone(), MoveRValue::Var(rvalue_var.unwrap())));
}
let temp_var = self.var_manager.declare_temp(lvalue_ty);
if is_addr {
instrs.push(IRInstr::Load(temp_var.clone(), target));
} else {
instrs.push(IRInstr::Move(temp_var.clone(), MoveRValue::Var(target)));
}
(instrs, Some(temp_var)) (instrs, Some(temp_var))
}, },
HirExprValue::ArrayAccess { array, index } => {
let result_ty: IRType = expr.ty.clone().into();
let (mut instrs, addr) = self.generate_array_element_addr(*array, *index)?;
if result_ty.is_array() {
(instrs, Some(addr))
} else {
let dest = self.var_manager.declare_temp(result_ty);
instrs.push(IRInstr::Load(dest.clone(), addr));
(instrs, Some(dest))
}
},
HirExprValue::UnaryOp { op, operand } => { HirExprValue::UnaryOp { op, operand } => {
let mut parent_is_logical = true; let mut parent_is_logical = true;
let exit_passdown = if matches!(op, AstUnaryOp::Not) { let exit_passdown = if matches!(op, AstUnaryOp::Not) {
@@ -319,26 +342,26 @@ impl<'a> Generator<'a> {
let operand_var = operand_var.unwrap(); let operand_var = operand_var.unwrap();
let dest_var = match op { let dest_var = match op {
AstUnaryOp::Add => { AstUnaryOp::Add => {
let dest_var = self.var_manager.declare_temp(operand_var.data_type); let dest_var = self.var_manager.declare_temp(operand_var.data_type.clone());
instrs.push(IRInstr::Move(dest_var, MoveRValue::Var(operand_var))); instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::Var(operand_var)));
dest_var dest_var
}, },
AstUnaryOp::Sub => { AstUnaryOp::Sub => {
let dest_var = self.var_manager.declare_temp(operand_var.data_type); let dest_var = self.var_manager.declare_temp(operand_var.data_type.clone());
instrs.push(IRInstr::Unary(dest_var, UnaryOp::Neg, operand_var)); instrs.push(IRInstr::Unary(dest_var.clone(), UnaryOp::Neg, operand_var));
dest_var dest_var
}, },
AstUnaryOp::Not => { AstUnaryOp::Not => {
let dest_var = self.var_manager.declare_unamed_local(operand_var.data_type); let dest_var = self.var_manager.declare_unamed_local(operand_var.data_type.clone());
// child will do the cmp // child will do the cmp
if !parent_is_logical { if !parent_is_logical {
let exit = exit_passdown.unwrap(); // (false_exit, true_exit) (consider `not`) let exit = exit_passdown.unwrap(); // (false_exit, true_exit) (consider `not`)
let final_exit = self.request_label(); let final_exit = self.request_label();
instrs.push(IRInstr::Label(exit.1)); instrs.push(IRInstr::Label(exit.1));
instrs.push(IRInstr::Move(dest_var, MoveRValue::ConstInt(1))); instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::ConstInt(1)));
instrs.push(IRInstr::Goto(final_exit)); instrs.push(IRInstr::Goto(final_exit));
instrs.push(IRInstr::Label(exit.0)); instrs.push(IRInstr::Label(exit.0));
instrs.push(IRInstr::Move(dest_var, MoveRValue::ConstInt(0))); instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::ConstInt(0)));
instrs.push(IRInstr::Goto(final_exit)); instrs.push(IRInstr::Goto(final_exit));
instrs.push(IRInstr::Label(final_exit)); instrs.push(IRInstr::Label(final_exit));
@@ -400,21 +423,21 @@ impl<'a> Generator<'a> {
let convert_to; let convert_to;
if op.is_logical() { if op.is_logical() {
// we dont really care since we use cmp // we dont really care since we use cmp
convert_to = left_var.data_type; convert_to = left_var.data_type.clone();
} else { } else {
convert_to = IRType::get_elevate_result(left_var.data_type, right_var.data_type).unwrap(); convert_to = IRType::get_elevate_result(&left_var.data_type, &right_var.data_type).unwrap();
} }
// do implicit convert if needed // do implicit convert if needed
// TODO: further check // TODO: further check
if !op.is_logical() && convert_to != left_var.data_type { if !op.is_logical() && convert_to != left_var.data_type {
let temp_var = self.var_manager.declare_temp(convert_to); let temp_var = self.var_manager.declare_temp(convert_to.clone());
instrs.push(IRInstr::Move(temp_var, MoveRValue::Var(left_var))); instrs.push(IRInstr::Move(temp_var.clone(), MoveRValue::Var(left_var)));
left_var = temp_var; left_var = temp_var;
} }
let result_type; let result_type;
match op { match op {
AstBinaryOp::Add | AstBinaryOp::Sub | AstBinaryOp::Mul | AstBinaryOp::Div | AstBinaryOp::Mod => { AstBinaryOp::Add | AstBinaryOp::Sub | AstBinaryOp::Mul | AstBinaryOp::Div | AstBinaryOp::Mod => {
result_type = left_var.data_type; result_type = left_var.data_type.clone();
}, },
AstBinaryOp::Equal | AstBinaryOp::NotEqual | AstBinaryOp::Less | AstBinaryOp::Greater | AstBinaryOp::LessEqual | AstBinaryOp::GreaterEqual AstBinaryOp::Equal | AstBinaryOp::NotEqual | AstBinaryOp::Less | AstBinaryOp::Greater | AstBinaryOp::LessEqual | AstBinaryOp::GreaterEqual
| AstBinaryOp::And | AstBinaryOp::Or => { | AstBinaryOp::And | AstBinaryOp::Or => {
@@ -448,17 +471,17 @@ impl<'a> Generator<'a> {
instrs.extend(right_instrs); instrs.extend(right_instrs);
if !op.is_logical() && convert_to != right_var.data_type { if !op.is_logical() && convert_to != right_var.data_type {
let temp_var = self.var_manager.declare_temp(convert_to); let temp_var = self.var_manager.declare_temp(convert_to);
instrs.push(IRInstr::Move(temp_var, MoveRValue::Var(right_var))); instrs.push(IRInstr::Move(temp_var.clone(), MoveRValue::Var(right_var)));
right_var = temp_var; right_var = temp_var;
} }
if !op.is_logical() { if !op.is_logical() {
if let Some((true_exit, false_exit)) = parent_exit { if let Some((true_exit, false_exit)) = parent_exit {
let final_exit = self.request_label(); let final_exit = self.request_label();
instrs.push(IRInstr::Label(true_exit)); instrs.push(IRInstr::Label(true_exit));
instrs.push(IRInstr::Move(dest_var, MoveRValue::ConstInt(1))); instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::ConstInt(1)));
instrs.push(IRInstr::Goto(final_exit)); instrs.push(IRInstr::Goto(final_exit));
instrs.push(IRInstr::Label(false_exit)); instrs.push(IRInstr::Label(false_exit));
instrs.push(IRInstr::Move(dest_var, MoveRValue::ConstInt(0))); instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::ConstInt(0)));
instrs.push(IRInstr::Label(final_exit)); instrs.push(IRInstr::Label(final_exit));
@@ -468,9 +491,9 @@ impl<'a> Generator<'a> {
return Some((instrs, Some(dest_var))); return Some((instrs, Some(dest_var)));
} else { } else {
if op.is_cmp() { if op.is_cmp() {
instrs.push(IRInstr::Cmp(dest_var, VariableOrIntLit::Var(left_var), op.into(), VariableOrIntLit::Var(right_var))); instrs.push(IRInstr::Cmp(dest_var.clone(), VariableOrIntLit::Var(left_var), op.into(), VariableOrIntLit::Var(right_var)));
} else { } else {
instrs.push(IRInstr::Binary(dest_var, left_var, op.into(), right_var)); instrs.push(IRInstr::Binary(dest_var.clone(), left_var, op.into(), right_var));
} }
} }
// if !op.is_logical() { // if !op.is_logical() {
@@ -504,21 +527,61 @@ impl<'a> Generator<'a> {
let ret_variable = if matches!(func_def.return_type, IRType::Void) { let ret_variable = if matches!(func_def.return_type, IRType::Void) {
None None
} else { } else {
Some(self.var_manager.declare_temp(func_def.return_type)) Some(self.var_manager.declare_temp(func_def.return_type.clone()))
}; };
instrs.push(IRInstr::FuncCall(func_def.clone(), arg_vars, ret_variable)); instrs.push(IRInstr::FuncCall(func_def.clone(), arg_vars, ret_variable.clone()));
(instrs, ret_variable) (instrs, ret_variable)
} }
}; };
if let Some((true_exit, false_exit)) = self.current_exit_label.last().cloned().flatten() { if let Some((true_exit, false_exit)) = self.current_exit_label.last().cloned().flatten() {
let cmp_var = self.var_manager.declare_temp(IRType::I1); let cmp_var = self.var_manager.declare_temp(IRType::I1);
instrs.push(IRInstr::Cmp(cmp_var, VariableOrIntLit::Var(var.unwrap()), CmpOp::Ne, VariableOrIntLit::IntLit(0))); instrs.push(IRInstr::Cmp(cmp_var.clone(), VariableOrIntLit::Var(var.clone().unwrap()), CmpOp::Ne, VariableOrIntLit::IntLit(0)));
instrs.push(IRInstr::CondGoto(cmp_var, true_exit, false_exit)); instrs.push(IRInstr::CondGoto(cmp_var, true_exit, false_exit));
Some((instrs, var)) Some((instrs, var))
} else { } else {
Some((instrs, var)) Some((instrs, var))
} }
} }
fn generate_lvalue(&mut self, expr: HirExpr) -> Option<(Vec<IRInstr>, Variable, bool)> {
match expr.value {
HirExprValue::Var(symbol) => {
let var = self.var_manager.get_symbol(symbol).unwrap();
Some((vec![], var, false))
}
HirExprValue::ArrayAccess { array, index } => {
let (instrs, addr) = self.generate_array_element_addr(*array, *index)?;
Some((instrs, addr, true))
}
_ => None,
}
}
fn generate_array_element_addr(&mut self, array: HirExpr, index: HirExpr) -> Option<(Vec<IRInstr>, Variable)> {
let elem_ty = array.ty.indexed_type().unwrap();
let elem_size = elem_ty.element_size_in_bytes();
let (mut instrs, base) = match array.value {
HirExprValue::Var(symbol) => {
let var = self.var_manager.get_symbol(symbol).unwrap();
if var.data_type.is_array() {
let ptr = self.var_manager.declare_temp(var.data_type.decay_to_ptr().unwrap());
(vec![IRInstr::GetAddr(ptr.clone(), var)], ptr)
} else {
(vec![], var)
}
}
HirExprValue::ArrayAccess { array, index } => self.generate_array_element_addr(*array, *index)?,
_ => self.generate_expr(array).map(|(instrs, var)| (instrs, var.unwrap()))?,
};
self.current_exit_label.push(None);
let (index_instrs, index_var) = self.generate_expr(index)?;
self.current_exit_label.pop();
instrs.extend(index_instrs);
let addr_ty = IRType::Ptr(Box::new(elem_ty.into()));
let dest = self.var_manager.declare_temp(addr_ty);
instrs.push(IRInstr::GetElementPtr(dest.clone(), base, index_var.unwrap(), elem_size));
Some((instrs, dest))
}
} }
struct VariableManager { struct VariableManager {
@@ -551,28 +614,28 @@ impl VariableManager {
} }
_ => unreachable!(), _ => unreachable!(),
}; };
self.variable_map.insert(symbol, variable); self.variable_map.insert(symbol, variable.clone());
if matches!(var_type, VariableType::Local) { if matches!(var_type, VariableType::Local) {
self.local_var_type.push(variable); self.local_var_type.push(variable.clone());
} }
variable variable
} }
pub fn declare_temp(&mut self, var_data_type: IRType) -> Variable { pub fn declare_temp(&mut self, var_data_type: IRType) -> Variable {
let var = Variable { index: self.local_counter, var_type: VariableType::Temp, data_type: var_data_type }; let var = Variable { index: self.local_counter, var_type: VariableType::Temp, data_type: var_data_type };
self.local_counter += 1; self.local_counter += 1;
self.local_var_type.push(var); self.local_var_type.push(var.clone());
var var
} }
pub fn declare_unamed_local(&mut self, var_data_type: IRType) -> Variable { pub fn declare_unamed_local(&mut self, var_data_type: IRType) -> Variable {
let var = Variable { index: self.local_counter, var_type: VariableType::Local, data_type: var_data_type }; let var = Variable { index: self.local_counter, var_type: VariableType::Local, data_type: var_data_type };
self.local_counter += 1; self.local_counter += 1;
self.local_var_type.push(var); self.local_var_type.push(var.clone());
var var
} }
pub fn declare_param_temp(&mut self, var_data_type: IRType, param_index: usize) -> Variable { pub fn declare_param_temp(&mut self, var_data_type: IRType, param_index: usize) -> Variable {
let var = Variable { index: self.local_counter, var_type: VariableType::ParamTemp(param_index), data_type: var_data_type }; let var = Variable { index: self.local_counter, var_type: VariableType::ParamTemp(param_index), data_type: var_data_type };
self.local_counter += 1; self.local_counter += 1;
self.local_var_type.push(var); self.local_var_type.push(var.clone());
var var
} }
pub fn clear_local_counter(&mut self) { pub fn clear_local_counter(&mut self) {
@@ -670,4 +733,8 @@ mod tests {
fn test_func() { fn test_func() {
test_case("12-13,58-60"); test_case("12-13,58-60");
} }
#[test]
fn test_array() {
test_case("4-7,11,42,71,74-78,82,84,86,90,95,96,100,101,103");
}
} }
+92 -7
View File
@@ -30,6 +30,10 @@ pub enum IRInstr {
CondGoto(Variable, usize, usize), // condition, true label, false label CondGoto(Variable, usize, usize), // condition, true label, false label
Label(usize), Label(usize),
Move(Variable, MoveRValue), Move(Variable, MoveRValue),
Load(Variable, Variable),
Store(Variable, Variable),
GetAddr(Variable, Variable),
GetElementPtr(Variable, Variable, Variable, usize),
} }
impl Display for IRInstr { impl Display for IRInstr {
@@ -47,7 +51,11 @@ impl Display for IRInstr {
} }
} }
IRInstr::Move(dest, src) => write!(f, "{} = {}", dest, src), IRInstr::Move(dest, src) => write!(f, "{} = {}", dest, src),
IRInstr::Declare(var) => write!(f, "declare {} {}", var.data_type, var), IRInstr::Load(dest, addr) => write!(f, "{} = *{}", dest, addr),
IRInstr::Store(addr, value) => write!(f, "*{} = {}", addr, value),
IRInstr::GetAddr(dest, var) => write!(f, "{} = getaddr {}", dest, var),
IRInstr::GetElementPtr(dest, base, index, elem_size) => write!(f, "{} = gep {}, {}, {}", dest, base, index, elem_size),
IRInstr::Declare(var) => write!(f, "declare {}", var.to_decl_string()),
IRInstr::DefineFunc(func, args, body) => { IRInstr::DefineFunc(func, args, body) => {
let body_str = body.iter().map(|instr| format!(" {}", instr)).collect::<Vec<_>>().join("\n"); let body_str = body.iter().map(|instr| format!(" {}", instr)).collect::<Vec<_>>().join("\n");
write!(f, "define {} {{\n{}\n}}", func.to_decl_string(args), body_str) write!(f, "define {} {{\n{}\n}}", func.to_decl_string(args), body_str)
@@ -59,11 +67,13 @@ impl Display for IRInstr {
} }
} }
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum IRType { pub enum IRType {
I32, I32,
I1, I1,
Void, Void,
Ptr(Box<IRType>),
Array(Box<IRType>, Vec<usize>),
} }
impl IRType { impl IRType {
pub fn size_in_bytes(&self) -> usize { pub fn size_in_bytes(&self) -> usize {
@@ -71,13 +81,47 @@ impl IRType {
IRType::I32 => 4, IRType::I32 => 4,
IRType::I1 => 1, IRType::I1 => 1,
IRType::Void => 0, IRType::Void => 0,
IRType::Ptr(_) => 4,
IRType::Array(elem, dims) => elem.size_in_bytes() * dims.iter().product::<usize>(),
} }
} }
pub fn get_elevate_result(lhs: IRType, rhs: IRType) -> Option<IRType> { pub fn is_array(&self) -> bool {
matches!(self, IRType::Array(_, _))
}
pub fn decay_to_ptr(&self) -> Option<IRType> {
match self {
IRType::Array(elem, dims) => {
let pointee = if dims.len() == 1 {
(**elem).clone()
} else {
IRType::Array(elem.clone(), dims[1..].to_vec())
};
Some(IRType::Ptr(Box::new(pointee)))
}
_ => None,
}
}
pub fn element_type(&self) -> Option<IRType> {
match self {
IRType::Array(elem, dims) => {
if dims.len() == 1 {
Some((**elem).clone())
} else {
Some(IRType::Array(elem.clone(), dims[1..].to_vec()))
}
}
IRType::Ptr(elem) => Some((**elem).clone()),
_ => None,
}
}
pub fn get_elevate_result(lhs: &IRType, rhs: &IRType) -> Option<IRType> {
if lhs == rhs { if lhs == rhs {
Some(lhs) Some(lhs.clone())
} else if (lhs == IRType::I32 && rhs == IRType::I1) || (lhs == IRType::I1 && rhs == IRType::I32) { } else if (*lhs == IRType::I32 && *rhs == IRType::I1) || (*lhs == IRType::I1 && *rhs == IRType::I32) {
Some(IRType::I32) Some(IRType::I32)
} else { } else {
None None
@@ -90,6 +134,30 @@ impl Display for IRType {
IRType::I32 => write!(f, "i32"), IRType::I32 => write!(f, "i32"),
IRType::Void => write!(f, "void"), IRType::Void => write!(f, "void"),
IRType::I1 => write!(f, "i1"), IRType::I1 => write!(f, "i1"),
IRType::Ptr(elem) => write!(f, "{}*", elem),
IRType::Array(elem, dims) => {
write!(f, "{}", elem)?;
for dim in dims {
write!(f, "[{}]", dim)?;
}
Ok(())
}
}
}
}
impl IRType {
pub fn base_type_and_dims(&self) -> (&IRType, &[usize]) {
match self {
IRType::Array(elem, dims) => (elem.as_ref(), dims.as_slice()),
_ => (self, &[]),
}
}
pub fn scalar_base_type(&self) -> &IRType {
match self {
IRType::Array(elem, _) => elem.scalar_base_type(),
IRType::Ptr(elem) => elem.scalar_base_type(),
_ => self,
} }
} }
} }
@@ -120,7 +188,7 @@ pub enum VariableType {
Local, Local,
Temp, Temp,
} }
#[derive(Clone, Copy)] #[derive(Clone)]
pub struct Variable { pub struct Variable {
// pub name: String, // pub name: String,
pub index: usize, pub index: usize,
@@ -160,6 +228,19 @@ impl Display for Variable {
write!(f, "{}{}", prefix, self.index) write!(f, "{}{}", prefix, self.index)
} }
} }
impl Variable {
pub fn to_decl_string(&self) -> String {
match &self.data_type {
IRType::Array(_, _) => {
let (base_type, dims) = self.data_type.base_type_and_dims();
let dims_str = dims.iter().map(|dim| format!("[{}]", dim)).collect::<Vec<_>>().join("");
format!("{} {}{}", base_type, self, dims_str)
}
IRType::Ptr(_) => format!("{}* {}", self.data_type.scalar_base_type(), self),
_ => format!("{} {}", self.data_type, self),
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Function { pub struct Function {
pub name: String, pub name: String,
@@ -175,7 +256,11 @@ impl Function {
} }
pub fn to_decl_string(&self, args: &Vec<Variable>) -> String { pub fn to_decl_string(&self, args: &Vec<Variable>) -> String {
let params_str = args.iter().zip(self.parameter_types.iter()).map(|(arg, param_type)| format!("{} {}", param_type, arg)).collect::<Vec<_>>().join(", "); let params_str = args.iter().zip(self.parameter_types.iter()).map(|(arg, param_type)| {
let (base_type, dims) = param_type.base_type_and_dims();
let dims_str = dims.iter().map(|dim| format!("[{}]", dim)).collect::<Vec<_>>().join("");
format!("{} {}{}", base_type, arg, dims_str)
}).collect::<Vec<_>>().join(", ");
format!("{} @{}({})", self.return_type, self.name, params_str) format!("{} @{}({})", self.return_type, self.name, params_str)
} }
} }
+106 -26
View File
@@ -2,7 +2,7 @@ use std::collections::BTreeMap;
use crate::{ use crate::{
ast::types::{ ast::types::{
BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt, ArrayDimension, BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt,
GlobalDeclStmt, IfElseBranch, IfStmt, ReturnStmt, Statement, VarDeclStmt, WhileStmt, GlobalDeclStmt, IfElseBranch, IfStmt, ReturnStmt, Statement, VarDeclStmt, WhileStmt,
}, },
diagnostic::{span::Span, Diagnositics}, diagnostic::{span::Span, Diagnositics},
@@ -38,6 +38,7 @@ impl Analyzer {
loop_depth: 0, loop_depth: 0,
}; };
analyzer.declare_builtin_func("putint", vec![SemaType::I32], SemaType::Void); analyzer.declare_builtin_func("putint", vec![SemaType::I32], SemaType::Void);
analyzer.declare_builtin_func("putch", vec![SemaType::I32], SemaType::Void);
analyzer.declare_builtin_func("getint", vec![], SemaType::I32); analyzer.declare_builtin_func("getint", vec![], SemaType::I32);
analyzer analyzer
} }
@@ -51,7 +52,7 @@ impl Analyzer {
} }
pub fn get_symbol_type(&self, symbol: SymbolId) -> SemaType { pub fn get_symbol_type(&self, symbol: SymbolId) -> SemaType {
self.symbols.get_symbol(symbol).ty self.symbols.get_symbol(symbol).ty.clone()
} }
pub fn get_symbol_kind(&self, symbol: SymbolId) -> SymbolKind { pub fn get_symbol_kind(&self, symbol: SymbolId) -> SymbolKind {
@@ -96,9 +97,10 @@ impl Analyzer {
} }
fn analyze_var_decl(&mut self, var_decl: VarDeclStmt, kind: SymbolKind) -> HirVarDeclStmt { fn analyze_var_decl(&mut self, var_decl: VarDeclStmt, kind: SymbolKind) -> HirVarDeclStmt {
let data_type = var_decl.data_type.into(); let base_type: SemaType = var_decl.data_type.into();
let mut values = vec![]; let mut values = vec![];
for value in var_decl.values { for value in var_decl.values {
let data_type = self.build_var_type(base_type.clone(), &value.dimensions, false);
match self.symbols.declare_variable(&value.name, kind, data_type) { match self.symbols.declare_variable(&value.name, kind, data_type) {
Ok(symbol) => values.push(HirVarDeclStmtValue { Ok(symbol) => values.push(HirVarDeclStmtValue {
symbol, symbol,
@@ -109,7 +111,7 @@ impl Analyzer {
} }
HirVarDeclStmt { HirVarDeclStmt {
values, values,
data_type, data_type: base_type,
type_span: var_decl.type_span, type_span: var_decl.type_span,
} }
} }
@@ -121,12 +123,15 @@ impl Analyzer {
} }
let function_id = FunctionId(self.functions.len()); let function_id = FunctionId(self.functions.len());
let parameter_types = func_decl.params.iter().map(|param| param.param_type.into()).collect::<Vec<_>>(); let mut parameter_types = vec![];
let return_type = func_decl.return_type.into(); for param in &func_decl.params {
parameter_types.push(self.build_var_type(param.param_type.into(), &param.dimensions, true));
}
let return_type: SemaType = func_decl.return_type.into();
let sig = FunctionSig { let sig = FunctionSig {
id: function_id, id: function_id,
name: func_decl.name.clone(), name: func_decl.name.clone(),
return_type, return_type: return_type.clone(),
parameter_types, parameter_types,
}; };
self.function_map.insert(func_decl.name.clone(), function_id); self.function_map.insert(func_decl.name.clone(), function_id);
@@ -137,8 +142,8 @@ impl Analyzer {
let mut params = vec![]; let mut params = vec![];
for param in func_decl.params { for param in func_decl.params {
let param_type = param.param_type.into(); let param_type = self.build_var_type(param.param_type.into(), &param.dimensions, true);
match self.symbols.declare_variable(&param.name, SymbolKind::Param, param_type) { match self.symbols.declare_variable(&param.name, SymbolKind::Param, param_type.clone()) {
Ok(symbol) => params.push(HirParam { Ok(symbol) => params.push(HirParam {
symbol, symbol,
param_type, param_type,
@@ -162,6 +167,40 @@ impl Analyzer {
}) })
} }
fn build_var_type(&mut self, base_type: SemaType, dimensions: &[ArrayDimension], is_param: bool) -> SemaType {
if dimensions.is_empty() {
return base_type;
}
let mut dims = vec![];
for (i, dimension) in dimensions.iter().enumerate() {
match &dimension.value {
Some(expr) => {
if let ExprValue::IntLit(value) = expr.value {
if value > 0 {
dims.push(value as usize);
} else {
self.add_error(SemaError::InvalidArrayDimension, dimension.span);
}
} else {
self.add_error(SemaError::InvalidArrayDimension, dimension.span);
}
}
None if is_param && i == 0 => {}
None => self.add_error(SemaError::InvalidArrayDimension, dimension.span),
}
}
if is_param {
let pointee_type = if dims.is_empty() {
base_type
} else {
SemaType::Array(Box::new(base_type), dims)
};
SemaType::Ptr(Box::new(pointee_type))
} else {
SemaType::Array(Box::new(base_type), dims)
}
}
fn analyze_block_stmt(&mut self, block_stmt: BlockStmt) -> HirBlockStmt { fn analyze_block_stmt(&mut self, block_stmt: BlockStmt) -> HirBlockStmt {
let mut statements = vec![]; let mut statements = vec![];
for stmt in block_stmt.statements { for stmt in block_stmt.statements {
@@ -191,7 +230,7 @@ impl Analyzer {
} }
fn analyze_return_stmt(&mut self, return_stmt: ReturnStmt) -> HirReturnStmt { fn analyze_return_stmt(&mut self, return_stmt: ReturnStmt) -> HirReturnStmt {
let expected_ty = self.current_func_return_type.unwrap(); let expected_ty = self.current_func_return_type.clone().unwrap();
let value = match return_stmt.value { let value = match return_stmt.value {
Some(expr) => { Some(expr) => {
if expected_ty == SemaType::Void { if expected_ty == SemaType::Void {
@@ -202,8 +241,8 @@ impl Analyzer {
Some(expr) => { Some(expr) => {
if expr.ty == SemaType::Void { if expr.ty == SemaType::Void {
self.add_error(SemaError::InvalidOperand(SemaType::Void), return_stmt.span); self.add_error(SemaError::InvalidOperand(SemaType::Void), return_stmt.span);
} else if expr.ty != expected_ty { } else if !self.type_matches(&expected_ty, &expr.ty) {
self.add_error(SemaError::TypeMismatch(expected_ty, expr.ty), return_stmt.span); self.add_error(SemaError::TypeMismatch(expected_ty.clone(), expr.ty.clone()), return_stmt.span);
} }
Some(expr) Some(expr)
} }
@@ -304,11 +343,12 @@ impl Analyzer {
}; };
Some(HirExpr { Some(HirExpr {
value: HirExprValue::Var(symbol), value: HirExprValue::Var(symbol),
ty: self.symbols.get_symbol(symbol).ty, ty: self.symbols.get_symbol(symbol).ty.clone(),
span, span,
}) })
} }
ExprValue::Assign { lvalue, rvalue } => self.analyze_assign_expr(*lvalue, *rvalue, span), ExprValue::Assign { lvalue, rvalue } => self.analyze_assign_expr(*lvalue, *rvalue, span),
ExprValue::ArrayAccess { array, index } => self.analyze_array_access_expr(*array, *index, span),
ExprValue::UnaryOp { op, operand } => { ExprValue::UnaryOp { op, operand } => {
let operand_span = operand.span; let operand_span = operand.span;
let operand = self.analyze_expr(*operand)?; let operand = self.analyze_expr(*operand)?;
@@ -318,7 +358,7 @@ impl Analyzer {
} }
let ty = match op { let ty = match op {
crate::ast::types::UnaryOp::Not => SemaType::I1, crate::ast::types::UnaryOp::Not => SemaType::I1,
_ => operand.ty, _ => operand.ty.clone(),
}; };
Some(HirExpr { Some(HirExpr {
value: HirExprValue::UnaryOp { value: HirExprValue::UnaryOp {
@@ -335,19 +375,27 @@ impl Analyzer {
} }
fn analyze_assign_expr(&mut self, lvalue: Expr, rvalue: Expr, span: Span) -> Option<HirExpr> { fn analyze_assign_expr(&mut self, lvalue: Expr, rvalue: Expr, span: Span) -> Option<HirExpr> {
if !matches!(lvalue.value, ExprValue::Var(_)) { if !matches!(lvalue.value, ExprValue::Var(_) | ExprValue::ArrayAccess { .. }) {
self.add_error(SemaError::InvalidAssignmentTarget, lvalue.span); self.add_error(SemaError::InvalidAssignmentTarget, lvalue.span);
return None; return None;
} }
let lvalue = self.analyze_expr(lvalue)?; let lvalue = self.analyze_expr(lvalue)?;
if lvalue.ty.is_array_like() {
self.add_error(SemaError::InvalidAssignmentTarget, lvalue.span);
return None;
}
let rvalue_span = rvalue.span; let rvalue_span = rvalue.span;
let rvalue = self.analyze_expr(rvalue)?; let rvalue = self.analyze_expr(rvalue)?;
if rvalue.ty == SemaType::Void { if rvalue.ty == SemaType::Void {
self.add_error(SemaError::InvalidOperand(SemaType::Void), rvalue_span); self.add_error(SemaError::InvalidOperand(SemaType::Void), rvalue_span);
return None; return None;
} }
if !self.type_matches(&lvalue.ty, &rvalue.ty) {
self.add_error(SemaError::TypeMismatch(lvalue.ty.clone(), rvalue.ty.clone()), span);
return None;
}
Some(HirExpr { Some(HirExpr {
ty: lvalue.ty, ty: lvalue.ty.clone(),
value: HirExprValue::Assign { value: HirExprValue::Assign {
lvalue: Box::new(lvalue), lvalue: Box::new(lvalue),
rvalue: Box::new(rvalue), rvalue: Box::new(rvalue),
@@ -361,24 +409,24 @@ impl Analyzer {
let rhs_span = rhs.span; let rhs_span = rhs.span;
let lhs = self.analyze_expr(lhs)?; let lhs = self.analyze_expr(lhs)?;
let rhs = self.analyze_expr(rhs)?; let rhs = self.analyze_expr(rhs)?;
if lhs.ty == SemaType::Void { if !lhs.ty.is_scalar() {
self.add_error(SemaError::InvalidOperand(SemaType::Void), lhs_span); self.add_error(SemaError::InvalidOperand(lhs.ty.clone()), lhs_span);
return None; return None;
} }
if rhs.ty == SemaType::Void { if !rhs.ty.is_scalar() {
self.add_error(SemaError::InvalidOperand(SemaType::Void), rhs_span); self.add_error(SemaError::InvalidOperand(rhs.ty.clone()), rhs_span);
return None; return None;
} }
let result_ty = if op.is_logical() { let result_ty = if op.is_logical() {
SemaType::I1 SemaType::I1
} else { } else {
match SemaType::get_elevate_result(lhs.ty, rhs.ty) { match SemaType::get_elevate_result(&lhs.ty, &rhs.ty) {
Some(_) if op.is_cmp() => SemaType::I1, Some(_) if op.is_cmp() => SemaType::I1,
Some(ty) => ty, Some(ty) => ty,
None => { None => {
self.add_error(SemaError::IncompatiableOperand(lhs.ty, rhs.ty), lhs_span); self.add_error(SemaError::IncompatiableOperand(lhs.ty.clone(), rhs.ty.clone()), lhs_span);
self.add_error(SemaError::IncompatiableOperand(lhs.ty, rhs.ty), rhs_span); self.add_error(SemaError::IncompatiableOperand(lhs.ty.clone(), rhs.ty.clone()), rhs_span);
return None; return None;
} }
} }
@@ -428,9 +476,9 @@ impl Analyzer {
let mut hir_args = vec![]; let mut hir_args = vec![];
for (i, arg) in args.into_iter().enumerate() { for (i, arg) in args.into_iter().enumerate() {
let arg = self.analyze_expr(arg)?; let arg = self.analyze_expr(arg)?;
let parameter_type = func_def.parameter_types[i]; let parameter_type = func_def.parameter_types[i].clone();
if parameter_type != arg.ty { if !self.type_matches(&parameter_type, &arg.ty) {
self.add_error(SemaError::TypeMismatch(parameter_type, arg.ty), span); self.add_error(SemaError::TypeMismatch(parameter_type, arg.ty.clone()), span);
has_error = true; has_error = true;
continue; continue;
} }
@@ -446,4 +494,36 @@ impl Analyzer {
span, span,
}) })
} }
fn analyze_array_access_expr(&mut self, array: Expr, index: Expr, span: Span) -> Option<HirExpr> {
let index_span = index.span;
let array = self.analyze_expr(array)?;
let index = self.analyze_expr(index)?;
if !index.ty.is_scalar() {
self.add_error(SemaError::InvalidOperand(index.ty.clone()), index_span);
return None;
}
let ty = match array.ty.indexed_type() {
Some(ty) => ty,
None => {
self.add_error(SemaError::NotSubscriptable, span);
return None;
}
};
Some(HirExpr {
value: HirExprValue::ArrayAccess {
array: Box::new(array),
index: Box::new(index),
},
ty,
span,
})
}
fn type_matches(&self, expected: &SemaType, actual: &SemaType) -> bool {
if expected == actual {
return true;
}
matches!((expected, actual), (SemaType::Ptr(expected_elem), SemaType::Array(_, _)) if actual.indexed_type().is_some_and(|ty| &ty == expected_elem.as_ref()))
}
} }
+4
View File
@@ -32,4 +32,8 @@ pub enum SemaError {
InvalidParameterType(SemaType), InvalidParameterType(SemaType),
#[error("return expression on void function")] #[error("return expression on void function")]
ReturnExpressionOnVoidFunction, ReturnExpressionOnVoidFunction,
#[error("array dimension must be a positive integer literal")]
InvalidArrayDimension,
#[error("subscripted value is not an array or pointer")]
NotSubscriptable,
} }
+4
View File
@@ -89,6 +89,10 @@ pub struct HirExpr {
pub enum HirExprValue { pub enum HirExprValue {
IntLit(i64), IntLit(i64),
Var(SymbolId), Var(SymbolId),
ArrayAccess {
array: Box<HirExpr>,
index: Box<HirExpr>,
},
BinaryOp { BinaryOp {
lhs: Box<HirExpr>, lhs: Box<HirExpr>,
op: BinaryOp, op: BinaryOp,
+48 -4
View File
@@ -2,23 +2,57 @@ use std::fmt::Display;
use crate::{ast::types::Type as AstType, ir::types::IRType}; use crate::{ast::types::Type as AstType, ir::types::IRType};
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum SemaType { pub enum SemaType {
I32, I32,
I1, I1,
Void, Void,
Array(Box<SemaType>, Vec<usize>),
Ptr(Box<SemaType>),
} }
impl SemaType { impl SemaType {
pub fn get_elevate_result(lhs: SemaType, rhs: SemaType) -> Option<SemaType> { pub fn get_elevate_result(lhs: &SemaType, rhs: &SemaType) -> Option<SemaType> {
if lhs == rhs { if lhs == rhs {
Some(lhs) Some(lhs.clone())
} else if (lhs == SemaType::I32 && rhs == SemaType::I1) || (lhs == SemaType::I1 && rhs == SemaType::I32) { } else if (*lhs == SemaType::I32 && *rhs == SemaType::I1) || (*lhs == SemaType::I1 && *rhs == SemaType::I32) {
Some(SemaType::I32) Some(SemaType::I32)
} else { } else {
None None
} }
} }
pub fn is_scalar(&self) -> bool {
matches!(self, SemaType::I32 | SemaType::I1)
}
pub fn is_array_like(&self) -> bool {
matches!(self, SemaType::Array(_, _) | SemaType::Ptr(_))
}
pub fn indexed_type(&self) -> Option<SemaType> {
match self {
SemaType::Array(elem, dims) => {
if dims.len() == 1 {
Some((**elem).clone())
} else {
Some(SemaType::Array(elem.clone(), dims[1..].to_vec()))
}
}
SemaType::Ptr(elem) => Some((**elem).clone()),
_ => None,
}
}
pub fn element_size_in_bytes(&self) -> usize {
match self {
SemaType::I32 => 4,
SemaType::I1 => 1,
SemaType::Void => 0,
SemaType::Array(elem, dims) => elem.element_size_in_bytes() * dims.iter().product::<usize>(),
SemaType::Ptr(_) => 4,
}
}
} }
impl Display for SemaType { impl Display for SemaType {
@@ -27,6 +61,14 @@ impl Display for SemaType {
SemaType::I32 => write!(f, "i32"), SemaType::I32 => write!(f, "i32"),
SemaType::I1 => write!(f, "i1"), SemaType::I1 => write!(f, "i1"),
SemaType::Void => write!(f, "void"), SemaType::Void => write!(f, "void"),
SemaType::Array(elem, dims) => {
write!(f, "{}", elem)?;
for dim in dims {
write!(f, "[{}]", dim)?;
}
Ok(())
}
SemaType::Ptr(elem) => write!(f, "{}*", elem),
} }
} }
} }
@@ -46,6 +88,8 @@ impl From<SemaType> for IRType {
SemaType::I32 => IRType::I32, SemaType::I32 => IRType::I32,
SemaType::I1 => IRType::I1, SemaType::I1 => IRType::I1,
SemaType::Void => IRType::Void, SemaType::Void => IRType::Void,
SemaType::Array(elem, dims) => IRType::Array(Box::new((*elem).into()), dims),
SemaType::Ptr(elem) => IRType::Ptr(Box::new((*elem).into())),
} }
} }
} }