From 047e1ed15cedb27940214741e6fc3d0199b69c06 Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Sun, 27 Oct 2024 19:55:11 +0100 Subject: [PATCH] adding null --- lang/README.md | 21 ++++++++++++--------- lang/src/fmt.rs | 1 + lang/src/lexer.rs | 4 +++- lang/src/parser.rs | 5 +++++ lang/src/son.rs | 26 +++++++++++++++++++++++++- 5 files changed, 46 insertions(+), 11 deletions(-) diff --git a/lang/README.md b/lang/README.md index 2d6ad497..8c52a920 100644 --- a/lang/README.md +++ b/lang/README.md @@ -18,7 +18,6 @@ Holey-Bytes-Language (hblang for short) (*.hb) is the only true language targeti hblang knows what it isn't, because it knows what it is, hblang computes this by sub... - ## Examples Examples are also used in tests. To add an example that runs during testing add: @@ -30,9 +29,9 @@ Examples are also used in tests. To add an example that runs during testing add: and also: ```rs - => README; +; ``` -to the `run_tests` macro at the bottom of the `src/codegen.rs`. +to the `run_tests` macro at the bottom of the `src/son.rs`. ### Tour Examples @@ -129,6 +128,9 @@ fib := fn(n: uint): uint { #### pointers ```hb main := fn(): uint { + n := @as(^uint, null) + if n != null return 9001 + a := 1 b := &a @@ -289,14 +291,14 @@ foo := fn(): uint return 0 arbitrary text ``` -- `@use()`: imports a module based of string, the string is passed to a loader that can be customized, default loader uses following syntax: - - `((rel:|)()|git::)`: `rel:` and `''` prefixes both mean module is located at `path` relavive to the current file, `git:` takes a git url without `https://` passed as `git-addr`, `path` then refers to file within the repository +- `@use()`: imports a module based on relative path, cycles are allowed when importing - `@TypeOf()`: results into literal type of whatever the type of `` is, `` is not included in final binary -- `@as(, )`: huint to the compiler that `@TypeOf() == ` +- `@as(, )`: hint to the compiler that `@TypeOf() == ` - `@intcast()`: needs to be used when conversion of `@TypeOf()` would loose precision (widening of integers is implicit) -- `@sizeof(), @alignof()`: I think explaining this would insult your intelligence -- `@bitcast()`: tell compiler to assume `@TypeOf()` is whatever is inferred, so long as size and alignment did not change -- `@eca(, ...)`: invoke `eca` instruction, where `` is the type this will return and `...` are arguments passed to the call +- `@sizeof(), @alignof()`: get size and align of a type in bytes +- `@bitcast()`: tell compiler to assume `@TypeOf()` is whatever is inferred, so long as size matches +- `@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 #### c_strings @@ -396,6 +398,7 @@ main := fn(): uint { return big_array[42] } ``` +note: this does not work on scalar values #### generic_functions ```hb diff --git a/lang/src/fmt.rs b/lang/src/fmt.rs index 2468064e..7c0c0feb 100644 --- a/lang/src/fmt.rs +++ b/lang/src/fmt.rs @@ -368,6 +368,7 @@ impl<'a> Formatter<'a> { } Expr::Bool { value, .. } => f.write_str(if value { "true" } else { "false" }), Expr::Idk { .. } => f.write_str("idk"), + Expr::Null { .. } => f.write_str("null"), Expr::BinOp { left, op: TokenKind::Assign, diff --git a/lang/src/lexer.rs b/lang/src/lexer.rs index 4a3232b2..fbaa25dc 100644 --- a/lang/src/lexer.rs +++ b/lang/src/lexer.rs @@ -131,6 +131,7 @@ pub enum TokenKind { Packed, True, False, + Null, Idk, Ctor, @@ -267,7 +268,8 @@ gen_token_kind! { Packed = b"packed", True = b"true", False = b"false", - Idk = b"idk", + Null = b"null", + Idk = b"idk", #[punkt] Ctor = ".{", Tupl = ".(", diff --git a/lang/src/parser.rs b/lang/src/parser.rs index 3a89ce2d..024c592b 100644 --- a/lang/src/parser.rs +++ b/lang/src/parser.rs @@ -335,6 +335,7 @@ impl<'a, 'b> Parser<'a, 'b> { }, T::True => E::Bool { pos, value: true }, T::False => E::Bool { pos, value: false }, + T::Null => E::Null { pos }, T::Idk => E::Idk { pos }, T::DQuote => E::String { pos, literal: self.tok_str(token) }, T::Packed => { @@ -881,6 +882,10 @@ generate_expr! { pos: Pos, value: bool, }, + /// `'null'` + Null { + pos: Pos, + }, /// `'idk'` Idk { pos: Pos, diff --git a/lang/src/son.rs b/lang/src/son.rs index 4ef84d3b..61603210 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -1714,6 +1714,30 @@ impl<'a> Codegen<'a> { fn raw_expr_ctx(&mut self, expr: &Expr, ctx: Ctx) -> Option { // ordered by complexity of the expression match *expr { + Expr::Null { pos } => { + let Some(ty) = ctx.ty else { + self.report( + pos, + "resulting pointer cannot be inferred from context, \ + consider using `@as(^, null)` to hint the type", + ); + return Value::NEVER; + }; + + if !ty.is_pointer() { + self.report( + pos, + fa!( + "'null' expression was inferred to be '{}', + which is not a pointer (and that is not supported yet)", + self.ty_display(ty) + ), + ); + return Value::NEVER; + } + + Some(self.ci.nodes.new_node_lit(ty, Kind::CInt { value: 0 }, [VOID])) + } Expr::Idk { pos } => { let Some(ty) = ctx.ty else { self.report( @@ -2812,7 +2836,7 @@ impl<'a> Codegen<'a> { } ref e => { self.report_unhandled_ast(e, "bruh"); - Some(Value::VOID) + Value::NEVER } } }