diff --git a/hblang/src/codegen.rs b/hblang/src/codegen.rs index cf2c8a8..9bf7462 100644 --- a/hblang/src/codegen.rs +++ b/hblang/src/codegen.rs @@ -984,14 +984,14 @@ impl<'a> Codegen<'a> { } } E::BinOp { - left: E::Ident { id, .. }, + left: E::Ident { id, last, .. }, op: T::Decl, right, } => { let val = self.expr(right)?; let loc = self.make_loc_owned(val.loc, val.ty); let loc = match loc { - Loc::Reg(r) => { + Loc::Reg(r) if last.is_some_and(|l| l.get() & parser::REFERENCED != 0) => { let size = self.size_of(val.ty); let stack = self.alloc_stack(size); self.store_stack(r.0, stack.offset, size as _); @@ -1033,14 +1033,20 @@ impl<'a> Codegen<'a> { loc, }); } - E::Ident { name, id, last } => { - let Some((index, var)) = self.vars.iter_mut().enumerate().find(|(_, v)| v.id == id) + E::Ident { + name, + id, + last, + index, + } => { + let Some((var_index, var)) = + self.vars.iter_mut().enumerate().find(|(_, v)| v.id == id) else { self.report(expr.pos(), format_args!("unknown variable: {}", name)) }; - let loc = match last.is_some_and(Cell::get) - && !self.loops.last().is_some_and(|l| l.var_count > index) + let loc = match last.is_some_and(|l| parser::ident_flag_index(l.get()) == index) + && !self.loops.last().is_some_and(|l| l.var_count > var_index) { true => std::mem::replace(&mut var.value.loc, Loc::Imm(0)), false => var.value.loc.take_ref(), diff --git a/hblang/src/parser.rs b/hblang/src/parser.rs index a3ec118..f3f6a07 100644 --- a/hblang/src/parser.rs +++ b/hblang/src/parser.rs @@ -8,18 +8,28 @@ use crate::{ pub type Pos = u32; +pub type IdentFlags = u32; + +pub const MUTABLE: IdentFlags = 1 << std::mem::size_of::() * 8 - 1; +pub const REFERENCED: IdentFlags = 1 << std::mem::size_of::() * 8 - 2; + +pub fn ident_flag_index(flag: IdentFlags) -> u32 { + flag & !(MUTABLE | REFERENCED) +} + struct ScopeIdent<'a> { ident: Ident, declared: bool, - last: &'a Cell, + last: &'a Cell, } pub struct Parser<'a, 'b> { - path: &'a str, - lexer: Lexer<'a>, - arena: &'b Arena<'a>, - token: Token, - idents: Vec>, + path: &'a str, + lexer: Lexer<'a>, + arena: &'b Arena<'a>, + token: Token, + idents: Vec>, + referening: bool, } impl<'a, 'b> Parser<'a, 'b> { @@ -32,6 +42,7 @@ impl<'a, 'b> Parser<'a, 'b> { path: "", arena, idents: Vec::new(), + referening: false, } } @@ -91,6 +102,7 @@ impl<'a, 'b> Parser<'a, 'b> { let left = &*self.arena.alloc(fold); if let Some(op) = op.assign_op() { + fold.mark_mut(); let right = Expr::BinOp { left, op, right }; fold = Expr::BinOp { left, @@ -99,6 +111,9 @@ impl<'a, 'b> Parser<'a, 'b> { }; } else { fold = Expr::BinOp { left, right, op }; + if op == TokenKind::Assign { + fold.mark_mut(); + } } } @@ -122,14 +137,13 @@ impl<'a, 'b> Parser<'a, 'b> { }) } - fn resolve_ident(&mut self, token: Token, decl: bool) -> (Ident, Option<&'a Cell>) { + fn resolve_ident(&mut self, token: Token, decl: bool) -> (Ident, Option<&'a Cell>) { let name = self.lexer.slice(token.range()); if let Some(builtin) = Self::try_resolve_builtin(name) { return (builtin, None); } - let last = self.arena.alloc(Cell::new(false)); let id = match self .idents .iter_mut() @@ -138,8 +152,12 @@ impl<'a, 'b> Parser<'a, 'b> { Some(elem) if decl && elem.declared => { self.report(format_args!("redeclaration of identifier: {name}")) } - Some(elem) => elem, + Some(elem) => { + elem.last.set(elem.last.get() + 1); + elem + } None => { + let last = self.arena.alloc(Cell::new(0)); let id = ident::new(token.start, name.len() as _); self.idents.push(ScopeIdent { ident: id, @@ -150,10 +168,11 @@ impl<'a, 'b> Parser<'a, 'b> { } }; - id.last = last; id.declared |= decl; + id.last + .set(id.last.get() | (REFERENCED * self.referening as u32)); - (id.ident, Some(last)) + (id.ident, Some(id.last)) } fn unit_expr(&mut self) -> Expr<'a> { @@ -187,8 +206,12 @@ impl<'a, 'b> Parser<'a, 'b> { }, T::Ident => { let (id, last) = self.resolve_ident(token, self.token.kind == T::Decl); - let name = self.lexer.slice(token.range()); - E::Ident { name, id, last } + E::Ident { + name: self.lexer.slice(token.range()), + id, + last, + index: last.map_or(0, |l| ident_flag_index(l.get())), + } } T::If => E::If { pos: token.start, @@ -231,7 +254,10 @@ impl<'a, 'b> Parser<'a, 'b> { T::Band | T::Mul => E::UnOp { pos: token.start, op: token.kind, - val: self.ptr_unit_expr(), + val: match token.kind { + T::Band => self.referenced(Self::ptr_unit_expr), + _ => self.ptr_unit_expr(), + }, }, T::LBrace => E::Block { pos: token.start, @@ -261,7 +287,9 @@ impl<'a, 'b> Parser<'a, 'b> { expr = match token.kind { T::LParen => Expr::Call { func: self.arena.alloc(expr), - args: self.collect_list(T::Comma, T::RParen, Self::expr), + args: self + .calcel_ref() + .collect_list(T::Comma, T::RParen, Self::expr), }, T::Ctor => E::Ctor { pos: token.start, @@ -300,6 +328,16 @@ impl<'a, 'b> Parser<'a, 'b> { expr } + fn referenced(&mut self, f: impl Fn(&mut Self) -> T) -> T { + if self.referening { + self.report("cannot take reference of reference, (souwy)"); + } + self.referening = true; + let expr = f(self); + self.referening = false; + expr + } + fn pop_scope(&mut self, frame: usize) { let mut undeclared_count = frame; for i in frame..self.idents.len() { @@ -309,9 +347,7 @@ impl<'a, 'b> Parser<'a, 'b> { } } - for id in self.idents.drain(undeclared_count..) { - id.last.set(true); - } + self.idents.drain(undeclared_count..); } fn ptr_unit_expr(&mut self) -> &'a Expr<'a> { @@ -362,13 +398,18 @@ impl<'a, 'b> Parser<'a, 'b> { eprintln!("{}:{}:{} => {}", self.path, line, col, msg); unreachable!(); } + + fn calcel_ref(&mut self) -> &mut Self { + self.referening = false; + self + } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Arg<'a> { pub name: &'a str, pub id: Ident, - pub last: Option<&'a Cell>, + pub last: Option<&'a Cell>, pub ty: Expr<'a>, } @@ -395,9 +436,10 @@ pub enum Expr<'a> { val: Option<&'a Self>, }, Ident { - name: &'a str, - id: Ident, - last: Option<&'a Cell>, + name: &'a str, + id: Ident, + index: u32, + last: Option<&'a Cell>, }, Block { pos: Pos, @@ -473,6 +515,14 @@ impl<'a> Expr<'a> { Self::Field { target, .. } => target.pos(), } } + + fn mark_mut(&self) { + match self { + Self::Ident { last, .. } => _ = last.map(|l| l.set(l.get() | MUTABLE)), + Self::Field { target, .. } => target.mark_mut(), + _ => {} + } + } } impl<'a> std::fmt::Display for Expr<'a> { diff --git a/hblang/tests/codegen_tests_fb_driver.txt b/hblang/tests/codegen_tests_fb_driver.txt index 58e9acf..f79bef2 100644 --- a/hblang/tests/codegen_tests_fb_driver.txt +++ b/hblang/tests/codegen_tests_fb_driver.txt @@ -1,3 +1,3 @@ -code size: 997 +code size: 758 ret: 0 status: Ok(()) diff --git a/hblang/tests/codegen_tests_loops.txt b/hblang/tests/codegen_tests_loops.txt index 8788c0c..5fadd38 100644 --- a/hblang/tests/codegen_tests_loops.txt +++ b/hblang/tests/codegen_tests_loops.txt @@ -1,3 +1,3 @@ -code size: 475 +code size: 347 ret: 55 status: Ok(()) diff --git a/hblang/tests/codegen_tests_pointers.txt b/hblang/tests/codegen_tests_pointers.txt index 22dcbc1..5216a64 100644 --- a/hblang/tests/codegen_tests_pointers.txt +++ b/hblang/tests/codegen_tests_pointers.txt @@ -1,3 +1,3 @@ -code size: 486 +code size: 437 ret: 0 status: Ok(()) diff --git a/hblang/tests/codegen_tests_variables.txt b/hblang/tests/codegen_tests_variables.txt index d265902..eac0032 100644 --- a/hblang/tests/codegen_tests_variables.txt +++ b/hblang/tests/codegen_tests_variables.txt @@ -1,3 +1,3 @@ -code size: 213 +code size: 130 ret: 0 status: Ok(())