From 95496116b05bf2ee2192a5acfe1bcedbdb23b28f Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Tue, 17 Dec 2024 18:30:19 +0100 Subject: [PATCH] making @len work on strings Signed-off-by: Jakub Doka --- lang/README.md | 3 ++- lang/src/son.rs | 22 ++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/lang/README.md b/lang/README.md index 95aaf42..6cbaca8 100644 --- a/lang/README.md +++ b/lang/README.md @@ -440,6 +440,7 @@ main := fn(): uint { ecall_that_returns_uint := @as(uint, @eca(1, foo.Type.(10, 20), 5, 6)) embedded_array := @as([u8; 15], @embed("text.txt")) two_fields := @len(foo.Type) + string_length := @len("foo\0") the_struct_kind := @kindof(foo.Type) return @inline(foo.foo) } @@ -466,7 +467,7 @@ arbitrary text - `@eca(...)`: invoke `eca` instruction, where return type is inferred and `...` are arguments passed to the call in the standard call convention - `@embed()`: include relative file as an array of bytes - `@inline(, ...)`: equivalent to `(...)` but function is guaranteed to inline, compiler will otherwise never inline -- `@len()`: reports a length of the type of indexing purposes +- `@len()`: reports a length of the type of indexing purposes or length ot a string constant - `@kindof()`: gives an u8 integer describing the kind of type as an index to array `[Builtin, Struct, Enum, Union, Ptr, Slice, Opt, Func, Template, Global, Const, Module]` #### c_strings diff --git a/lang/src/son.rs b/lang/src/son.rs index 9ff816f..dffea11 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -1309,16 +1309,18 @@ impl<'a> Codegen<'a> { self.gen_inferred_const(ctx, ty::Id::DINT, align) } Expr::Directive { name: "len", args: [ety], .. } => { - let ty = self.ty(ety); - let Some(len) = self.tys.len_of(ty) else { - return self.error( - ety.pos(), - fa!( - "'@len' only supports structs and arrays, \ - '{}' is neither", - self.ty_display(ty) - ), - ); + let ty = self.expr(ety)?; + let len = match self.ci.nodes[ty.id].kind { + Kind::CInt { value } + if let Some(len) = self.tys.len_of(ty::Id::from(value as u64)) => + { + len + } + Kind::Global { global } => self.tys.ins.globals[global].data.len() as u32 - 1, + _ => { + return self + .error(ety.pos(), "'@len' only supports structs and arrays or strings") + } }; self.gen_inferred_const(ctx, ty::Id::DINT, len) }