commit 830a9f0d339d5de45af8bcee5279f42de1ea575c
parent b8ecba974bf631cdb7814419a2c588a24232f9b1
Author: citbl <citbl@citbl.org>
Date: Thu, 20 Nov 2025 18:05:23 +1000
wip
Diffstat:
4 files changed, 325 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
@@ -6,3 +6,5 @@ fox
err.log
*.o
out
+notes.*
+*.webarchive
diff --git a/TODO b/TODO
@@ -7,7 +7,7 @@
[x] printing `-5` crashes, I think parsing is wrong for `-`, sees as value 5
[x] print allow more than 1 arg
[x] handle return values
-[ ] print allow format
+[ ] print allow format
[x] print anything else than a string
[x] call another function from main, that prints something,
[x] call another function that prints the passed argument
@@ -24,3 +24,18 @@
[x] redo arguments as list and not linked list, handle in parse and in gen (2 places in gen?)
[x] get rid of count_args and search for 'argc'
[ ] clean up symbols table from parsing to jit time
+
+@notes
+
+to get specific access to float sizes, gccjit@16 is required, which can't be easily built on macOS atm.
+
+ CC_JIT_TYPE_FLOAT16
+ GCC_JIT_TYPE_FLOAT32
+ GCC_JIT_TYPE_FLOAT64
+ GCC_JIT_TYPE_FLOAT128
+
+ otherwise these are target platform dependent
+
+ GCC_JIT_TYPE_FLOAT
+ GCC_JIT_TYPE_DOUBLE
+ GCC_JIT_TYPE_LONG_DOUBLE
diff --git a/oxdesign.ox b/oxdesign.ox
@@ -0,0 +1,248 @@
+i32 ~x = 42 // make a integer 32bit that is a variable (can be updated) `~` initialised with 2.
+i32 x = 42 // like a "let" statement or final variable, runtime constant.
+i32 #x = 42 // compile time constant
+
+// give me the raw pointer of x and assign it to y
+i32* y = &x
+
+
+// default types
+// i8, i16, i32, i64,
+// u8, u16, u32, u64,
+// f8, f16, f32, f64,
+// str, chr, bool,
+
+// arrays (fixed) and lists (dynamic)
+arr<i32>[16] ages // fixed slice of 16
+vec<i32> bobs // dynamic list
+set<str> names // sets
+
+type Person {
+ i32 age
+ str name
+}
+
+fn say_hello () void {
+ print("hello") // print is part of stdlib.local which is auto imported
+ warn("hello") // this print to stderr instead
+ print_("hello\n") // all of the above but with `_` won't insert a trailing \n
+ fatal("hello") // fatal print, returning non-zero
+}
+
+// strings are really arrays of special u32, aka vec<chr>
+typedef chr u32 // (but u32 is not a rune/chr, as the whole UTF-16 range does not cover u32)
+
+// exported function returns one i32
+fx add (i32 a, b) i32 => a + b
+
+// fx = function is exported
+// fn = function is static
+
+fx passed (Person p) {} // ownership passed and cannot be used after
+fn borrow (Person& p) {} // borrowed and unmutable
+fn mutate (Person~ p) {} // borrowed and mutable
+fn unsafe (Person* p) unsafe {} // C style passing of pointer, must tag `unsafe`
+
+// lambda style function definition
+fx add = (i32 a, b) i32 => a + b
+
+// void return is implicit, so is void type arg
+fx say_hello() {
+ print("hello")
+}
+
+// multiple return values go into parens
+fx flip(i32 a, b) (i32, i32) => b, a
+
+struct Person {
+ str name
+ i16 age
+ i32 number
+ str street
+ str suburb
+ str postcode
+ str country
+ // string interpolation `$.` is identifying a type component
+ fx address () str => "$.number, $.street, $.suburb $.postcode\n$.country"
+}
+
+extend Person {
+ ...
+}
+
+// lambda style main function
+fn main => print("hello world")
+
+fn main(i32 argc, arr<str> argv) int = {
+ if argc != 0 {
+ print("usage...")
+ return 0
+ }
+ print("hello world! $argc") // string interpolation similar to Dart's
+ return 0
+}
+
+fn rename({str name}) str {} // enforce the label to be passed: rename(name:"jack")
+
+// if statement don't have required parens, they're optional
+
+if a == b {
+ do_this();
+} else if a == c {
+ do_that();
+} else {
+ do_nothing();
+}
+
+// inline if can be done as is
+if cache_miss() { print("cached missed!") }
+
+// ternary if
+i32 bla = cond ? 42 : 420
+
+// for statements
+// classic for statement use commas separated init, cond and modifier
+for (i32 i = 0, i < 42, i++) {}
+
+for i32 i in 0..< 42 {} // shorthand for loop with for each
+
+for chr c in word {} // for each .. in
+
+for (chr c, i32 i) in word {} // for each in with index, parens optional
+
+// while loops
+while cond == true {
+ // body
+}
+
+// infinite loop until broken
+loop {}
+
+// switch
+switch (action.key) {
+ KEY_ENTER {
+ open_door()
+ }
+ KEY_UP { move_up() }
+ default {
+ warn("unsupported!")
+ }
+}
+
+// match expr
+chr c = match key {
+ 61 => 'a'
+ 62 => 'b'
+ default => '_'
+}
+
+
+// dealing with nil values. They're not allowed unless unsafe in play.
+Person? p = find("jack")
+
+if Person x = p {
+ print("found jack of ${x.age} age") // safe usage
+}
+
+if p {
+ print("found jack of ${p!.age} age") // force unwrap
+}
+
+Person* p = NULL // is allowed. NULL is a constant 0xffffff of some kind.
+
+// not allowed: Person&? Person~?
+
+// null coalescing of maybes
+print("jack may be of ${p?.age ?? \"some unknown\"}")
+
+i32 res = some_test() ?? 42
+
+// namespacing
+
+ns main // is default and not required, this unit will require a main function
+ns tools // loosely required to be in tools/
+
+// using namespaces, importing, namespaces are forced lowercase to not impact types
+
+use math // bring all of math functions in, to be prefixed by math.something
+use math { random, sin, cos } // limit the import to these symbols, directly accessible: sin()
+use math as mth // alias math to `mth`
+
+
+// async operations using the Aloha assignment operator `~=`
+
+i32? response = await some_long_action()
+
+// error handling
+
+fn fetch_data({str url}) async str! {
+ // fetch the data of the website, parse the body content
+ // return the body content
+ await ...
+ return content
+}
+
+struct Error {
+ u16 code
+ str message
+ Error? cause
+}
+
+str website_data = await try fetch_data(url: "fleacebook.com") or Error e => print("could not fetch data ${e.message}")
+
+
+fx flip(i32 a, b) (i32, i32)! {
+
+}
+
+
+// APPENDIX
+
+// keywords
+// return, break, continue, if, else, for, while, loop, goto, defer, heap, free,
+// type, ext, union, arr, vec, set, typedef, fx, fn, maybe, mut, ref, ptr, voidptr,
+// unsafe, inline
+
+
+// types
+// all of the
+// stdlib.local auto imported
+// equivalent of `use always { print, print_, warn, warn_, fatal }`
+// print, print_, warn, warn_, fatal
+
+// FFI interaction with C and C types
+// core FFI aliases
+typedef voidptr = void*
+typedef cstr = char*
+typedef ccstr = const char*
+
+use math
+use c <stdio.h>
+use c <stdlib.h>
+use c <stdint.h>
+use c "include/termbox2.h"
+
+extern c {
+ fn printf(ccstr, ...) int
+ fn free(voidptr)
+ fn malloc(size_t) voidptr
+ fn tb_print(i32, i32, u16, u16, cstr); // x, y, fg, bg, text
+
+ // NOTES
+ // don't use `const char*` etc. and warn against it at compile time
+ // use cstr or ccstr instead to avoid the baggage of weird
+ // pointer precedence and const position
+ //
+}
+
+fn main() {
+ voidptr ptr = malloc(65128)
+ // invalid: *ptr = 420 // voidptr should be undereferenceable
+ // no deref of voidptr without a cast
+ ptr<u8> bytes = cast(ptr<u8> p)
+ bytes[0] = 42
+ free(ptr)
+
+ // presume init called etc.
+ tb_print(12, 12, TB_MAGENTA, TB_BLACK, c_const_str("some words of wisdom"))
+}
diff --git a/stuff/micro/syntax/ox.yaml b/stuff/micro/syntax/ox.yaml
@@ -0,0 +1,59 @@
+filetype: ox
+
+detect:
+ filename: "(\\.(ox|OX)$)"
+
+rules:
+ - identifier: "\\b[A-Z_][0-9A-Z_]+\\b"
+ - type: "\\b(float|bool|char|int|uint|short|str|err|bool|string|long|enum|void|union|voidptr|typeof|typeof_unqual|(un)?signed|_Noreturn)\\b"
+ - type: "\\b((s?size)|ptr|cstr|ccstr|(i|u|f)(8|16|32)|chr)_?t?\\b"
+ - type: "\\b(_Float16|__fp16|_Float32|_Float32x|_Float64|_Float64x|__float80|_Float128|_Float128x|__float128|__ibm128|__int128|_Fract|_Sat|_Accum)\\b"
+ - type: "\\b[a-z_][0-9a-z_]+(_t|_T)\\b"
+ - type: "\\b[A-Z]I?[0-9a-zA-Z_]+\\b"
+ - statement: "\\b(auto|volatile|register|typedef|new|extend|restrict|_Alignas|alignas|_Alignof|alignof|static|async|await|inline|const|var|constexpr|extern c|_Thread_local|thread_local)\\b"
+ - statement: "\\b(fx|fn|use ?c?|as|try|or|export|c_str|c_const_str|unsafe|struct|set|vec|arr|free|heap|print_?|warn_?|fatal|cast|in|ns|for|each|if|while|loop|match|else|case|default|switch|_Generic|_Static_assert|static_assert)\\b"
+ - statement: "\\b(goto|continue|break|return)\\b"
+ - statement: "\\b(asm|fortran)\\b"
+ - preproc: "^[[:space:]]*#[[:space:]]*(define|embed|pragma|include|(un|ifn?)def|endif|el(if|ifdef|ifndef|se)|if|line|warning|error|__has_include|__has_embed|__has_c_attribute)"
+ - preproc: "^[[:space:]]*_Pragma\\b"
+ # GCC builtins
+ - statement: "__attribute__[[:space:]]*\\(\\([^)]*\\)\\)"
+ - statement: "__(aligned|asm|builtin|extension|hidden|inline|packed|restrict|section|typeof|weak)__"
+ # Operator Color
+ - symbol.operator: "[-+*/%=<>.:;,~&|^!?]|\\b(offsetof|sizeof)\\b"
+ - symbol.brackets: "[(){}]|\\[|\\]"
+ # Integer Constants
+ - constant.number: "(\\b([1-9][0-9]*|0[0-7]*|0[Xx][0-9A-Fa-f]+|0[Bb][01]+)([Uu][Ll]?[Ll]?|[Ll][Ll]?[Uu]?)?\\b)"
+ # Decimal Floating Constants
+ - constant.number: "(\\b(([0-9]*[.][0-9]+|[0-9]+[.][0-9]*)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)[FfLl]?\\b)"
+ # Hexadecimal Floating Constants
+ - constant.number: "(\\b0[Xx]([0-9A-Za-z]*[.][0-9A-Za-z]+|[0-9A-Za-z]+[.][0-9A-Za-z]*)[Pp][+-]?[0-9]+[FfLl]?\\b)"
+ - constant.bool: "(\\b(true|false|NULL|nullptr|TRUE|FALSE)\\b)"
+
+ - constant.string:
+ start: "\""
+ end: "\""
+ skip: "\\\\."
+ rules:
+ - constant.specialChar: "\\\\([\"'abfnrtv\\\\]|[0-3]?[0-7]{1,2}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})"
+
+ - constant.string:
+ start: "'"
+ end: "'"
+ skip: "\\\\."
+ rules:
+ # TODO: Revert back to - error: "..+" once #3127 is merged
+ - error: "[[:graph:]]{2,}'"
+ - constant.specialChar: "\\\\([\"'abfnrtv\\\\]|[0-3]?[0-7]{1,2}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})"
+
+ - comment:
+ start: "//"
+ end: "$"
+ rules:
+ - todo: "(TODO|XXX|FIXME):?"
+
+ - comment:
+ start: "/\\*"
+ end: "\\*/"
+ rules:
+ - todo: "(TODO|XXX|FIXME):?"