add Stmt::Struct and Expr::New

This commit is contained in:
2026-03-10 18:32:58 +01:00
parent 0dc130b85c
commit 316e60eedb
4 changed files with 54 additions and 4 deletions

View File

@@ -117,6 +117,7 @@ impl Analyzer {
} }
self.functions.insert(name.lexeme.clone(), -1); self.functions.insert(name.lexeme.clone(), -1);
} }
Stmt::Struct { name: _, fields: _ } => todo!(),
} }
Ok(()) Ok(())
} }
@@ -188,6 +189,7 @@ impl Analyzer {
Expr::AddrOf { op: _, expr } => { Expr::AddrOf { op: _, expr } => {
self.analyze_expr(expr)?; self.analyze_expr(expr)?;
} }
Expr::New(_) => {}
} }
Ok(()) Ok(())
} }

View File

@@ -6,8 +6,9 @@ use crate::{
tokenizer::{TokenType, ZernError, error}, tokenizer::{TokenType, ZernError, error},
}; };
pub struct Var { struct Var {
pub stack_offset: usize, pub stack_offset: usize,
pub var_type: String,
} }
pub struct Env { pub struct Env {
@@ -37,19 +38,20 @@ impl Env {
self.scopes.pop(); self.scopes.pop();
} }
pub fn define_var(&mut self, name: String, _var_type: String) -> usize { pub fn define_var(&mut self, name: String, var_type: String) -> usize {
let offset = self.next_offset; let offset = self.next_offset;
self.next_offset += 8; self.next_offset += 8;
self.scopes.last_mut().unwrap().insert( self.scopes.last_mut().unwrap().insert(
name, name,
Var { Var {
stack_offset: offset, stack_offset: offset,
var_type,
}, },
); );
offset offset
} }
pub fn get_var(&self, name: &str) -> Option<&Var> { fn get_var(&self, name: &str) -> Option<&Var> {
for scope in self.scopes.iter().rev() { for scope in self.scopes.iter().rev() {
if let Some(var) = scope.get(name) { if let Some(var) = scope.get(name) {
return Some(var); return Some(var);
@@ -315,6 +317,9 @@ _builtin_environ:
Stmt::Extern(name) => { Stmt::Extern(name) => {
emit!(&mut self.output, "extern {}", name.lexeme); emit!(&mut self.output, "extern {}", name.lexeme);
} }
Stmt::Struct { name: _, fields: _ } => {
// handled in the analyzer
}
} }
Ok(()) Ok(())
} }
@@ -622,6 +627,7 @@ _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!(),
} }
Ok(()) Ok(())
} }

View File

@@ -45,6 +45,10 @@ pub enum Stmt {
Break, Break,
Continue, Continue,
Extern(Token), Extern(Token),
Struct {
name: Token,
fields: Vec<Param>,
},
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -84,6 +88,7 @@ pub enum Expr {
op: Token, op: Token,
expr: Box<Expr>, expr: Box<Expr>,
}, },
New(Token),
} }
// TODO: currently they are all just 64 bit values // TODO: currently they are all just 64 bit values
@@ -127,6 +132,9 @@ impl Parser {
if self.match_token(&[TokenType::KeywordConst]) { if self.match_token(&[TokenType::KeywordConst]) {
return self.const_declaration(); return self.const_declaration();
} }
if self.match_token(&[TokenType::KeywordStruct]) {
return self.struct_declaration();
}
return error!( return error!(
self.peek().loc, self.peek().loc,
"statements not allowed outside function body" "statements not allowed outside function body"
@@ -182,6 +190,29 @@ impl Parser {
}) })
} }
fn struct_declaration(&mut self) -> Result<Stmt, ZernError> {
let name = self.consume(TokenType::Identifier, "expected struct name")?;
self.consume(TokenType::Indent, "expected indent after struct name")?;
let mut fields = vec![];
while !self.eof() && !self.check(&TokenType::Dedent) {
let var_name = self.consume(TokenType::Identifier, "expected field name")?;
self.consume(TokenType::Colon, "expected ':' after field name")?;
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 });
}
self.consume(TokenType::Dedent, "expected dedent after the struct fields")?;
Ok(Stmt::Struct { name, fields })
}
fn let_declaration(&mut self) -> Result<Stmt, ZernError> { fn let_declaration(&mut self) -> Result<Stmt, ZernError> {
let name = self.consume(TokenType::Identifier, "expected variable name")?; let name = self.consume(TokenType::Identifier, "expected variable name")?;
@@ -524,10 +555,17 @@ impl Parser {
self.consume(TokenType::RightBracket, "expected ']' after values")?; self.consume(TokenType::RightBracket, "expected ']' after values")?;
Ok(Expr::ArrayLiteral(xs)) Ok(Expr::ArrayLiteral(xs))
} else if self.match_token(&[TokenType::KeywordNew]) {
let struct_name =
self.consume(TokenType::Identifier, "expected struct name after 'new'")?;
Ok(Expr::New(struct_name))
} else if self.match_token(&[TokenType::Identifier]) { } else if self.match_token(&[TokenType::Identifier]) {
Ok(Expr::Variable(self.previous().clone())) Ok(Expr::Variable(self.previous().clone()))
} else { } else {
error!(self.peek().loc, "expected expression") error!(
self.peek().loc,
format!("expected expression, got '{}'", self.peek().lexeme)
)
} }
} }

View File

@@ -52,6 +52,8 @@ pub enum TokenType {
KeywordContinue, KeywordContinue,
KeywordExtern, KeywordExtern,
KeywordExport, KeywordExport,
KeywordStruct,
KeywordNew,
Indent, Indent,
Dedent, Dedent,
@@ -347,6 +349,8 @@ impl Tokenizer {
"continue" => TokenType::KeywordContinue, "continue" => TokenType::KeywordContinue,
"extern" => TokenType::KeywordExtern, "extern" => TokenType::KeywordExtern,
"export" => TokenType::KeywordExport, "export" => TokenType::KeywordExport,
"struct" => TokenType::KeywordStruct,
"new" => TokenType::KeywordNew,
"true" => TokenType::True, "true" => TokenType::True,
"false" => TokenType::False, "false" => TokenType::False,
_ => TokenType::Identifier, _ => TokenType::Identifier,