Skip to content

Commit

Permalink
feat: array expressions
Browse files Browse the repository at this point in the history
closes #44
  • Loading branch information
MilkeeyCat committed Sep 4, 2024
1 parent bf9bc80 commit 6ef43b7
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 18 deletions.
66 changes: 63 additions & 3 deletions src/codegen/codegen.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use operands::{Base, Memory};

use super::{operands, CodeGenError, Destination, EffectiveAddress, Immediate, Offset, Source};
use crate::{
archs::{Arch, Jump},
parser::{
BinOp, CmpOp, Expr, ExprArrayAccess, ExprBinary, ExprFunctionCall, ExprIdent, ExprLit,
ExprStruct, ExprStructAccess, ExprUnary, Expression, LValue, Stmt, StmtFor, StmtFunction,
StmtIf, StmtReturn, StmtVarDecl, StmtWhile, UnOp,
BinOp, CmpOp, Expr, ExprArray, ExprArrayAccess, ExprBinary, ExprFunctionCall, ExprIdent,
ExprLit, ExprStruct, ExprStructAccess, ExprUnary, Expression, IntLitRepr, LValue, Stmt,
StmtFor, StmtFunction, StmtIf, StmtReturn, StmtVarDecl, StmtWhile, UIntLitRepr, UnOp,
},
scope::Scope,
symbol_table::{Symbol, SymbolTableError},
Expand Down Expand Up @@ -315,6 +317,11 @@ impl CodeGen {
self.struct_expr(expr, dest, state)?
}
}
Expr::Array(expr) => {
if let Some(dest) = dest {
self.array_expr(expr, dest, state)?
}
}
Expr::StructAccess(expr) => {
if let Some(dest) = dest {
self.struct_access(expr, dest)?;
Expand Down Expand Up @@ -736,6 +743,59 @@ impl CodeGen {
Ok(())
}

fn array_expr(
&mut self,
expr: ExprArray,
dest: Destination,
state: Option<&State>,
) -> Result<(), CodeGenError> {
for (i, expr) in expr.0.into_iter().enumerate() {
let size = expr.type_(&self.scope)?.size(&self.arch, &self.scope)?;
let index = self.arch.alloc()?;
let r = self.arch.alloc()?;
let r_loc = r.dest(self.arch.word_size());

self.arch.mov(
&Source::Immediate(Immediate::UInt(i as u64)),
&index.dest(self.arch.word_size()),
false,
)?;

self.arch.lea(
&Destination::Register(operands::Register {
register: r,
size: self.arch.word_size(),
}),
&EffectiveAddress {
base: dest.clone().into(),
index: Some(index),
scale: None,
displacement: None,
},
);

self.arch
.array_offset(&r_loc, &index.dest(self.arch.word_size()), size)?;

self.expr(
expr,
Some(Destination::Memory(Memory {
effective_address: EffectiveAddress {
base: Base::Register(r),
index: None,
scale: None,
displacement: None,
},
size,
})),
state,
)?;
self.arch.free(r)?;
}

Ok(())
}

fn struct_access(
&mut self,
expr: ExprStructAccess,
Expand Down
61 changes: 52 additions & 9 deletions src/parser/expr/expr.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashSet;

use super::{int_repr::UIntLitRepr, ExprError, IntLitRepr};
use crate::{
archs::ArchError,
Expand All @@ -6,7 +8,7 @@ use crate::{
scope::Scope,
symbol_table::{Symbol, SymbolTableError},
type_table,
types::{Type, TypeError},
types::{Type, TypeArray, TypeError},
};
use operands::{Base, EffectiveAddress, Memory};

Expand All @@ -26,6 +28,7 @@ pub enum Expr {
Lit(ExprLit),
Ident(ExprIdent),
Struct(ExprStruct),
Array(ExprArray),
StructAccess(ExprStructAccess),
ArrayAccess(ExprArrayAccess),
FunctionCall(ExprFunctionCall),
Expand All @@ -40,6 +43,7 @@ impl Expression for Expr {
Self::Ident(ident) => ident.type_(scope),
Self::Cast(cast) => cast.type_(scope),
Self::Struct(expr_struct) => expr_struct.type_(scope),
Self::Array(expr) => expr.type_(scope),
Self::StructAccess(expr_struct_access) => expr_struct_access.type_(scope),
Self::ArrayAccess(expr) => expr.type_(scope),
Self::FunctionCall(function_call) => {
Expand Down Expand Up @@ -284,6 +288,35 @@ impl ExprStruct {
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct ExprArray(pub Vec<Expr>);

impl Expression for ExprArray {
fn type_(&self, scope: &Scope) -> Result<Type, ExprError> {
Ok(Type::Array(TypeArray {
type_: Box::new(self.0.get(0).unwrap().type_(scope)?),
length: self.0.len(),
}))
}
}

impl ExprArray {
pub fn new(items: Vec<Expr>, scope: &Scope) -> Self {
let unique = items
.iter()
.map(|item| item.type_(scope).unwrap())
.collect::<HashSet<_>>()
.into_iter()
.collect::<Vec<_>>();

if unique.len() != 1 {
panic!("Types only of the same type allowed in an array expression")
}

Self(items)
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct ExprStructAccess {
pub expr: Box<Expr>,
Expand Down Expand Up @@ -383,6 +416,13 @@ impl LValue for ExprArrayAccess {
let r = codegen.arch.alloc()?;
let r_loc = r.dest(codegen.arch.word_size());

codegen
.expr(
*self.index.clone(),
Some(index.dest(codegen.arch.word_size())),
None,
)
.unwrap();
codegen.arch.lea(
&Destination::Register(operands::Register {
register: r,
Expand All @@ -395,21 +435,24 @@ impl LValue for ExprArrayAccess {
displacement: None,
},
);
codegen
.expr(
*self.index.clone(),
Some(index.dest(codegen.arch.word_size())),
None,
)
.unwrap();
codegen.arch.array_offset(
&r_loc,
&index.dest(codegen.arch.word_size()),
self.type_(&codegen.scope)?
.size(&codegen.arch, &codegen.scope)?,
)?;

Ok(r_loc)
Ok(Destination::Memory(Memory {
effective_address: EffectiveAddress {
base: Base::Register(r),
index: None,
scale: None,
displacement: None,
},
size: self
.type_(&codegen.scope)?
.size(&codegen.arch, &codegen.scope)?,
}))
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/parser/expr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ mod int_repr;

pub use error::ExprError;
pub use expr::{
Expr, ExprArrayAccess, ExprBinary, ExprCast, ExprFunctionCall, ExprIdent, ExprLit, ExprStruct,
ExprStructAccess, ExprUnary, Expression, LValue,
Expr, ExprArray, ExprArrayAccess, ExprBinary, ExprCast, ExprFunctionCall, ExprIdent, ExprLit,
ExprStruct, ExprStructAccess, ExprUnary, Expression, LValue,
};
pub use int_repr::{IntLitRepr, IntLitReprError, UIntLitRepr};
22 changes: 20 additions & 2 deletions src/parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use super::{
expr::{ExprBinary, ExprLit, ExprUnary},
precedence::Precedence,
stmt::{StmtFor, StmtIf, StmtReturn, StmtWhile},
BinOp, Block, Expr, ExprArrayAccess, ExprCast, ExprIdent, ExprStruct, Expression, ParserError,
Stmt, StmtFunction, StmtVarDecl, UIntLitRepr, UnOp,
BinOp, Block, Expr, ExprArray, ExprArrayAccess, ExprCast, ExprIdent, ExprStruct, Expression,
ParserError, Stmt, StmtFunction, StmtVarDecl, UIntLitRepr, UnOp,
};
use crate::{
codegen::Offset,
Expand Down Expand Up @@ -49,6 +49,7 @@ impl Parser {
(Token::LParen, Self::grouped_expr),
(Token::Ampersand, Self::addr_expr),
(Token::Asterisk, Self::deref_expr),
(Token::LBracket, Self::array_expr),
]),
infix_fns: HashMap::from([
(Token::Plus, Self::bin_expr as InfixFn),
Expand Down Expand Up @@ -765,6 +766,23 @@ impl Parser {

Ok(Expr::Unary(ExprUnary::new(UnOp::Deref, Box::new(expr))))
}

fn array_expr(&mut self) -> Result<Expr, ParserError> {
self.expect(&Token::LBracket)?;
let mut items = Vec::new();

while !self.cur_token_is(&Token::RBracket) {
items.push(self.expr(Precedence::default())?);

if !self.cur_token_is(&Token::RBracket) {
self.expect(&Token::Comma)?;
}
}

self.expect(&Token::RBracket)?;

Ok(Expr::Array(ExprArray::new(items, &self.scope)))
}
}

#[cfg(test)]
Expand Down
4 changes: 2 additions & 2 deletions src/types/types.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use super::TypeError;
use crate::{archs::Arch, scope::Scope};

#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
pub struct TypeArray {
pub type_: Box<Type>,
pub length: usize,
}

#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
pub enum Type {
U8,
I8,
Expand Down

0 comments on commit 6ef43b7

Please sign in to comment.