malloc structs and allow using them as types
This commit is contained in:
@@ -8,6 +8,7 @@ use crate::{
|
|||||||
pub struct Analyzer {
|
pub struct Analyzer {
|
||||||
pub functions: HashMap<String, i32>,
|
pub functions: HashMap<String, i32>,
|
||||||
pub constants: HashMap<String, u64>,
|
pub constants: HashMap<String, u64>,
|
||||||
|
pub structs: HashMap<String, HashMap<String, usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Analyzer {
|
impl Analyzer {
|
||||||
@@ -15,6 +16,7 @@ impl Analyzer {
|
|||||||
Analyzer {
|
Analyzer {
|
||||||
functions: HashMap::new(),
|
functions: HashMap::new(),
|
||||||
constants: HashMap::new(),
|
constants: HashMap::new(),
|
||||||
|
structs: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +119,17 @@ impl Analyzer {
|
|||||||
}
|
}
|
||||||
self.functions.insert(name.lexeme.clone(), -1);
|
self.functions.insert(name.lexeme.clone(), -1);
|
||||||
}
|
}
|
||||||
Stmt::Struct { name: _, fields: _ } => todo!(),
|
Stmt::Struct { name, fields } => {
|
||||||
|
let mut fields_map: HashMap<String, usize> = HashMap::new();
|
||||||
|
|
||||||
|
let mut offset: usize = 0;
|
||||||
|
for field in fields {
|
||||||
|
fields_map.insert(field.var_name.lexeme.clone(), offset);
|
||||||
|
offset += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.structs.insert(name.lexeme.clone(), fields_map);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,9 @@ macro_rules! emit {
|
|||||||
|
|
||||||
static REGISTERS: [&str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
static REGISTERS: [&str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
||||||
|
|
||||||
|
// TODO: currently they are all just 64 bit values
|
||||||
|
static BUILTIN_TYPES: [&str; 7] = ["void", "u8", "i64", "str", "bool", "ptr", "array"];
|
||||||
|
|
||||||
pub struct CodegenX86_64<'a> {
|
pub struct CodegenX86_64<'a> {
|
||||||
output: String,
|
output: String,
|
||||||
data_section: String,
|
data_section: String,
|
||||||
@@ -170,6 +173,10 @@ _builtin_environ:
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !self.is_valid_type_name(&var_type) {
|
||||||
|
return error!(&name.loc, "unrecognized type: ".to_owned() + &var_type);
|
||||||
|
}
|
||||||
|
|
||||||
self.compile_expr(env, initializer)?;
|
self.compile_expr(env, initializer)?;
|
||||||
let offset = env.define_var(name.lexeme.clone(), var_type);
|
let offset = env.define_var(name.lexeme.clone(), var_type);
|
||||||
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
|
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
|
||||||
@@ -627,8 +634,25 @@ _builtin_environ:
|
|||||||
return error!(&op.loc, "can only take address of variables and functions");
|
return error!(&op.loc, "can only take address of variables and functions");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Expr::New(_) => todo!(),
|
Expr::New(struct_name) => {
|
||||||
|
let struct_fields = &self.analyzer.structs[&struct_name.lexeme];
|
||||||
|
|
||||||
|
let memory_size = struct_fields.len() * 8;
|
||||||
|
|
||||||
|
emit!(&mut self.output, " mov rdi, {}", memory_size);
|
||||||
|
emit!(&mut self.output, " call malloc");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_valid_type_name(&self, name: &str) -> bool {
|
||||||
|
if BUILTIN_TYPES.contains(&name) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if self.analyzer.structs.contains_key(name) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,9 +91,6 @@ pub enum Expr {
|
|||||||
New(Token),
|
New(Token),
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: currently they are all just 64 bit values
|
|
||||||
static TYPES: [&str; 7] = ["void", "u8", "i64", "str", "bool", "ptr", "array"];
|
|
||||||
|
|
||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
tokens: Vec<Token>,
|
tokens: Vec<Token>,
|
||||||
current: usize,
|
current: usize,
|
||||||
@@ -159,9 +156,6 @@ impl Parser {
|
|||||||
self.consume(TokenType::Colon, "expected ':' after parameter name")?;
|
self.consume(TokenType::Colon, "expected ':' after parameter name")?;
|
||||||
|
|
||||||
let var_type = self.consume(TokenType::Identifier, "expected parameter type")?;
|
let var_type = self.consume(TokenType::Identifier, "expected parameter type")?;
|
||||||
if !TYPES.contains(&var_type.lexeme.as_str()) {
|
|
||||||
return error!(&name.loc, format!("unknown type: {}", var_type.lexeme));
|
|
||||||
}
|
|
||||||
|
|
||||||
params.push(Param { var_type, var_name });
|
params.push(Param { var_type, var_name });
|
||||||
if !self.match_token(&[TokenType::Comma]) {
|
if !self.match_token(&[TokenType::Comma]) {
|
||||||
@@ -173,9 +167,6 @@ impl Parser {
|
|||||||
self.consume(TokenType::RightBracket, "expected ']' after arguments")?;
|
self.consume(TokenType::RightBracket, "expected ']' after arguments")?;
|
||||||
self.consume(TokenType::Colon, "expected ':' after '['")?;
|
self.consume(TokenType::Colon, "expected ':' after '['")?;
|
||||||
let return_type = self.consume(TokenType::Identifier, "expected return type")?;
|
let return_type = self.consume(TokenType::Identifier, "expected return type")?;
|
||||||
if !TYPES.contains(&return_type.lexeme.as_str()) {
|
|
||||||
return error!(&name.loc, format!("unknown type: {}", return_type.lexeme));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.is_inside_function = true;
|
self.is_inside_function = true;
|
||||||
let body = Box::new(self.block()?);
|
let body = Box::new(self.block()?);
|
||||||
@@ -201,9 +192,6 @@ impl Parser {
|
|||||||
self.consume(TokenType::Colon, "expected ':' after field name")?;
|
self.consume(TokenType::Colon, "expected ':' after field name")?;
|
||||||
|
|
||||||
let var_type = self.consume(TokenType::Identifier, "expected field type")?;
|
let var_type = self.consume(TokenType::Identifier, "expected field type")?;
|
||||||
if !TYPES.contains(&var_type.lexeme.as_str()) {
|
|
||||||
return error!(&name.loc, format!("unknown type: {}", var_type.lexeme));
|
|
||||||
}
|
|
||||||
|
|
||||||
fields.push(Param { var_type, var_name });
|
fields.push(Param { var_type, var_name });
|
||||||
}
|
}
|
||||||
@@ -218,9 +206,6 @@ impl Parser {
|
|||||||
|
|
||||||
let var_type = if self.match_token(&[TokenType::Colon]) {
|
let var_type = if self.match_token(&[TokenType::Colon]) {
|
||||||
let token = self.consume(TokenType::Identifier, "expected variable type")?;
|
let token = self.consume(TokenType::Identifier, "expected variable type")?;
|
||||||
if !TYPES.contains(&token.lexeme.as_str()) {
|
|
||||||
return error!(&name.loc, format!("unknown type: {}", token.lexeme));
|
|
||||||
}
|
|
||||||
Some(token)
|
Some(token)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|||||||
Reference in New Issue
Block a user