forked from AbleOS/holey-bytes
adding slices
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
parent
418fd0039e
commit
5275a7e0fd
|
@ -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)
|
||||
|
|
|
@ -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")?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<const N: usize>(&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<u8> {
|
||||
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,
|
||||
|
|
|
@ -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<std::backtrace::Backtrace>;
|
||||
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")))]
|
||||
{}
|
||||
|
|
|
@ -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<Nid> for Nodes {
|
||||
|
|
|
@ -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,
|
||||
|
|
138
lang/src/son.rs
138
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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(())
|
||||
|
|
41
lang/tests/son_tests_slices.txt
Normal file
41
lang/tests/son_tests_slices.txt
Normal file
|
@ -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(())
|
|
@ -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(())
|
||||
|
|
Loading…
Reference in a new issue