From 5275a7e0fdbe941334eeea1e090034a5f194afe6 Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Sat, 21 Dec 2024 23:44:33 +0100 Subject: [PATCH] adding slices Signed-off-by: Jakub Doka --- lang/README.md | 37 +++-- lang/src/fmt.rs | 89 +++++------ lang/src/lexer.rs | 22 ++- lang/src/lib.rs | 8 +- lang/src/nodes.rs | 30 +++- lang/src/parser.rs | 49 +++++-- lang/src/son.rs | 138 ++++++++++++++---- .../son_tests_method_receiver_by_value.txt | 12 +- lang/tests/son_tests_nullable_types.txt | 41 +++--- lang/tests/son_tests_slices.txt | 41 ++++++ lang/tests/son_tests_string_array.txt | 9 +- 11 files changed, 350 insertions(+), 126 deletions(-) create mode 100644 lang/tests/son_tests_slices.txt diff --git a/lang/README.md b/lang/README.md index 43c55052..d7df52ce 100644 --- a/lang/README.md +++ b/lang/README.md @@ -342,7 +342,7 @@ main := fn(): uint { Foo := struct {a: ^uint, b: uint} no_foo := fn(): ?Foo return null new_foo := fn(): ?Foo return .(&0, 0) -use_foo := fn(foo: Foo, str: ^u8): void { +use_foo := fn(foo: Foo, str: []u8): void { } Bar := struct {a: ?^uint, b: uint} @@ -453,7 +453,6 @@ main := fn(): uint { ecall_that_returns_uint := @as(uint, @eca(1, foo.Type.(10, 20), 5, 6)) embedded_array := @as([15]u8, @embed("text.txt")) two_fields := @lenof(foo.Type) - string_length := @lenof("foo\0") the_struct_kind := @kindof(foo.Type) return @inline(foo.foo) } @@ -501,9 +500,9 @@ str_len := fn(str: ^u8): uint { main := fn(): uint { // when string ends with '\0' its a C string and thus type is '^u8' - some_str := "abඞ\n\r\t\{35}\{36373839}\0" + some_str := "abඞ\n\r\t\{35}\{36373839}\0".ptr len := str_len(some_str) - some_other_str := "fff\0" + some_other_str := "fff\0".ptr lep := str_len(some_other_str) return lep + len } @@ -557,6 +556,22 @@ pass := fn(arr: ^[3]uint): uint { } ``` +#### slices +```hb +main := fn(): uint { + one := &10 + from_ptr: []uint = one[..1] + + arr := .[0, 1, 2, 3] + start := arr[..2] + mid := arr[1..3] + end := arr[2..] + all := arr[..] + + return start[0] + mid[0] + end[0] + all[3] + all.len - from_ptr[0] +} +``` + #### inline ```hb main := fn(): uint { @@ -723,10 +738,10 @@ main := fn(): uint { #### string_array ```hb -strings := (^u8).["abcdefshijklmnop\0", "abcdefghijklnnop\0", "abcdefshijklmnop\0", "abcdefghijklmnop\0", "abcdefghijflmnop\0", "dbcdefghijklmnop\0", "abcdefghijklmnop\0"] main := fn(): uint { - return @bitcast(strings[0]) + strings := (^u8).["abcdefshijklmnop\0".ptr, "abcdefghijklnnop\0".ptr, "abcdefshijklmnop\0".ptr, "abcdefghijklmnop\0".ptr, "abcdefghijflmnop\0".ptr, "dbcdefghijklmnop\0".ptr, "abcdefghijklmnop\0".ptr] + return *strings[0] } ``` @@ -822,12 +837,12 @@ Struct2 := struct { } main := fn(): void { - lhs := Struct.("Hello, World!\0") - rhs := Struct.("Goodbye, World!\0") + lhs := Struct.("Hello, World!\0".ptr) + rhs := Struct.("Goodbye, World!\0".ptr) lhs.print(rhs) - lhs2 := Struct2.("Hello, World!\0") - rhs2 := Struct2.("Goodbye, World!\0") + lhs2 := Struct2.("Hello, World!\0".ptr) + rhs2 := Struct2.("Goodbye, World!\0".ptr) lhs2.print2(&rhs2) } ``` @@ -1684,7 +1699,7 @@ main := fn(): void { #### request_page ```hb request_page := fn(page_count: u8): ^u8 { - msg := "\{00}\{01}xxxxxxxx\0" + msg := "\{00}\{01}xxxxxxxx\0".ptr msg_page_count := msg + 1; *msg_page_count = page_count return @eca(3, 2, msg, 12) diff --git a/lang/src/fmt.rs b/lang/src/fmt.rs index 97a287a0..1bb71884 100644 --- a/lang/src/fmt.rs +++ b/lang/src/fmt.rs @@ -51,27 +51,29 @@ enum TokenGroup { Ctor, } -fn token_group(kind: TokenKind) -> TokenGroup { - use {crate::lexer::TokenKind::*, TokenGroup as TG}; - match kind { - BSlash | Pound | Eof | Ct => TG::Blank, - Comment => TG::Comment, - Directive => TG::Directive, - Colon => TG::Colon, - Semi | Comma => TG::Comma, - Dot => TG::Dot, - Ctor | Arr | Tupl | TArrow => TG::Ctor, - LParen | RParen => TG::Paren, - LBrace | RBrace | LBrack | RBrack => TG::Bracket, - Number | Float => TG::Number, - Under | CtIdent | Ident => TG::Identifier, - Tick | Tilde | Que | Not | Mod | Band | Bor | Xor | Mul | Add | Sub | Div | Shl | Shr - | Or | And | Lt | Gt | Eq | Le | Ge | Ne => TG::Op, - Decl | Assign | BorAss | XorAss | BandAss | AddAss | SubAss | MulAss | DivAss | ModAss - | ShrAss | ShlAss => TG::Assign, - DQuote | Quote => TG::String, - Slf | Defer | Return | If | Else | Loop | Break | Continue | Fn | Idk | Die | Struct - | Packed | True | False | Null | Match | Enum | Union | CtLoop => TG::Keyword, +impl TokenKind { + fn to_higlight_group(self) -> TokenGroup { + use {TokenGroup as TG, TokenKind::*}; + match self { + BSlash | Pound | Eof | Ct => TG::Blank, + Comment => TG::Comment, + Directive => TG::Directive, + Colon => TG::Colon, + Semi | Comma => TG::Comma, + Dot => TG::Dot, + Ctor | Arr | Tupl | TArrow | Range => TG::Ctor, + LParen | RParen => TG::Paren, + LBrace | RBrace | LBrack | RBrack => TG::Bracket, + Number | Float => TG::Number, + Under | CtIdent | Ident => TG::Identifier, + Tick | Tilde | Que | Not | Mod | Band | Bor | Xor | Mul | Add | Sub | Div | Shl + | Shr | Or | And | Lt | Gt | Eq | Le | Ge | Ne => TG::Op, + Decl | Assign | BorAss | XorAss | BandAss | AddAss | SubAss | MulAss | DivAss + | ModAss | ShrAss | ShlAss => TG::Assign, + DQuote | Quote => TG::String, + Slf | Defer | Return | If | Else | Loop | Break | Continue | Fn | Idk | Die + | Struct | Packed | True | False | Null | Match | Enum | Union | CtLoop => TG::Keyword, + } } } @@ -89,7 +91,7 @@ pub fn get_token_kinds(mut source: &mut [u8]) -> usize { let start = token.start as usize; let end = token.end as usize; source[..start].fill(0); - source[start..end].fill(token_group(token.kind) as u8); + source[start..end].fill(token.kind.to_higlight_group() as u8); source = &mut source[end..]; } len @@ -222,12 +224,12 @@ impl<'a> Formatter<'a> { f.write_str(sep)?; } if let Some(expr) = list.get(i + 1) - && let Some(rest) = self.source.get(expr.posi() as usize..) + && let Some(prev) = self.source.get(..expr.posi() as usize) { - if sep.is_empty() && insert_needed_semicolon(rest) { + if sep.is_empty() && prev.trim_end().ends_with(';') { f.write_str(";")?; } - if preserve_newlines(&self.source[..expr.posi() as usize]) > 1 { + if count_trailing_newlines(prev) > 1 { f.write_str("\n")?; } } @@ -305,10 +307,6 @@ impl<'a> Formatter<'a> { } match *expr { - Expr::Ct { value, .. } => { - f.write_str("$: ")?; - self.fmt(value, f) - } Expr::Defer { value, .. } => { f.write_str("defer ")?; self.fmt(value, f) @@ -324,6 +322,16 @@ impl<'a> Formatter<'a> { f.write_str(".")?; f.write_str(field) } + Expr::Range { start, end, .. } => { + if let Some(start) = start { + self.fmt(start, f)?; + } + f.write_str("..")?; + if let Some(end) = end { + self.fmt(end, f)?; + } + Ok(()) + } Expr::Directive { name, args, .. } => { f.write_str("@")?; f.write_str(name)?; @@ -424,10 +432,10 @@ impl<'a> Formatter<'a> { self.fmt(size, f)?; } f.write_str("]")?; - self.fmt(item, f) + self.fmt_paren(item, f, unary) } Expr::Index { base, index } => { - self.fmt(base, f)?; + self.fmt_paren(base, f, postfix)?; f.write_str("[")?; self.fmt(index, f)?; f.write_str("]") @@ -550,7 +558,7 @@ impl<'a> Formatter<'a> { prev.rfind(|c: char| c.is_ascii_whitespace()).map_or(prev.len(), |i| i + 1); let exact_bound = lexer::Lexer::new(&prev[estimate_bound..]).last().start; prev = &prev[..exact_bound as usize + estimate_bound]; - if preserve_newlines(prev) > 0 { + if count_trailing_newlines(prev) > 0 { f.write_str("\n")?; for _ in 0..self.depth + 1 { f.write_str("\t")?; @@ -575,15 +583,10 @@ impl<'a> Formatter<'a> { } } -pub fn preserve_newlines(source: &str) -> usize { +pub fn count_trailing_newlines(source: &str) -> usize { source[source.trim_end().len()..].bytes().filter(|&c| c == b'\n').count() } -pub fn insert_needed_semicolon(source: &str) -> bool { - let kind = lexer::Lexer::new(source).eat().kind; - kind.precedence().is_some() || matches!(kind, TokenKind::Ctor | TokenKind::Tupl) -} - impl core::fmt::Display for parser::Ast { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt_file(self.exprs(), &self.file, f) @@ -594,14 +597,14 @@ pub fn fmt_file(exprs: &[Expr], file: &str, f: &mut impl fmt::Write) -> fmt::Res for (i, expr) in exprs.iter().enumerate() { Formatter::new(file).fmt(expr, f)?; if let Some(expr) = exprs.get(i + 1) - && let Some(rest) = file.get(expr.pos() as usize..) + && let Some(prefix) = file.get(..expr.pos() as usize) { - if insert_needed_semicolon(rest) { - write!(f, ";")?; + if prefix.trim_end().ends_with(';') { + f.write_str(";")?; } - if preserve_newlines(&file[..expr.pos() as usize]) > 1 { - writeln!(f)?; + if count_trailing_newlines(prefix) > 1 { + f.write_str("\n")?; } } diff --git a/lang/src/lexer.rs b/lang/src/lexer.rs index 7de8d45c..ad76e4c9 100644 --- a/lang/src/lexer.rs +++ b/lang/src/lexer.rs @@ -140,6 +140,7 @@ pub enum TokenKind { Tupl, Arr, TArrow, + Range, Or, And, @@ -350,6 +351,7 @@ gen_token_kind! { Tupl = ".(", Arr = ".[", TArrow = "=>", + Range = "..", // #define OP: each `#[prec]` delimeters a level of precedence from lowest to highest #[ops] #[prec] @@ -432,6 +434,19 @@ impl<'a> Lexer<'a> { Lexer { pos: self.pos, source: self.source }.eat() } + fn peek_n(&self) -> Option<&[u8; N]> { + if core::intrinsics::unlikely(self.pos as usize + N > self.source.len()) { + None + } else { + Some(unsafe { + self.source + .get_unchecked(self.pos as usize..self.pos as usize + N) + .first_chunk() + .unwrap_unchecked() + }) + } + } + fn peek(&self) -> Option { if core::intrinsics::unlikely(self.pos >= self.source.len() as u32) { None @@ -500,7 +515,11 @@ impl<'a> Lexer<'a> { self.advance(); } - if self.advance_if(b'.') { + if self + .peek_n() + .map_or_else(|| self.peek() == Some(b'.'), |&[a, b]| a == b'.' && b != b'.') + { + self.pos += 1; while let Some(b'0'..=b'9') = self.peek() { self.advance(); } @@ -553,6 +572,7 @@ impl<'a> Lexer<'a> { b'.' if self.advance_if(b'{') => T::Ctor, b'.' if self.advance_if(b'(') => T::Tupl, b'.' if self.advance_if(b'[') => T::Arr, + b'.' if self.advance_if(b'.') => T::Range, b'=' if self.advance_if(b'>') => T::TArrow, b'&' if self.advance_if(b'&') => T::And, b'|' if self.advance_if(b'|') => T::Or, diff --git a/lang/src/lib.rs b/lang/src/lib.rs index 041681d2..0434d289 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -127,6 +127,8 @@ pub mod backend { mod utils; mod debug { + use {core::fmt::Debug, std::string::String}; + pub fn panicking() -> bool { #[cfg(feature = "std")] { @@ -139,14 +141,14 @@ mod debug { } #[cfg(all(debug_assertions, feature = "std"))] - pub type Trace = std::rc::Rc; + pub type Trace = std::rc::Rc<(std::backtrace::Backtrace, String)>; #[cfg(not(all(debug_assertions, feature = "std")))] pub type Trace = (); - pub fn trace() -> Trace { + pub fn trace(_hint: impl Debug) -> Trace { #[cfg(all(debug_assertions, feature = "std"))] { - std::rc::Rc::new(std::backtrace::Backtrace::capture()) + std::rc::Rc::new((std::backtrace::Backtrace::capture(), format!("{_hint:?}"))) } #[cfg(not(all(debug_assertions, feature = "std")))] {} diff --git a/lang/src/nodes.rs b/lang/src/nodes.rs index 4fca2e24..594e8739 100644 --- a/lang/src/nodes.rs +++ b/lang/src/nodes.rs @@ -699,7 +699,7 @@ impl Nodes { if self.free == Nid::MAX { self.free = self.values.len() as _; - self.values.push(Err((Nid::MAX, debug::trace()))); + self.values.push(Err((Nid::MAX, debug::trace("")))); } let free = self.free; @@ -775,13 +775,11 @@ impl Nodes { } self.remove_node_lookup(target); - + let trace = debug::trace(&self.values[target as usize]); if cfg!(debug_assertions) { - mem::replace(&mut self.values[target as usize], Err((Nid::MAX, debug::trace()))) - .unwrap(); + mem::replace(&mut self.values[target as usize], Err((Nid::MAX, trace))).unwrap(); } else { - mem::replace(&mut self.values[target as usize], Err((self.free, debug::trace()))) - .unwrap(); + mem::replace(&mut self.values[target as usize], Err((self.free, trace))).unwrap(); self.free = target; } @@ -1637,6 +1635,7 @@ impl Nodes { } pub fn replace(&mut self, target: Nid, with: Nid) { + self.patch_aclass(target, with); debug_assert_ne!(target, with, "{:?}", self[target]); for out in self[target].outputs.clone() { let index = self[out].inputs.iter().position(|&p| p == target).unwrap(); @@ -1981,6 +1980,25 @@ impl Nodes { self[blocker].peep_triggers.push(target); } } + + fn patch_aclass(&mut self, target: Nid, with: Nid) { + let (_, region) = self.aclass_index(target); + if region == 0 { + return; + } + + fn patch_aclass_inner(s: &mut Nodes, root: Nid, with: Nid, matches: Nid) { + for out in s[root].outputs.clone() { + let (_, region) = s.aclass_index(out); + if region == matches { + s.pass_aclass(with, out); + patch_aclass_inner(s, out, with, matches); + } + } + } + + patch_aclass_inner(self, target, with, target); + } } impl ops::Index for Nodes { diff --git a/lang/src/parser.rs b/lang/src/parser.rs index 56e13f71..f7288313 100644 --- a/lang/src/parser.rs +++ b/lang/src/parser.rs @@ -17,6 +17,7 @@ use { ptr::NonNull, sync::atomic::AtomicUsize, }, + std::panic, }; pub type Pos = u32; @@ -31,7 +32,7 @@ pub enum FileKind { Embed, } -trait Trans { +pub trait Trans { fn trans(self) -> Self; } @@ -308,7 +309,6 @@ impl<'a, 'b> Parser<'a, 'b> { let prev_captured = self.ctx.captured.len(); let mut must_trail = false; let mut expr = match token.kind { - T::Ct => E::Ct { pos, value: self.ptr_expr()? }, T::Defer => E::Defer { pos, value: self.ptr_expr()? }, T::Slf => E::Slf { pos }, T::Directive if self.lexer.slice(token.range()) == "use" => { @@ -491,6 +491,15 @@ impl<'a, 'b> Parser<'a, 'b> { }, body: self.ptr_expr()?, }, + T::Range => E::Range { + pos: token.start, + start: None, + end: if matches!(self.token.kind, TokenKind::RBrack) { + None + } else { + Some(self.ptr_expr()?) + }, + }, T::Ctor => self.ctor(pos, None), T::Tupl => self.tupl(pos, None, ListKind::Tuple), T::Arr => self.tupl(pos, None, ListKind::Array), @@ -562,7 +571,14 @@ impl<'a, 'b> Parser<'a, 'b> { let token = self.token; if matches!( token.kind, - T::LParen | T::Ctor | T::Dot | T::Tupl | T::Arr | T::LBrack | T::Colon + T::LParen + | T::Ctor + | T::Dot + | T::Tupl + | T::Arr + | T::LBrack + | T::Colon + | T::Range ) { self.next(); } @@ -584,6 +600,15 @@ impl<'a, 'b> Parser<'a, 'b> { self.arena.alloc(index) }, }, + T::Range => E::Range { + pos: token.start, + start: Some(self.arena.alloc(expr)), + end: if matches!(self.token.kind, TokenKind::RBrack) { + None + } else { + Some(self.ptr_expr()?) + }, + }, T::Colon => E::BinOp { left: { self.declare_rec(&expr, false); @@ -737,7 +762,9 @@ impl<'a, 'b> Parser<'a, 'b> { ) -> &'a [T] { let mut trailing_sep = false; let mut view = self.ctx.stack.view(); - 'o: while (keep_end && self.token.kind != end) || (!keep_end && !self.advance_if(end)) { + 'o: while (keep_end && self.token.kind != end) + || (!keep_end && !self.advance_if(end)) && self.token.kind != TokenKind::Eof + { let val = match f(self) { Some(val) => val, None => { @@ -810,6 +837,9 @@ impl<'a, 'b> Parser<'a, 'b> { #[track_caller] fn report(&mut self, pos: Pos, msg: impl fmt::Display) -> Option { if log::log_enabled!(log::Level::Error) { + if self.ctx.errors.get_mut().len() > 1024 * 10 { + panic!("{}", self.ctx.errors.get_mut()); + } use core::fmt::Write; writeln!( self.ctx.errors.get_mut(), @@ -916,11 +946,6 @@ generate_expr! { /// `OP := grep for `#define OP:` #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Expr<'a> { - /// `'ct' Expr` - Ct { - pos: Pos, - value: &'a Self, - }, /// `'defer' Expr` Defer { pos: Pos, @@ -1079,6 +1104,12 @@ generate_expr! { base: &'a Self, index: &'a Self, }, + /// `[ Expr ] .. [ Expr ]` + Range { + pos: u32, + start: Option<&'a Self>, + end: Option<&'a Self>, + }, /// `Expr '.' Ident` Field { target: &'a Self, diff --git a/lang/src/son.rs b/lang/src/son.rs index 868e8173..19628015 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -897,16 +897,18 @@ impl<'a> Codegen<'a> { self.gen_inferred_const(ctx, ty::Id::U8, value) } else { - if data.last() != Some(&0) { - self.error(pos, "string literal must end with null byte (for now)"); - } - let (global, ty) = self.create_string_global(&data); + let len = self.ci.nodes.new_const_lit(ty, data.len() as i64); data.clear(); self.pool.lit_buf = data; - - Some(Value::new(global).ty(ty)) + let slc = self.tys.make_array(ty::Id::U8, ArrayLen::MAX); + let mem = self.new_stack(pos, slc); + for (off, value) in [(0u32, Value::ptr(global).ty(ty)), (8, len)] { + let region = self.offset(mem, off); + self.store_mem(region, value.ty, value.id); + } + Some(Value::ptr(mem).ty(slc)) } } Expr::Defer { pos, value } => { @@ -1255,6 +1257,80 @@ impl<'a> Codegen<'a> { .error(pos, fa!("'{} {op} _' is not supported", self.ty_display(lhs.ty))), } } + Expr::Index { base, index: &Expr::Range { start, end, pos } } => { + let mut bs = self.ptr_expr(base)?; + + let start = match start { + Some(s) => self.checked_expr(s, ty::Id::UINT, "range start")?.id, + None => self.ci.nodes.new_const(ty::Id::UINT, 0), + }; + self.ci.nodes.lock(start); + + let end = match end { + Some(e) => self.checked_expr(e, ty::Id::UINT, "range end")?.id, + None => match bs.ty.expand() { + ty::Kind::Slice(s) if let Some(len) = self.tys.ins.slices[s].len() => { + self.ci.nodes.new_const(ty::Id::UINT, len as i64) + } + ty::Kind::Slice(_) => { + // Might change + let off = self.offset(bs.id, 8); + self.load_mem(off, ty::Id::UINT) + } + ty::Kind::Ptr(_) => { + return self + .error(pos, "upper bound is required when slicing a pointer") + } + _ => NEVER, + }, + }; + self.ci.nodes.lock(end); + + let len = self.ci.nodes.new_node_lit( + ty::Id::UINT, + Kind::BinOp { op: TokenKind::Sub }, + [VOID, end, start], + self.tys, + ); + self.ci.nodes.lock(len.id); + + let elem = match bs.ty.expand() { + ty::Kind::Slice(s) => self.tys.ins.slices[s].elem, + ty::Kind::Ptr(_) => { + if let Some(base) = self.tys.base_of(bs.ty) { + bs.ptr = true; + bs.ty = base; + } + + bs.ty + } + _ => { + return self.error( + base.pos(), + fa!( + "cant slice into '{}' which is not array nor slice not a pointer", + self.ty_display(bs.ty) + ), + ) + } + }; + + let ptr = self.offset_ptr(bs.id, elem, start); + self.ci.nodes.lock(ptr.id); + + let ty = self.tys.make_array(elem, ArrayLen::MAX); + + let mem = self.new_stack(pos, ty); + for (off, value) in [(0u32, ptr), (8, len)] { + let region = self.offset(mem, off); + self.store_mem(region, value.ty, value.id); + } + self.ci.nodes.unlock(start); + self.ci.nodes.unlock(len.id); + self.ci.nodes.unlock(end); + self.ci.nodes.unlock(ptr.id); + Some(Value::ptr(mem).ty(ty)) + } Expr::Index { base, index } => { let mut bs = self.ptr_expr(base)?; @@ -1266,27 +1342,16 @@ impl<'a> Codegen<'a> { let idx = self.checked_expr(index, ty::Id::DINT, "subscript")?; match bs.ty.expand() { + ty::Kind::Slice(s) if self.tys.ins.slices[s].len().is_some() => { + let elem = self.tys.ins.slices[s].elem; + Some(self.offset_ptr(bs.id, elem, idx.id)) + } ty::Kind::Slice(s) => { let elem = self.tys.ins.slices[s].elem; - let size = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem)); - let inps = [VOID, idx.id, size]; - let offset = self.ci.nodes.new_node( - ty::Id::INT, - Kind::BinOp { op: TokenKind::Mul }, - inps, - self.tys, - ); - let aclass = self.ci.nodes.aclass_index(bs.id).1; - let inps = [VOID, bs.id, offset]; - let ptr = self.ci.nodes.new_node( - ty::Id::INT, - Kind::BinOp { op: TokenKind::Add }, - inps, - self.tys, - ); - self.ci.nodes.pass_aclass(aclass, ptr); - - Some(Value::ptr(ptr).ty(elem)) + let off = self.offset(bs.id, 0); + let base = self.tys.make_ptr(elem); + let bs = std::dbg!(self.load_mem(off, base)); + Some(self.offset_ptr(bs, elem, idx.id)) } ty::Kind::Struct(s) => { let Kind::CInt { value: idx } = self.ci.nodes[idx.id].kind else { @@ -2450,6 +2515,20 @@ impl<'a> Codegen<'a> { } } + fn offset_ptr(&mut self, bs: Nid, elem: ty::Id, idx: Nid) -> Value { + let size = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem)); + let inps = [VOID, idx, size]; + let offset = + self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Mul }, inps, self.tys); + let aclass = self.ci.nodes.aclass_index(bs).1; + let inps = [VOID, bs, offset]; + let ptr = + self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps, self.tys); + self.ci.nodes.pass_aclass(aclass, ptr); + + Value::ptr(ptr).ty(elem) + } + fn spill(&mut self, pos: Pos, value: &mut Value) { debug_assert!(!value.ptr); let stck = self.new_stack(pos, value.ty); @@ -2535,6 +2614,14 @@ impl<'a> Codegen<'a> { ) } } + ty::Kind::Slice(s) => { + let (offset, ty) = match name { + "len" => (8, ty::Id::UINT), + "ptr" => (0, self.tys.make_ptr(self.tys.ins.slices[s].elem)), + _ => return None, + }; + Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty)) + } ty::Kind::TYPE => match self.ci.nodes.as_ty(vtarget.id).expand() { ty::Kind::Module(m) => self.find_type_as_value(pos, m, name, ctx), ty::Kind::Enum(e) @@ -4331,6 +4418,7 @@ mod tests { c_strings; struct_patterns; arrays; + slices; inline; idk; generic_functions; diff --git a/lang/tests/son_tests_method_receiver_by_value.txt b/lang/tests/son_tests_method_receiver_by_value.txt index 479e3dd4..469ed94b 100644 --- a/lang/tests/son_tests_method_receiver_by_value.txt +++ b/lang/tests/son_tests_method_receiver_by_value.txt @@ -3,15 +3,15 @@ main: ST r31, r254, 32a, 40h LRA r32, r0, :"Goodbye, World!\0" LRA r33, r0, :"Hello, World!\0" - ST r32, r254, 8a, 8h + ST r32, r254, 16a, 8h ST r33, r254, 24a, 8h LD r2, r254, 24a, 8h - LD r3, r254, 8a, 8h + LD r3, r254, 16a, 8h JAL r31, r0, :print - ADDI64 r34, r254, 0d - ADDI64 r35, r254, 16d - ST r32, r254, 0a, 8h - ST r33, r254, 16a, 8h + ADDI64 r34, r254, 8d + ADDI64 r35, r254, 0d + ST r32, r254, 8a, 8h + ST r33, r254, 0a, 8h CP r2, r35 CP r3, r34 JAL r31, r0, :print2 diff --git a/lang/tests/son_tests_nullable_types.txt b/lang/tests/son_tests_nullable_types.txt index 1d41bc1c..b5cc9310 100644 --- a/lang/tests/son_tests_nullable_types.txt +++ b/lang/tests/son_tests_nullable_types.txt @@ -3,11 +3,11 @@ decide: CP r1, r13 JALA r0, r31, 0a main: - ADDI64 r254, r254, -128d - ST r31, r254, 80a, 48h + ADDI64 r254, r254, -144d + ST r31, r254, 96a, 48h JAL r31, r0, :decide CP r33, r0 - ADDI64 r34, r254, 72d + ADDI64 r34, r254, 88d CP r32, r1 ANDI r32, r32, 255d JNE r32, r0, :0 @@ -15,7 +15,7 @@ main: JMP :1 0: CP r32, r34 1: LI64 r35, 1d - ST r35, r254, 72a, 8h + ST r35, r254, 88a, 8h JNE r32, r33, :2 LI64 r32, 9001d CP r1, r32 @@ -25,12 +25,12 @@ main: ANDI r33, r33, 255d JNE r33, r0, :4 LI8 r33, 1b - ST r33, r254, 56a, 1h + ST r33, r254, 72a, 1h LD r32, r32, 0a, 8h - ST r32, r254, 64a, 8h + ST r32, r254, 80a, 8h JMP :5 - 4: ST r0, r254, 56a, 1h - 5: LD r32, r254, 56a, 1h + 4: ST r0, r254, 72a, 1h + 5: LD r32, r254, 72a, 1h ANDI r32, r32, 255d JEQ r32, r0, :6 LI64 r32, 42d @@ -50,17 +50,20 @@ main: LI64 r32, 69d CP r1, r32 JMP :3 - 9: ADDI64 r33, r254, 40d + 9: ADDI64 r33, r254, 56d JAL r31, r0, :new_foo ST r1, r33, 0a, 16h - LD r36, r254, 40a, 8h + LD r36, r254, 56a, 8h JNE r36, r0, :10 LI64 r32, 999d CP r1, r32 JMP :3 10: LRA r36, r0, :"foo\0" + ST r36, r254, 40a, 8h + LI64 r36, 4d + ST r36, r254, 48a, 8h LD r2, r33, 0a, 16h - CP r4, r36 + LD r4, r254, 40a, 16h JAL r31, r0, :use_foo ADDI64 r33, r254, 0d JAL r31, r0, :no_foo @@ -98,8 +101,8 @@ main: ANDI r32, r32, 65535d SUB64 r32, r32, r33 CP r1, r32 - 3: LD r31, r254, 80a, 48h - ADDI64 r254, r254, 128d + 3: LD r31, r254, 96a, 48h + ADDI64 r254, r254, 144d JALA r0, r31, 0a new_bar: ADDI64 r254, r254, -24d @@ -129,11 +132,13 @@ no_foo: ADDI64 r254, r254, 16d JALA r0, r31, 0a use_foo: - ADDI64 r254, r254, -16d - ST r2, r254, 0a, 16h - ADDI64 r2, r254, 0d - ADDI64 r254, r254, 16d + ADDI64 r254, r254, -32d + ST r2, r254, 16a, 16h + ADDI64 r2, r254, 16d + ST r4, r254, 0a, 16h + ADDI64 r4, r254, 0d + ADDI64 r254, r254, 32d JALA r0, r31, 0a -code size: 1092 +code size: 1162 ret: 0 status: Ok(()) diff --git a/lang/tests/son_tests_slices.txt b/lang/tests/son_tests_slices.txt new file mode 100644 index 00000000..bcf0c1ab --- /dev/null +++ b/lang/tests/son_tests_slices.txt @@ -0,0 +1,41 @@ +main: + ADDI64 r254, r254, -120d + ADDI64 r13, r254, 32d + ST r0, r254, 32a, 8h + ADDI64 r14, r13, 8d + LI64 r15, 1d + ST r15, r14, 0a, 8h + ADDI64 r15, r13, 16d + LI64 r16, 2d + ST r16, r15, 0a, 8h + LI64 r16, 3d + ADDI64 r17, r254, 112d + LI64 r18, 10d + ST r13, r254, 0a, 8h + ST r16, r254, 56a, 8h + ST r18, r254, 112a, 8h + ST r14, r254, 64a, 8h + LD r14, r254, 0a, 8h + LD r16, r254, 64a, 8h + ST r15, r254, 96a, 8h + ST r13, r254, 16a, 8h + LD r13, r14, 0a, 8h + LD r14, r16, 0a, 8h + LD r15, r254, 96a, 8h + LD r16, r254, 16a, 8h + ADD64 r13, r14, r13 + LD r14, r15, 0a, 8h + ST r17, r254, 80a, 8h + ADD64 r13, r14, r13 + LD r14, r16, 24a, 8h + LD r15, r254, 80a, 8h + ADD64 r13, r14, r13 + LD r14, r15, 0a, 8h + ADDI64 r13, r13, 4d + SUB64 r13, r13, r14 + CP r1, r13 + ADDI64 r254, r254, 120d + JALA r0, r31, 0a +code size: 415 +ret: 0 +status: Ok(()) diff --git a/lang/tests/son_tests_string_array.txt b/lang/tests/son_tests_string_array.txt index bd54d443..479ed2e2 100644 --- a/lang/tests/son_tests_string_array.txt +++ b/lang/tests/son_tests_string_array.txt @@ -1,8 +1,9 @@ main: - LRA r13, r0, :strings - LD r13, r13, 0a, 8h + LRA r13, r0, :"abcdefshijklmnop\0" + LD r13, r13, 0a, 1h + ANDI r13, r13, 255d CP r1, r13 JALA r0, r31, 0a -code size: 98 -ret: 134998808175692 +code size: 70 +ret: 97 status: Ok(())