From 739c3638a69299e0e99f5d8c5302233fbc624d27 Mon Sep 17 00:00:00 2001 From: zongor Date: Sun, 26 Oct 2025 14:49:00 -0700 Subject: [PATCH] Code cleanup, add halt return type, add neg and abs ops, fix strings, --- Makefile | 2 +- README.org | 32 +- ROADMAP.org | 256 ++++++++++--- docs/project-syntax-example/client.ul | 44 --- docs/project-syntax-example/common.ul | 81 ---- docs/project-syntax-example/server.ul | 22 -- src/arch/linux/devices.h | 5 +- src/arch/linux/main.c | 521 +++++++++++++------------- src/tools/assembler.c | 70 +++- src/tools/lexer.c | 104 ++++- src/tools/lexer.h | 7 +- src/tools/parser.c | 20 +- src/vm/common.h | 4 +- src/vm/device.c | 25 +- src/vm/device.h | 6 +- src/vm/{str.c => libc.c} | 2 +- src/vm/{str.h => libc.h} | 4 +- src/vm/opcodes.h | 58 +-- src/vm/vm.c | 36 +- src/vm/vm.h | 7 +- test/add.asm.lisp | 8 +- test/fib.asm.lisp | 2 +- test/hello.asm.lisp | 2 +- test/loop.asm.lisp | 2 +- test/loop.ul | 2 +- test/malloc.asm.lisp | 2 +- test/paint-bw.asm.lisp | 2 +- test/paint-bw.ul | 27 +- test/paint.asm.lisp | 2 +- test/paint.ul | 43 ++- test/simple.asm.lisp | 2 +- test/window.asm.lisp | 2 +- test/window.ul | 19 +- 33 files changed, 755 insertions(+), 666 deletions(-) delete mode 100644 docs/project-syntax-example/client.ul delete mode 100644 docs/project-syntax-example/common.ul delete mode 100644 docs/project-syntax-example/server.ul rename src/vm/{str.c => libc.c} (99%) rename src/vm/{str.h => libc.h} (90%) diff --git a/Makefile b/Makefile index c5ce8ef..716919e 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,7 @@ endif VM_SOURCES := \ $(SRC_DIR)/vm/vm.c \ $(SRC_DIR)/vm/device.c \ - $(SRC_DIR)/vm/str.c + $(SRC_DIR)/vm/libc.c ifeq ($(BUILD_MODE), release) PLATFORM_SOURCE := $(ARCH_DIR)/main.c \ diff --git a/README.org b/README.org index 266ec69..c6495c4 100644 --- a/README.org +++ b/README.org @@ -17,7 +17,7 @@ * Undâr -Undâr is a programming language for the purpose of creating three dimensional video games and graphical user interfaces that work on constrained systems, microcontrollers, retro consoles, and the using emscripten. The language emphasizes hardware longevity, energy efficiency, and the preservation of digital art and games for future generations. +Undâr is a programming language for the purpose of creating 3D games and graphical user interfaces that work on constrained systems, microcontrollers, retro consoles, and the web using emscripten. The language emphasizes hardware longevity, energy efficiency, and the preservation of digital art and games for future generations. It has an internal REPL that allows for quick development as well as the ability to dump the program to a binary rom for preserving that program/game/etc. @@ -66,11 +66,10 @@ The Undâr compiler will be written in Sċieppan, as well as core VM tests. (load-immediate $11 0) (syscall OPEN $1 $1 $11) (load-immediate $3 &new-line) - (load-offset-32 $7 $1 4) ; load handle (string-length $2 $0) - (syscall WRITE $7 $0 $2) + (syscall WRITE $1 $0 $2) (string-length $4 $3) - (syscall WRITE $7 $3 $4) + (syscall WRITE $1 $3 $4) (return nil))) (data (label terminal-namespace "/dev/term/0") @@ -102,18 +101,16 @@ heap allocations using the internal malloc opcode push pointers within this fram (load-immediate $1 32) ; read in a string of max 32 char length (malloc $4 $1) ; allocate memory for the string - (load-offset-32 $7 $0 4) ; load handle - (syscall READ $7 $2 $1 $4) ; read the string + (syscall READ $0 $4 $1) ; read the string (call &pln ($0 $4) nil) ; print the string (halt)) (label pln (load-immediate $3 &new-line) - (load-offset-32 $7 $0 4) ; load handle (string-length $2 $1) - (syscall WRITE $7 $1 $2) + (syscall WRITE $0 $1 $2) (string-length $4 $3) - (syscall WRITE $7 $3 $4) + (syscall WRITE $0 $3 $4) (return nil))) (data (label terminal-namespace "/dev/term/0") @@ -125,15 +122,14 @@ values passed to functions must be explicitly returned to propagate. heap values **Core Types** -| Type | Description | -|--------+-------------------------------------------| -| =int= | 32-bit signed integer | -| =nat= | 32-bit natural number | -| =real= | Q16.16 fixed-point real number | -| =str= | fat pointer [length + data] string | -| =bool= | true/false | -| =char= | Character | -| =ref= | Reference prefix for passing by reference | +| Type | Description | +|------+------------------------------------| +| =int= | 32-bit signed integer | +| =nat= | 32-bit natural number | +| =real= | Q16.16 fixed-point real number | +| =str= | fat pointer [length + data] string | +| =bool= | true/false | +| =byte= | Character/8 bit unsigned int | A ref type allows pass by reference similar to a pointer in c. most types will be pass by value with some types being explicitly pass by reference. diff --git a/ROADMAP.org b/ROADMAP.org index aaef8cb..61b68f5 100644 --- a/ROADMAP.org +++ b/ROADMAP.org @@ -10,57 +10,34 @@ * Roadmap -** Actor System - -* Actor-Based Concurrency Model (Frame-Managed Memory) - -** Core Principles -- Deterministic memory management with no garbage collection or manual free -- Zero fragmentation via contiguous arena allocation -- Isolated memory spaces for all actors (no shared memory) -- Compile-time memory bounds enforcement -- Mission-critical certified (DO-178C Level A compliant) - -** Memory Architecture -- Actor memory is partitioned into fixed-size arenas -- Two primary arenas: - - =Main Thread Arena= (top of memory) - - =Actor Arenas= (bottom-up allocation) -- Arena layout: - #+begin_src text - |---------------------| <-- Top of memory - | MAIN THREAD | (e.g., 8KB) - |---------------------| <-- Base address of actor pool - | ACTOR 1 (4KB) | <-- Preallocated at system startup - |---------------------| - | ACTOR 2 (2KB) | <-- Size specified by developer - |---------------------| - | ACTOR 3 (1KB) | - |---------------------| <-- Bottom of memory - #+end_src - -*** Communication Protocol -- Bounded mailbox system -- Message flow: - 1. Main thread sends via =send_message()= - 2. Message copied into actor's mailbox - 3. Actor processes in =on_message()= during next cycle - 4. Actor sends response via =send_response()= - -*** Failure Behaviors -| Behavior | Action | Certification Impact | Example Use Case | -|----------------|----------------------------|----------------------|--------------------------| -| =RESTART= | Reset arena offset to 0 | 2 artifacts | Network reconnection | -| =EXIT= | Free arena | 1 artifact | Session termination | -| =CRASH= | Halt entire VM | 1 artifact | Critical subsystem fail | - ** Example: Hello world (=hello.ul=) *WIP syntax, not final implementation** #+BEGIN_SRC ul -fn main(int argc, str[] argv) { - print("nuqneH 'u'?"); +/** + * Constants + */ +const str nl = "\n"; + +plex Terminal { + nat handle; +} + +/** + * Main function + */ +function main() { + pln("nuqneH 'u'?"); +} + +/** + * Print with a newline + */ +function pln(str message) { + Terminal term = open("/dev/term/0", 0); + write(term, message, message.length); + write(term, nl, nl.length); } #+END_SRC @@ -68,42 +45,161 @@ fn main(int argc, str[] argv) { **WIP syntax, not final implementation** -#+BEGIN_SRC ul -use "common.ul"; +Common: -fn256 main(int argc, str[] argv) { - nat w = 800, h = 450; - Player me(argv[1], [0.0, 1.0, 2.0], PURPLE); +#+BEGIN_SRC ul +/** + * Camera. + */ +plex Camera { + int setting; + real pov; + real[3] up; + real[3] pos; + real[3] look; + + init(real[3] pos, real[3] look) { + this.setting = CAMERA_PERSPECTIVE; + this.pov = 45.0; + this.up = [0.0, 1.0, 0.0]; + this.pos = pos; + this.look = look; + } +} + +/** + * Player. + */ +plex Player { + Client client; + str username; + real[3] pos; + nat color; + Camera camera; + + init(str username, real[3] pos, Color color) { + this.client = Client("tcp://localhost:25565"); + this.username = username; + this.pos = pos; + this.color = color; + this.camera = + Camera([this.pos.x + 10.0, this.pos.y + 10.0, this.pos.z], this.pos); + } + + login(str password) Player[] { // looks like a method but really it just has an implied "Player this" as the first argument + this.client.attach(this.username, password); + this.players = client.open("players"); + return players.read(); + } + + logout() { + this.players.flush(); + this.client.clunk(); + } + + update() { + if (key_down("right")) { + this.pos.x += 0.2; + this.client.write(Command(this.username, KEY_RIGHT)) + } + + if (key_down("left")) { + this.pos.x -= 0.2; + this.client.write(Command(this.username, KEY_LEFT)) + } + + if (key_down("down")) { + this.pos.z += 0.2; + this.client.write(Command(this.username, KEY_DOWN)) + } + + if (key_down("up")) { + this.pos.z -= 0.2; + this.client.write(Command(this.username, KEY_UP)) + } + this.camera.sync(); + } +} + +const nat RED = rgb332([255, 0, 0]); +const nat WHITE = rgb332([0, 0, 0]); +const nat PURPLE = rgb332([255, 255, 0]); +#+END_SRC + +Client: +#+BEGIN_SRC ul +use ; // from stdlib +use "common.ul"; // from local + +function main(int argc, str[] argv) { + nat screen_width = 800; + nat screen_height = 450; + + if (argv < 2) { + pln("usage: undar client.ul "); + exit(-1); + } + str username = argv[1]; + str password = argv[2]; + + Player me(username, [0.0, 1.0, 2.0], PURPLE); bool running = true; while (running) { - window("Client", w, h) { - splitbox(parent.size, 0.25) { + window("zwl client", screen_width, screen_height) { + splitbox(parent.size 0.25) { canvas() { - if (button("Logout")) { + if (button("logout")) { me.logout(); running = false; } } } - splitbox(parent.size, 0.75) { + splitbox(parent.size 0.75) { canvas() { model(Floor([0, 0, 0], 30)); me.update(); - model(Cube(me.pos, [0.5,0.5,0.5], me.color)); - if (Player[] others = me.server.read("players")) { - for (p in others) { - model(Cube(p.pos, [0.5,0.5,0.5], p.color)); + model(Cube(me.pos, [0.5, 0.5, 0.5], me.appearance)); + if (Player[] players = me.server.read("players")) { + for (p in players) { + model(Cube(p.pos, [0.5, 0.5, 0.5], p.apperance)); } } } } } } + exits("Client Closed Successfully"); } #+END_SRC +Server: +#+BEGIN_SRC ul +use "common.ul"; + +function main(int argc, str[] argv) { + Server s("tcp://0.0.0.0:25565"); + bool running = true; + Player[] players = [Player("user", [0.0, 0.0, 0.0], RED)]; + while (running) { + if (Client client = s.accept("players")) { + if (Message message = client.get()) { + if (message.t == "close") { + client.close(); + running = false; + } else if (message.t == "players") { + client.write(players); + } else { + print("unknown message {message}"); + } + } + } + } + exits(nil); +} +#+END_SRC + ** Plex A =plex= is a structure which, works like a struct but syntactically looks like a class. the naming of "plex" comes from douglas ross's paper "a generalized technique for symbol manipulation and numerical calculation". It is used instead of "class" or "struct" is to make a break from the historical baggage of "classes". unlike classes it does not describe a object in real life and copy it, but it allows for a convenient way to mediate states and handling. i.e. compositions + encodings instead of oop/polymorphisms. for example, instead of having a struct with a bool flag in it (like for a game alive/dead), we can create a multilist where the structs move from a "alive" list to a "dead" list; or things like that. instances of a plex in memory are called "atoms". @@ -194,3 +290,45 @@ if (server.attach(auth)) { | =.clunk()= | Close communication | | =.stat()= | returns the status of the file resource | | =.version()= | returns the version code for the connected tunnel | + +** Actor System + +*** Core Principles +- Deterministic memory management with no garbage collection or manual free +- Zero fragmentation via contiguous arena allocation +- Isolated memory spaces for all actors (no shared memory) +- Compile-time memory bounds enforcement +- Mission-critical certified (DO-178C Level A compliant) + +*** Memory Architecture +- Actor memory is partitioned into fixed-size arenas +- Two primary arenas: + - =Main Thread Arena= (top of memory) + - =Actor Arenas= (bottom-up allocation) +- Arena layout: + #+begin_src text + |---------------------| <-- Top of memory + | MAIN THREAD | (e.g., 8KB) + |---------------------| <-- Base address of actor pool + | ACTOR 1 (4KB) | <-- Preallocated at system startup + |---------------------| + | ACTOR 2 (2KB) | <-- Size specified by developer + |---------------------| + | ACTOR 3 (1KB) | + |---------------------| <-- Bottom of memory + #+end_src + +*** Communication Protocol +- Bounded mailbox system +- Message flow: + 1. Main thread sends via =send_message()= + 2. Message copied into actor's mailbox + 3. Actor processes in =on_message()= during next cycle + 4. Actor sends response via =send_response()= + +*** Failure Behaviors +| Behavior | Action | Certification Impact | Example Use Case | +|----------+-------------------------+----------------------+-------------------------| +| =RESTART= | Reset arena offset to 0 | 2 artifacts | Network reconnection | +| =EXIT= | Free arena | 1 artifact | Session termination | +| =CRASH= | Halt entire VM | 1 artifact | Critical subsystem fail | diff --git a/docs/project-syntax-example/client.ul b/docs/project-syntax-example/client.ul deleted file mode 100644 index c876ade..0000000 --- a/docs/project-syntax-example/client.ul +++ /dev/null @@ -1,44 +0,0 @@ -use ; // from stdlib -use "common.ul"; // from local - -function main(int argc, str[] argv) { - nat screen_width = 800; - nat screen_height = 450; - - if (argv < 2) { - pln("usage: undar client.ul "); - exit(-1); - } - str username = argv[1]; - str password = argv[2]; - - Player me(username, [0.0, 1.0, 2.0], PURPLE); - - bool running = true; - while (running) { - window("zwl client", screen_width, screen_height) { - splitbox(parent.size 0.25) { - canvas() { - if (button("logout")) { - me.logout(); - running = false; - } - } - } - splitbox(parent.size 0.75) { - canvas() { - model(Floor([0, 0, 0], 30)); - me.update(); - model(Cube(me.pos, [0.5, 0.5, 0.5], me.appearance)); - if (Player[] players = me.server.read("players")) { - for (p in players) { - model(Cube(p.pos, [0.5, 0.5, 0.5], p.apperance)); - } - } - } - } - } - } - - exits("Client Closed Successfully"); -} diff --git a/docs/project-syntax-example/common.ul b/docs/project-syntax-example/common.ul deleted file mode 100644 index 3867eb6..0000000 --- a/docs/project-syntax-example/common.ul +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Note that these look like classes but act like structs - * the methods actually have a implied struct as their first argument - */ - -/** - * Camera. - */ -plex Camera { - int setting; - real pov; - real[3] up; - real[3] pos; - real[3] look; - - init(real[3] pos, real[3] look) { - this.setting = CAMERA_PERSPECTIVE; - this.pov = 45.0; - this.up = [0.0, 1.0, 0.0]; - this.pos = pos; - this.look = look; - } -} - -/** - * Player. - */ -plex Player { - Client client; - str username; - real[3] pos; - nat color; - Camera camera; - - init(str username, real[3] pos, Color color) { - this.client = Client("tcp://localhost:25565"); - this.username = username; - this.pos = pos; - this.color = color; - this.camera = - Camera([this.pos.x + 10.0, this.pos.y + 10.0, this.pos.z], this.pos); - } - - login(str password) Player[] { // looks like a method but really it just has an implied "Player this" as the first argument - this.client.attach(this.username, password); - this.players = client.open("players"); - return players.read(); - } - - logout() { - this.players.flush(); - this.client.clunk(); - } - - update() { - if (key_down("right")) { - this.pos.x += 0.2; - this.client.write(Command(this.username, KEY_RIGHT)) - } - - if (key_down("left")) { - this.pos.x -= 0.2; - this.client.write(Command(this.username, KEY_LEFT)) - } - - if (key_down("down")) { - this.pos.z += 0.2; - this.client.write(Command(this.username, KEY_DOWN)) - } - - if (key_down("up")) { - this.pos.z -= 0.2; - this.client.write(Command(this.username, KEY_UP)) - } - this.camera.sync(); - } -} - -const nat RED = rgb332([255, 0, 0]); -const nat WHITE = rgb332([0, 0, 0]); -const nat PURPLE = rgb332([255, 255, 0]); diff --git a/docs/project-syntax-example/server.ul b/docs/project-syntax-example/server.ul deleted file mode 100644 index 677b743..0000000 --- a/docs/project-syntax-example/server.ul +++ /dev/null @@ -1,22 +0,0 @@ -use "common.ul"; - -function main(int argc, str[] argv) { - Server s("tcp://0.0.0.0:25565"); - bool running = true; - Player[] players = [Player("user", [0.0, 0.0, 0.0], RED)]; - while (running) { - if (Client client = s.accept("players")) { - if (Message message = client.get()) { - if (message.t == "close") { - client.close(); - running = false; - } else if (message.t == "players") { - client.write(players); - } else { - print("unknown message {message}"); - } - } - } - } - exits(nil); -} diff --git a/src/arch/linux/devices.h b/src/arch/linux/devices.h index d0a5549..946ed28 100644 --- a/src/arch/linux/devices.h +++ b/src/arch/linux/devices.h @@ -26,16 +26,13 @@ typedef struct mouse_device_data_s { u8 btn2; u8 btn3; u8 btn4; - u32 size; } MouseDeviceData; /* Keyboard device data */ typedef struct keyboard_device_data_s { u32 handle; - const u8 *keys; i32 key_count; - u32 pos; - u32 size; + const u8 *keys; } KeyboardDeviceData; /* Console device data */ diff --git a/src/arch/linux/main.c b/src/arch/linux/main.c index 8bcfe9a..cad07d3 100644 --- a/src/arch/linux/main.c +++ b/src/arch/linux/main.c @@ -1,6 +1,6 @@ #include "../../tools/assembler.h" -#include "../../tools/parser.h" #include "../../tools/lexer.h" +#include "../../tools/parser.h" #include "../../vm/vm.h" #include "devices.h" #include @@ -32,14 +32,12 @@ static DeviceOps keyboard_ops = {.open = keyboard_open, .ioctl = nil, .refresh = nil}; -static DeviceOps console_device_ops = { - .open = console_open, - .read = console_read, - .write = console_write, - .close = console_close, - .ioctl = console_ioctl, - .refresh = nil -}; +static DeviceOps console_device_ops = {.open = console_open, + .read = console_read, + .write = console_write, + .close = console_close, + .ioctl = console_ioctl, + .refresh = nil}; static ScreenDeviceData screen_data = {0}; static MouseDeviceData mouse_data = {0}; @@ -156,11 +154,8 @@ bool compileAndSave(const char *source_file, const char *output_file, VM *vm) { break; // Stop on error, or continue if you want to see more } if (token.type != TOKEN_EOF) { - printf("Line %d [%s]: %.*s\n", - token.line, - tokenTypeToString(token.type), - token.length, - token.start); + printf("Line %d [%s]: %.*s\n", token.line, tokenTypeToString(token.type), + token.length, token.start); } } while (token.type != TOKEN_EOF); @@ -278,137 +273,137 @@ void repl(VM *vm) { } // If unbalanced, continue reading more lines } - exit(0); + exit(vm->flag); } - #ifdef ASM_DEBUG const char *opcode_to_string(Opcode op) { static const char *names[] = { - [OP_HALT] = "halt", - [OP_JMP] = "jump", - [OP_JMPF] = "jump-if-flag", - [OP_CALL] = "call", - [OP_RETURN] = "return", - - /* Immediate loads (only 32-bit variant needed) */ - [OP_LOAD_IMM] = "load-immediate", - - /* Register-indirect loads */ - [OP_LOAD_IND_8] = "load-indirect-8", - [OP_LOAD_IND_16] = "load-indirect-16", - [OP_LOAD_IND_32] = "load-indirect-32", - - /* Absolute address loads */ - [OP_LOAD_ABS_8] = "load-absolute-8", - [OP_LOAD_ABS_16] = "load-absolute-16", - [OP_LOAD_ABS_32] = "load-absolute-32", - - /* Base+offset loads */ - [OP_LOAD_OFF_8] = "load-offset-8", - [OP_LOAD_OFF_16] = "load-offset-16", - [OP_LOAD_OFF_32] = "load-offset-32", - - /* Absolute address stores */ - [OP_STORE_ABS_8] = "store-absolute-8", - [OP_STORE_ABS_16] = "store-absolute-16", - [OP_STORE_ABS_32] = "store-absolute-32", - - /* Register-indirect stores */ - [OP_STORE_IND_8] = "store-indirect-8", - [OP_STORE_IND_16] = "store-indirect-16", - [OP_STORE_IND_32] = "store-indirect-32", - - /* Base+offset stores */ - [OP_STORE_OFF_8] = "store-offset-8", - [OP_STORE_OFF_16] = "store-offset-16", - [OP_STORE_OFF_32] = "store-offset-32", - - /* Memory operations */ - [OP_MALLOC] = "malloc", - [OP_MEMSET_8] = "memset-8", - [OP_MEMSET_16] = "memset-16", - [OP_MEMSET_32] = "memset-32", - - /* Stack operations */ - [OP_PUSH] = "push", - [OP_POP] = "pop", - - /* Register operations */ - [OP_REG_MOV] = "register-move", - [OP_SYSCALL] = "syscall", - - /* Bit operations */ - [OP_SLL] = "bit-shift-left", - [OP_SRL] = "bit-shift-right", - [OP_SRE] = "bit-shift-re", - [OP_BAND] = "bit-and", - [OP_BOR] = "bit-or", - [OP_BXOR] = "bit-xor", - - /* Integer arithmetic */ - [OP_ADD_INT] = "add-int", - [OP_SUB_INT] = "sub-int", - [OP_MUL_INT] = "mul-int", - [OP_DIV_INT] = "div-int", - - /* Natural number arithmetic */ - [OP_ADD_NAT] = "add-nat", - [OP_SUB_NAT] = "sub-nat", - [OP_MUL_NAT] = "mul-nat", - [OP_DIV_NAT] = "div-nat", - - /* Floating point operations */ - [OP_ADD_REAL] = "add-real", - [OP_SUB_REAL] = "sub-real", - [OP_MUL_REAL] = "mul-real", - [OP_DIV_REAL] = "div-real", - - /* Type conversions */ - [OP_INT_TO_REAL] = "int-to-real", - [OP_NAT_TO_REAL] = "nat-to-real", - [OP_REAL_TO_INT] = "real-to-int", - [OP_REAL_TO_NAT] = "real-to-nat", - - /* Integer comparisons */ - [OP_JEQ_INT] = "jump-eq-int", - [OP_JNEQ_INT] = "jump-neq-int", - [OP_JGT_INT] = "jump-gt-int", - [OP_JLT_INT] = "jump-lt-int", - [OP_JLE_INT] = "jump-le-int", - [OP_JGE_INT] = "jump-ge-int", - - /* Natural number comparisons */ - [OP_JEQ_NAT] = "jump-eq-nat", - [OP_JNEQ_NAT] = "jump-neq-nat", - [OP_JGT_NAT] = "jump-gt-nat", - [OP_JLT_NAT] = "jump-lt-nat", - [OP_JLE_NAT] = "jump-le-nat", - [OP_JGE_NAT] = "jump-ge-nat", - - /* Floating point comparisons */ - [OP_JEQ_REAL] = "jump-eq-real", - [OP_JNEQ_REAL] = "jump-neq-real", - [OP_JGE_REAL] = "jump-ge-real", - [OP_JGT_REAL] = "jump-gt-real", - [OP_JLT_REAL] = "jump-lt-real", - [OP_JLE_REAL] = "jump-le-real", - - /* String operations */ - [OP_STRLEN] = "string-length", - [OP_STREQ] = "string-eq", - [OP_STRCAT] = "string-concat", - [OP_STR_GET_CHAR] = "string-get-char", - [OP_STR_FIND_CHAR] = "string-find-char", - [OP_STR_SLICE] = "string-slice", - - /* String conversions */ - [OP_INT_TO_STRING] = "int-to-string", - [OP_NAT_TO_STRING] = "nat-to-string", - [OP_REAL_TO_STRING] = "real-to-string", - [OP_STRING_TO_INT] = "string-to-int", - [OP_STRING_TO_NAT] = "string-to-nat", - [OP_STRING_TO_REAL] = "string-to-real" - }; + [OP_HALT] = "halt", + [OP_JMP] = "jump", + [OP_JMPF] = "jump-if-flag", + [OP_CALL] = "call", + [OP_RETURN] = "return", + + /* Immediate loads (only 32-bit variant needed) */ + [OP_LOAD_IMM] = "load-immediate", + + /* Register-indirect loads */ + [OP_LOAD_IND_8] = "load-indirect-8", + [OP_LOAD_IND_16] = "load-indirect-16", + [OP_LOAD_IND_32] = "load-indirect-32", + + /* Absolute address loads */ + [OP_LOAD_ABS_8] = "load-absolute-8", + [OP_LOAD_ABS_16] = "load-absolute-16", + [OP_LOAD_ABS_32] = "load-absolute-32", + + /* Base+offset loads */ + [OP_LOAD_OFF_8] = "load-offset-8", + [OP_LOAD_OFF_16] = "load-offset-16", + [OP_LOAD_OFF_32] = "load-offset-32", + + /* Absolute address stores */ + [OP_STORE_ABS_8] = "store-absolute-8", + [OP_STORE_ABS_16] = "store-absolute-16", + [OP_STORE_ABS_32] = "store-absolute-32", + + /* Register-indirect stores */ + [OP_STORE_IND_8] = "store-indirect-8", + [OP_STORE_IND_16] = "store-indirect-16", + [OP_STORE_IND_32] = "store-indirect-32", + + /* Base+offset stores */ + [OP_STORE_OFF_8] = "store-offset-8", + [OP_STORE_OFF_16] = "store-offset-16", + [OP_STORE_OFF_32] = "store-offset-32", + + /* Memory operations */ + [OP_MALLOC] = "malloc", + [OP_MEMSET_8] = "memset-8", + [OP_MEMSET_16] = "memset-16", + [OP_MEMSET_32] = "memset-32", + + /* Register operations */ + [OP_REG_MOV] = "register-move", + [OP_SYSCALL] = "syscall", + + /* Bit operations */ + [OP_BIT_SHIFT_LEFT] = "bit-shift-left", + [OP_BIT_SHIFT_RIGHT] = "bit-shift-right", + [OP_BIT_SHIFT_R_EXT] = "bit-shift-r-ext", + [OP_BAND] = "bit-and", + [OP_BOR] = "bit-or", + [OP_BXOR] = "bit-xor", + + /* Integer arithmetic */ + [OP_ADD_INT] = "add-int", + [OP_SUB_INT] = "sub-int", + [OP_MUL_INT] = "mul-int", + [OP_DIV_INT] = "div-int", + [OP_ABS_INT] = "abs-int", // ← NEW + [OP_NEG_INT] = "neg-int", // ← NEW + + /* Natural number arithmetic */ + [OP_ADD_NAT] = "add-nat", + [OP_SUB_NAT] = "sub-nat", + [OP_MUL_NAT] = "mul-nat", + [OP_DIV_NAT] = "div-nat", + [OP_ABS_NAT] = "abs-nat", // ← NEW + [OP_NEG_NAT] = "neg-nat", // ← NEW + + /* Floating point operations */ + [OP_ADD_REAL] = "add-real", + [OP_SUB_REAL] = "sub-real", + [OP_MUL_REAL] = "mul-real", + [OP_DIV_REAL] = "div-real", + [OP_ABS_REAL] = "abs-real", // ← NEW + [OP_NEG_REAL] = "neg-real", // ← NEW + + /* Type conversions */ + [OP_INT_TO_REAL] = "int-to-real", + [OP_NAT_TO_REAL] = "nat-to-real", + [OP_REAL_TO_INT] = "real-to-int", + [OP_REAL_TO_NAT] = "real-to-nat", + + /* Integer comparisons */ + [OP_JEQ_INT] = "jump-eq-int", + [OP_JNEQ_INT] = "jump-neq-int", + [OP_JGT_INT] = "jump-gt-int", + [OP_JLT_INT] = "jump-lt-int", + [OP_JLE_INT] = "jump-le-int", + [OP_JGE_INT] = "jump-ge-int", + + /* Natural number comparisons */ + [OP_JEQ_NAT] = "jump-eq-nat", + [OP_JNEQ_NAT] = "jump-neq-nat", + [OP_JGT_NAT] = "jump-gt-nat", + [OP_JLT_NAT] = "jump-lt-nat", + [OP_JLE_NAT] = "jump-le-nat", + [OP_JGE_NAT] = "jump-ge-nat", + + /* Floating point comparisons */ + [OP_JEQ_REAL] = "jump-eq-real", + [OP_JNEQ_REAL] = "jump-neq-real", + [OP_JGE_REAL] = "jump-ge-real", + [OP_JGT_REAL] = "jump-gt-real", + [OP_JLT_REAL] = "jump-lt-real", + [OP_JLE_REAL] = "jump-le-real", + + /* String operations */ + [OP_STRLEN] = "string-length", + [OP_STREQ] = "string-eq", + [OP_STRCAT] = "string-concat", + [OP_STR_GET_CHAR] = "string-get-char", + [OP_STR_FIND_CHAR] = "string-find-char", + [OP_STR_SLICE] = "string-slice", + + /* String conversions */ + [OP_INT_TO_STRING] = "int-to-string", + [OP_NAT_TO_STRING] = "nat-to-string", + [OP_REAL_TO_STRING] = "real-to-string", + [OP_STRING_TO_INT] = "string-to-int", + [OP_STRING_TO_NAT] = "string-to-nat", + [OP_STRING_TO_REAL] = "string-to-real"}; if (op < 0 || op >= (int)(sizeof(names) / sizeof(names[0]))) { return ""; @@ -420,7 +415,6 @@ const char *opcode_to_string(Opcode op) { #endif i32 main(i32 argc, char *argv[]) { - bool gui_mode = false; bool dump_rom = false; char *input_file = nil; char *output_file = nil; @@ -429,10 +423,7 @@ i32 main(i32 argc, char *argv[]) { // Parse command line arguments for (i32 i = 1; i < argc; i++) { - if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "--gui") == 0) { - gui_mode = true; - } else if (strcmp(argv[i], "-o") == 0 || - strcmp(argv[i], "--dump-rom") == 0) { + if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--dump-rom") == 0) { dump_rom = true; } else if (input_file == nil) { // This is the input file @@ -496,145 +487,135 @@ i32 main(i32 argc, char *argv[]) { vm_register_device(&vm, "/dev/term/0", "terminal", &console_data, &console_device_ops, 4); - if (gui_mode) { - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - printf("SDL initialization failed: %s\n", SDL_GetError()); - return 1; - } - SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + printf("SDL initialization failed: %s\n", SDL_GetError()); + return 1; + } + SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); - screen_data.width = 640; - screen_data.height = 480; - screen_data.buffer_size = screen_data.width * screen_data.height; + screen_data.width = 640; + screen_data.height = 480; + screen_data.buffer_size = screen_data.width * screen_data.height; - vm_register_device(&vm, "/dev/screen/0", "screen", &screen_data, - &screen_ops, 16 + screen_data.buffer_size); + vm_register_device(&vm, "/dev/screen/0", "screen", &screen_data, &screen_ops, + 16 + screen_data.buffer_size); - mouse_data.x = 0; - mouse_data.y = 0; - mouse_data.btn1 = 0; - mouse_data.btn2 = 0; - mouse_data.btn3 = 0; - mouse_data.btn4 = 0; - mouse_data.size = 16; + mouse_data.x = 0; + mouse_data.y = 0; + mouse_data.btn1 = 0; + mouse_data.btn2 = 0; + mouse_data.btn3 = 0; + mouse_data.btn4 = 0; - vm_register_device(&vm, "/dev/mouse/0", "mouse", &mouse_data, &mouse_ops, - mouse_data.size); + vm_register_device(&vm, "/dev/mouse/0", "mouse", &mouse_data, &mouse_ops, 16); - keyboard_data.keys = SDL_GetKeyboardState(&keyboard_data.key_count); - vm_register_device(&vm, "/dev/keyboard/0", "keyboard", &keyboard_data, - &keyboard_ops, keyboard_data.key_count + 4); + keyboard_data.keys = SDL_GetKeyboardState(&keyboard_data.key_count); + vm_register_device(&vm, "/dev/keyboard/0", "keyboard", &keyboard_data, + &keyboard_ops, keyboard_data.key_count + 4); - SDL_Event event; - bool running = true; - SDL_PumpEvents(); - while (running) { - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_QUIT: - running = false; - break; - // Mouse events - case SDL_MOUSEMOTION: - mouse_data.x = event.motion.x; - mouse_data.y = event.motion.y; - break; + SDL_Event event; + bool running = true; + SDL_PumpEvents(); + while (running) { + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + running = false; + break; + // Mouse events + case SDL_MOUSEMOTION: + mouse_data.x = event.motion.x; + mouse_data.y = event.motion.y; + break; - case SDL_MOUSEBUTTONDOWN: - if (event.button.button == SDL_BUTTON_LEFT) + case SDL_MOUSEBUTTONDOWN: + if (event.button.button == SDL_BUTTON_LEFT) + mouse_data.btn1 = 1; + if (event.button.button == SDL_BUTTON_RIGHT) + mouse_data.btn2 = 1; + if (event.button.button == SDL_BUTTON_MIDDLE) + mouse_data.btn3 = 1; + if (event.button.button == SDL_BUTTON_X1) + mouse_data.btn4 = 1; + break; + + case SDL_MOUSEBUTTONUP: + if (event.button.button == SDL_BUTTON_LEFT) + mouse_data.btn1 = 0; + if (event.button.button == SDL_BUTTON_RIGHT) + mouse_data.btn2 = 0; + if (event.button.button == SDL_BUTTON_MIDDLE) + mouse_data.btn3 = 0; + if (event.button.button == SDL_BUTTON_X1) + mouse_data.btn4 = 0; + break; + + // Touch events (map to mouse_data as left-click equivalent) + case SDL_FINGERMOTION: + case SDL_FINGERDOWN: + case SDL_FINGERUP: { + + float x = event.tfinger.x * 640; + float y = event.tfinger.y * 480; + + mouse_data.x = (int)x; + mouse_data.y = (int)y; + + // Only treat the first finger as mouse input (ignore multi-touch + // beyond 1 finger) + if (event.tfinger.fingerId == 0) { + if (event.type == SDL_FINGERDOWN || event.type == SDL_FINGERMOTION) { mouse_data.btn1 = 1; - if (event.button.button == SDL_BUTTON_RIGHT) - mouse_data.btn2 = 1; - if (event.button.button == SDL_BUTTON_MIDDLE) - mouse_data.btn3 = 1; - if (event.button.button == SDL_BUTTON_X1) - mouse_data.btn4 = 1; - break; - - case SDL_MOUSEBUTTONUP: - if (event.button.button == SDL_BUTTON_LEFT) + } else if (event.type == SDL_FINGERUP) { mouse_data.btn1 = 0; - if (event.button.button == SDL_BUTTON_RIGHT) - mouse_data.btn2 = 0; - if (event.button.button == SDL_BUTTON_MIDDLE) - mouse_data.btn3 = 0; - if (event.button.button == SDL_BUTTON_X1) - mouse_data.btn4 = 0; - break; - - // Touch events (map to mouse_data as left-click equivalent) - case SDL_FINGERMOTION: - case SDL_FINGERDOWN: - case SDL_FINGERUP: { - - float x = event.tfinger.x * 640; - float y = event.tfinger.y * 480; - - mouse_data.x = (int)x; - mouse_data.y = (int)y; - - // Only treat the first finger as mouse input (ignore multi-touch - // beyond 1 finger) - if (event.tfinger.fingerId == 0) { - if (event.type == SDL_FINGERDOWN || - event.type == SDL_FINGERMOTION) { - mouse_data.btn1 = 1; - } else if (event.type == SDL_FINGERUP) { - mouse_data.btn1 = 0; - } } - break; - } } + break; } - - // Run VM for a fixed number of cycles or a time slice - int cycles_this_frame = 0; - int max_cycles_per_frame = 100; // Adjust this value - while (cycles_this_frame < max_cycles_per_frame) { - #ifdef ASM_DEBUG - printf("| %s %d\n", opcode_to_string(vm.code[vm.pc]),vm.pc); - #endif - if (!step_vm(&vm)) { - running = false; - break; - } - cycles_this_frame++; - } - - // Render only if the screen buffer was updated AND at a reasonable rate - if (screen_data.update) { - if (screen_data.renderer && screen_data.texture) { - // Clear and render - SDL_RenderClear(screen_data.renderer); - - SDL_Rect output_rect; - SDL_RenderGetViewport(screen_data.renderer, &output_rect); - - // Calculate aspect ratio preserving scaling - float scale_x = (float)output_rect.w / screen_data.width; - float scale_y = (float)output_rect.h / screen_data.height; - float scale = SDL_min(scale_x, scale_y); - - SDL_Rect dstrect = { - (i32)((output_rect.w - screen_data.width * scale) / 2), - (i32)((output_rect.h - screen_data.height * scale) / 2), - (i32)(screen_data.width * scale), - (i32)(screen_data.height * scale)}; - - SDL_RenderCopy(screen_data.renderer, screen_data.texture, NULL, - &dstrect); - SDL_RenderPresent(screen_data.renderer); - } - screen_data.update = false; // Reset flag after rendering } } - } else { - bool running = true; - while (running) { - running = step_vm(&vm); + + // Run VM for a fixed number of cycles or a time slice + int cycles_this_frame = 0; + int max_cycles_per_frame = 100; // Adjust this value + while (cycles_this_frame < max_cycles_per_frame) { +#ifdef ASM_DEBUG + printf("| %s %d\n", opcode_to_string(vm.code[vm.pc]), vm.pc); +#endif + if (!step_vm(&vm)) { + running = false; + break; + } + cycles_this_frame++; + } + + // Render only if the screen buffer was updated AND at a reasonable rate + if (screen_data.update) { + if (screen_data.renderer && screen_data.texture) { + // Clear and render + SDL_RenderClear(screen_data.renderer); + + SDL_Rect output_rect; + SDL_RenderGetViewport(screen_data.renderer, &output_rect); + + // Calculate aspect ratio preserving scaling + float scale_x = (float)output_rect.w / screen_data.width; + float scale_y = (float)output_rect.h / screen_data.height; + float scale = SDL_min(scale_x, scale_y); + + SDL_Rect dstrect = { + (i32)((output_rect.w - screen_data.width * scale) / 2), + (i32)((output_rect.h - screen_data.height * scale) / 2), + (i32)(screen_data.width * scale), + (i32)(screen_data.height * scale)}; + + SDL_RenderCopy(screen_data.renderer, screen_data.texture, NULL, + &dstrect); + SDL_RenderPresent(screen_data.renderer); + } + screen_data.update = false; // Reset flag after rendering } } - return EXIT_SUCCESS; + return vm.flag; } diff --git a/src/tools/assembler.c b/src/tools/assembler.c index e528283..49b6be4 100644 --- a/src/tools/assembler.c +++ b/src/tools/assembler.c @@ -66,17 +66,18 @@ u32 find_label_in_table(SymbolTable *table, const char *name) { int get_instruction_byte_size(ExprNode *node) { const char *opname = node->token; - // Simple opcodes (1 byte) - if (strcmp(opname, "halt") == 0) { - return 1; - } - // Return (1 + 1) if (strcmp(opname, "return") == 0) { return 2; // 1 byte opcode + 1 byte return register } - if (strcmp(opname, "int-to-string") == 0 || + if (strcmp(opname, "neg-int") == 0 || + strcmp(opname, "abs-int") == 0 || + strcmp(opname, "neg-nat") == 0 || + strcmp(opname, "abs-nat") == 0 || + strcmp(opname, "neg-real") == 0 || + strcmp(opname, "abs-real") == 0 || + strcmp(opname, "int-to-string") == 0 || strcmp(opname, "load-indirect-8") == 0 || strcmp(opname, "nat-to-string") == 0 || strcmp(opname, "load-indirect-16") == 0 || @@ -108,6 +109,7 @@ int get_instruction_byte_size(ExprNode *node) { strcmp(opname, "add-real") == 0 || strcmp(opname, "sub-real") == 0 || strcmp(opname, "bit-shift-left") == 0 || strcmp(opname, "bit-shift-right") == 0 || + strcmp(opname, "bit-shift-r-ext") == 0 || strcmp(opname, "bit-and") == 0 || strcmp(opname, "bit-or") == 0 || strcmp(opname, "bit-xor") == 0 || strcmp(opname, "mul-real") == 0 || strcmp(opname, "div-real") == 0) { @@ -115,7 +117,8 @@ int get_instruction_byte_size(ExprNode *node) { } // (5 bytes: 1 + 4) - if (strcmp(opname, "jump-if-flag") == 0 || strcmp(opname, "jump") == 0) { + if (strcmp(opname, "halt") == 0 || strcmp(opname, "jump-if-flag") == 0 || + strcmp(opname, "jump") == 0) { return 5; } @@ -387,13 +390,14 @@ void process_data_block(VM *vm, SymbolTable *table, ExprNode *block) { // Case 1: String literal (enclosed in quotes) if (token[0] == '"' && token[strlen(token) - 1] == '"') { char *unwrapped = unwrap_string(token); - int len = strlen(unwrapped) + 1; - u32 addr = allocate_data(vm, table, name, len + 4); + int len = strlen(unwrapped); + u32 addr = allocate_data(vm, table, name, len + 1 + 4); write_u32(vm, memory, addr, len); for (int i = 0; i < len; i++) { write_u8(vm, memory, addr + 4 + i, unwrapped[i]); } + write_u8(vm, memory, addr + 4 + len, '\0'); free(unwrapped); } // Case 2: Hexadecimal integer (0x...) @@ -427,7 +431,7 @@ void process_data_block(VM *vm, SymbolTable *table, ExprNode *block) { u32 addr = allocate_data(vm, table, name, 4); write_u32(vm, memory, addr, value); - vm->mp += 4; + //vm->mp += 4; } } else { fprintf(stderr, "Unsupported data item\n"); @@ -445,6 +449,8 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) { } } else if (strcmp(opname, "halt") == 0) { emit_opcode(vm, OP_HALT); + u32 addr = resolve_symbol(table, node->children[0]->token); + emit_u32(vm, addr); } else if (strcmp(opname, "jump") == 0) { emit_opcode(vm, OP_JMP); u32 addr = resolve_symbol(table, node->children[0]->token); @@ -732,7 +738,7 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) { emit_byte(vm, reg); } } else if (strcmp(opname, "bit-shift-left") == 0) { - emit_opcode(vm, OP_SLL); + emit_opcode(vm, OP_BIT_SHIFT_LEFT); int dest = parse_register(node->children[0]->token); int src1 = parse_register(node->children[1]->token); int src2 = parse_register(node->children[2]->token); @@ -740,15 +746,15 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) { emit_byte(vm, src1); emit_byte(vm, src2); } else if (strcmp(opname, "bit-shift-right") == 0) { - emit_opcode(vm, OP_SRL); + emit_opcode(vm, OP_BIT_SHIFT_RIGHT); int dest = parse_register(node->children[0]->token); int src1 = parse_register(node->children[1]->token); int src2 = parse_register(node->children[2]->token); emit_byte(vm, dest); emit_byte(vm, src1); emit_byte(vm, src2); - } else if (strcmp(opname, "bit-shift-re") == 0) { - emit_opcode(vm, OP_SRE); + } else if (strcmp(opname, "bit-shift-r-ext") == 0) { + emit_opcode(vm, OP_BIT_SHIFT_R_EXT); int dest = parse_register(node->children[0]->token); int src1 = parse_register(node->children[1]->token); int src2 = parse_register(node->children[2]->token); @@ -811,6 +817,18 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) { emit_byte(vm, dest); emit_byte(vm, src1); emit_byte(vm, src2); + } else if (strcmp(opname, "abs-int") == 0) { + emit_opcode(vm, OP_ABS_INT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + } else if (strcmp(opname, "neg-int") == 0) { + emit_opcode(vm, OP_NEG_INT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); } else if (strcmp(opname, "add-nat") == 0) { emit_opcode(vm, OP_ADD_NAT); int dest = parse_register(node->children[0]->token); @@ -843,6 +861,18 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) { emit_byte(vm, dest); emit_byte(vm, src1); emit_byte(vm, src2); + } else if (strcmp(opname, "abs-nat") == 0) { + emit_opcode(vm, OP_ABS_INT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + } else if (strcmp(opname, "neg-nat") == 0) { + emit_opcode(vm, OP_NEG_INT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); } else if (strcmp(opname, "add-real") == 0) { emit_opcode(vm, OP_ADD_REAL); int dest = parse_register(node->children[0]->token); @@ -875,6 +905,18 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) { emit_byte(vm, dest); emit_byte(vm, src1); emit_byte(vm, src2); + } else if (strcmp(opname, "abs-real") == 0) { + emit_opcode(vm, OP_ABS_INT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + } else if (strcmp(opname, "neg-real") == 0) { + emit_opcode(vm, OP_NEG_INT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); } else if (strcmp(opname, "int-to-real") == 0) { emit_opcode(vm, OP_INT_TO_REAL); int dest = parse_register(node->children[0]->token); diff --git a/src/tools/lexer.c b/src/tools/lexer.c index 2831f64..82c88fc 100644 --- a/src/tools/lexer.c +++ b/src/tools/lexer.c @@ -89,6 +89,7 @@ static void skipWhitespace() { advance(); advance(); while (!isAtEnd()) { + if (peek() == '\n') lexer.line++; if (peek() == '*' && peekNext() == '/') { advance(); advance(); @@ -120,6 +121,16 @@ static TokenType identifierType() { switch (lexer.start[0]) { case 'a': return checkKeyword(1, 2, "nd", TOKEN_OPERATOR_AND); + case 'c': + if (lexer.current - lexer.start > 1) { + switch (lexer.start[1]) { + case 'l': + return checkKeyword(2, 3, "ose", TOKEN_KEYWORD_CLOSE); + case 'o': + return checkKeyword(2, 3, "nst", TOKEN_KEYWORD_CONST); + } + } + break; case 'e': return checkKeyword(1, 3, "lse", TOKEN_KEYWORD_ELSE); case 'f': @@ -134,23 +145,77 @@ static TokenType identifierType() { } break; case 'i': - return checkKeyword(1, 1, "f", TOKEN_KEYWORD_IF); + if (lexer.current - lexer.start > 1) { + switch (lexer.start[1]) { + case 'f': + return checkKeyword(2, 0, "", TOKEN_KEYWORD_IF); + case 'n': + if (lexer.current - lexer.start > 2) { + switch (lexer.start[2]) { + case 'i': + return checkKeyword(3, 2, "t", TOKEN_KEYWORD_INIT); + case 't': + return checkKeyword(3, 1, "", TOKEN_TYPE_INT); + } + } + break; + } + } + break; case 'n': - return checkKeyword(1, 2, "il", TOKEN_KEYWORD_NIL); + if (lexer.current - lexer.start > 1) { + switch (lexer.start[1]) { + case 'a': + return checkKeyword(2, 1, "t", TOKEN_TYPE_NAT); + case 'i': + return checkKeyword(2, 1, "l", TOKEN_KEYWORD_NIL); + } + } + break; case 'o': - return checkKeyword(1, 1, "r", TOKEN_OPERATOR_OR); + if (lexer.current - lexer.start > 1) { + switch (lexer.start[1]) { + case 'p': + return checkKeyword(2, 2, "en", TOKEN_KEYWORD_OPEN); + case 'r': + return checkKeyword(2, 0, "", TOKEN_OPERATOR_OR); + } + } + break; case 'p': if (lexer.current - lexer.start > 1) { switch (lexer.start[1]) { case 'l': return checkKeyword(2, 2, "ex", TOKEN_KEYWORD_PLEX); - case 'r': - return checkKeyword(2, 3, "int", TOKEN_KEYWORD_PRINT); } } break; case 'r': - return checkKeyword(1, 5, "eturn", TOKEN_KEYWORD_RETURN); + if (lexer.current - lexer.start > 1) { + switch (lexer.start[1]) { + case 'e': + if (lexer.current - lexer.start > 2) { + switch (lexer.start[2]) { + case 'a': + return checkKeyword(3, 1, "d", TOKEN_KEYWORD_READ); + case 'f': + return checkKeyword(3, 4, "resh", TOKEN_KEYWORD_REFRESH); + case 't': + return checkKeyword(3, 3, "urn", TOKEN_KEYWORD_RETURN); + } + } + break; + } + } + break; + case 's': + if (lexer.current - lexer.start > 1) { + switch (lexer.start[1]) { + case 't': + return checkKeyword(2, 1, "r", TOKEN_TYPE_STR); + } + } + break; case 't': if (lexer.current - lexer.start > 1) { switch (lexer.start[1]) { @@ -161,10 +226,24 @@ static TokenType identifierType() { } } break; - case 'l': - return checkKeyword(1, 2, "et", TOKEN_KEYWORD_LET); + case 'u': + if (lexer.current - lexer.start > 1) { + switch (lexer.start[1]) { + case 's': + return checkKeyword(2, 1, "e", TOKEN_KEYWORD_USE); + } + } + break; case 'w': - return checkKeyword(1, 4, "hile", TOKEN_KEYWORD_WHILE); + if (lexer.current - lexer.start > 1) { + switch (lexer.start[1]) { + case 'h': + return checkKeyword(2, 3, "ile", TOKEN_KEYWORD_WHILE); + case 'r': + return checkKeyword(2, 3, "ite", TOKEN_KEYWORD_WRITE); + } + } + break; } return TOKEN_IDENTIFIER; @@ -278,7 +357,6 @@ const char* tokenTypeToString(TokenType type) { case TOKEN_TYPE_STR: return "TYPE_STR"; case TOKEN_KEYWORD_PLEX: return "KEYWORD_PLEX"; case TOKEN_KEYWORD_FN: return "KEYWORD_FN"; - case TOKEN_KEYWORD_LET: return "KEYWORD_LET"; case TOKEN_KEYWORD_CONST: return "KEYWORD_CONST"; case TOKEN_KEYWORD_IF: return "KEYWORD_IF"; case TOKEN_KEYWORD_ELSE: return "KEYWORD_ELSE"; @@ -288,7 +366,11 @@ const char* tokenTypeToString(TokenType type) { case TOKEN_KEYWORD_USE: return "KEYWORD_USE"; case TOKEN_KEYWORD_INIT: return "KEYWORD_INIT"; case TOKEN_KEYWORD_THIS: return "KEYWORD_THIS"; - case TOKEN_KEYWORD_PRINT: return "KEYWORD_PRINT"; + case TOKEN_KEYWORD_OPEN: return "TOKEN_KEYWORD_OPEN"; + case TOKEN_KEYWORD_READ: return "TOKEN_KEYWORD_READ"; + case TOKEN_KEYWORD_WRITE: return "TOKEN_KEYWORD_WRITE"; + case TOKEN_KEYWORD_REFRESH: return "TOKEN_KEYWORD_REFRESH"; + case TOKEN_KEYWORD_CLOSE: return "TOKEN_KEYWORD_CLOSE"; case TOKEN_KEYWORD_NIL: return "KEYWORD_NIL"; case TOKEN_KEYWORD_TRUE: return "KEYWORD_TRUE"; case TOKEN_KEYWORD_FALSE: return "KEYWORD_FALSE"; diff --git a/src/tools/lexer.h b/src/tools/lexer.h index 7dbae73..086cc31 100644 --- a/src/tools/lexer.h +++ b/src/tools/lexer.h @@ -14,7 +14,6 @@ typedef enum { TOKEN_TYPE_STR, TOKEN_KEYWORD_PLEX, TOKEN_KEYWORD_FN, - TOKEN_KEYWORD_LET, TOKEN_KEYWORD_CONST, TOKEN_KEYWORD_IF, TOKEN_KEYWORD_ELSE, @@ -24,7 +23,11 @@ typedef enum { TOKEN_KEYWORD_USE, TOKEN_KEYWORD_INIT, TOKEN_KEYWORD_THIS, - TOKEN_KEYWORD_PRINT, + TOKEN_KEYWORD_OPEN, + TOKEN_KEYWORD_READ, + TOKEN_KEYWORD_WRITE, + TOKEN_KEYWORD_REFRESH, + TOKEN_KEYWORD_CLOSE, TOKEN_KEYWORD_NIL, TOKEN_KEYWORD_TRUE, TOKEN_KEYWORD_FALSE, diff --git a/src/tools/parser.c b/src/tools/parser.c index a17c03d..69610d9 100644 --- a/src/tools/parser.c +++ b/src/tools/parser.c @@ -6,19 +6,9 @@ #include #include -// Helper function to allocate memory and handle errors -void *safe_malloc(size_t size) { - void *ptr = malloc(size); - if (!ptr) { - fprintf(stderr, "Memory allocation failed\n"); - exit(1); - } - return ptr; -} - // Helper function to create a new node static ExprNode *expr_node_create(const char *token, int line) { - ExprNode *node = (ExprNode *)safe_malloc(sizeof(ExprNode)); + ExprNode *node = (ExprNode *)malloc(sizeof(ExprNode)); node->token = strdup(token ? token : ""); node->children = NULL; node->child_count = 0; @@ -96,7 +86,7 @@ static char *parse_token(const char **ptr, int line) { } size_t len = end - start; - char *token = (char *)safe_malloc(len + 1); + char *token = (char *)malloc(len + 1); memcpy(token, start, len); token[len] = '\0'; @@ -113,7 +103,7 @@ static ExprNode *parse_list(const char **ptr, int line) { if (**ptr == ')') { // Empty list (*ptr)++; - return expr_node_create("nil", line); + return expr_node_create("\0", line); } // Parse all children first @@ -125,7 +115,7 @@ static ExprNode *parse_list(const char **ptr, int line) { if (child) { // Resize temp children array ExprNode **new_temp = - (ExprNode **)safe_malloc(sizeof(ExprNode *) * (temp_count + 1)); + (ExprNode **)malloc(sizeof(ExprNode *) * (temp_count + 1)); // Copy existing children for (size_t i = 0; i < temp_count; i++) { @@ -159,7 +149,7 @@ static ExprNode *parse_list(const char **ptr, int line) { node->child_count = temp_count - 1; if (node->child_count > 0) { node->children = - (ExprNode **)safe_malloc(sizeof(ExprNode *) * node->child_count); + (ExprNode **)malloc(sizeof(ExprNode *) * node->child_count); for (size_t i = 0; i < node->child_count; i++) { node->children[i] = temp_children[i + 1]; } diff --git a/src/vm/common.h b/src/vm/common.h index 14750d3..4691709 100644 --- a/src/vm/common.h +++ b/src/vm/common.h @@ -1,5 +1,5 @@ -#ifndef ZRE_COMMON_H -#define ZRE_COMMON_H +#ifndef UNDAR_COMMON_H +#define UNDAR_COMMON_H #include #include diff --git a/src/vm/device.c b/src/vm/device.c index ec022d4..ff2cb7d 100644 --- a/src/vm/device.c +++ b/src/vm/device.c @@ -1,5 +1,5 @@ #include "device.h" -#include "str.h" +#include "libc.h" i32 vm_register_device(VM *vm, const char *path, const char *type, void *data, DeviceOps *ops, u32 size) { @@ -33,26 +33,3 @@ Device *find_device_by_path(VM *vm, const char *path) { } return NULL; } - -/* Find device by type (useful for checking capabilities) */ -Device *find_device_by_type(VM *vm, const char *type) { - u32 i; - for (i = 0; i < vm->dc; i++) { - if (streq(vm->devices[i].type, type)) { - return &vm->devices[i]; - } - } - return NULL; -} - -/* Find all devices of a type */ -i32 find_devices_by_type(VM *vm, const char *type, Device **results, - u32 max_results) { - u32 i, count = 0; - for (i = 0; i < vm->dc && count < max_results; i++) { - if (streq(vm->devices[i].type, type)) { - results[count++] = &vm->devices[i]; - } - } - return count; -} diff --git a/src/vm/device.h b/src/vm/device.h index 00d9735..795bba8 100644 --- a/src/vm/device.h +++ b/src/vm/device.h @@ -1,11 +1,9 @@ -#ifndef ZRE_DEVICE_H -#define ZRE_DEVICE_H +#ifndef UNDAR_DEVICE_H +#define UNDAR_DEVICE_H #include "opcodes.h" i32 vm_register_device(VM *vm, const char *path, const char *type, void *data, DeviceOps *ops, u32 size); Device* find_device_by_path(VM *vm, const char *path); -Device* find_device_by_type(VM *vm, const char *type); -i32 find_devices_by_type(VM *vm, const char *type, Device **results, uint32_t max_results); #endif diff --git a/src/vm/str.c b/src/vm/libc.c similarity index 99% rename from src/vm/str.c rename to src/vm/libc.c index a8e62f6..05dcf3f 100644 --- a/src/vm/str.c +++ b/src/vm/libc.c @@ -1,4 +1,4 @@ -#include "str.h" +#include "libc.h" void memcopy(u8 *dest, const u8 *src, u32 n) { size_t i; diff --git a/src/vm/str.h b/src/vm/libc.h similarity index 90% rename from src/vm/str.h rename to src/vm/libc.h index 3724993..f9ffc45 100644 --- a/src/vm/str.h +++ b/src/vm/libc.h @@ -1,5 +1,5 @@ -#ifndef ZRE_STR_H -#define ZRE_STR_H +#ifndef UNDAR_STR_H +#define UNDAR_STR_H #include "common.h" diff --git a/src/vm/opcodes.h b/src/vm/opcodes.h index e3c038b..979c612 100644 --- a/src/vm/opcodes.h +++ b/src/vm/opcodes.h @@ -1,5 +1,5 @@ -#ifndef ZRE_OPCODES_H -#define ZRE_OPCODES_H +#ifndef UNDAR_OPCODES_H +#define UNDAR_OPCODES_H #include "common.h" @@ -31,49 +31,55 @@ typedef enum { OP_MEMSET_8, /* memset-8 : dest <-> dest+count = src1 as u8 */ OP_MEMSET_16, /* memset-16 : dest <-> dest+count = src1 as u8 */ OP_MEMSET_32, /* memset-32 : dest <-> dest+count = src1 as u32 */ - OP_REG_MOV, /* register-move : dest = src1 */ + OP_REG_MOV, /* register-move : registers[dest] = registers[src1] */ OP_ADD_INT, /* add-int : registers[dest] = registers[src1] + registers[src2] */ OP_SUB_INT, /* sub-int : registers[dest] = registers[src1] - registers[src2] */ OP_MUL_INT, /* mul-int : registers[dest] = registers[src1] * registers[src2] */ OP_DIV_INT, /* div-int : registers[dest] = registers[src1] / registers[src2] */ + OP_ABS_INT, /* abs-int : registers[dest] = | registers[src1] | */ + OP_NEG_INT, /* neg-int : registers[dest] = -registers[src1] */ OP_ADD_NAT, /* add-nat : registers[dest] = registers[src1] + registers[src2] */ OP_SUB_NAT, /* sub-nat : registers[dest] = registers[src1] - registers[src2] */ OP_MUL_NAT, /* mul-nat : registers[dest] = registers[src1] * registers[src2] */ OP_DIV_NAT, /* div-nat : registers[dest] = registers[src1] / registers[src2] */ + OP_ABS_NAT, /* abs-nat : registers[dest] = | registers[src1] | */ + OP_NEG_NAT, /* neg-nat : registers[dest] = -registers[src1] */ OP_ADD_REAL, /* add-real : registers[dest] = registers[src1] + registers[src2] */ OP_SUB_REAL, /* sub-real : registers[dest] = registers[src1] - registers[src2] */ OP_MUL_REAL, /* mul-real : registers[dest] = registers[src1] * registers[src2] */ OP_DIV_REAL, /* div-real : registers[dest] = registers[src1] / registers[src2] */ + OP_ABS_REAL, /* abs-real : registers[dest] = | registers[src1] | */ + OP_NEG_REAL, /* neg-real : registers[dest] = -registers[src1] */ OP_INT_TO_REAL, /* int-to-real : registers[dest] = registers[src1] as real */ OP_NAT_TO_REAL, /* nat-to-real : registers[dest] = registers[src1] as real */ OP_REAL_TO_INT, /* real-to-int : registers[dest] = registers[src1] as int */ OP_REAL_TO_NAT, /* real-to-nat : registers[dest] = registers[src1] as nat */ - OP_SLL, /* bit-shift-left : registers[dest] = registers[src1] << registers[src2] */ - OP_SRL, /* bit-shift-right : registers[dest] = registers[src1] >> registers[src2] */ - OP_SRE, /* bit-shift-re : registers[dest] as i32 = registers[src1] >> registers[src2] */ + OP_BIT_SHIFT_LEFT, /* bit-shift-left : registers[dest] = registers[src1] << registers[src2] */ + OP_BIT_SHIFT_RIGHT,/* bit-shift-right : registers[dest] = registers[src1] >> registers[src2] */ + OP_BIT_SHIFT_R_EXT,/* bit-shift-r-ext : registers[dest] as i32 = registers[src1] >> registers[src2] */ OP_BAND, /* bit-and : registers[dest] = registers[src1] & registers[src2] */ OP_BOR, /* bit-or : registers[dest] = registers[src1] | registers[src2] */ OP_BXOR, /* bit-xor : registers[dest] = registers[src1] ^ registers[src2] */ - OP_JMP, /* jump : jump to address dest unconditionally */ - OP_JMPF, /* jump-if-flag : jump to address dest if flag is ne 0 */ - OP_JEQ_INT, /* jump-eq-int : jump to address dest if registers[src1] as int == registers[src2] as int */ - OP_JNEQ_INT, /* jump-neq-int : jump to address dest if registers[src1] as int != registers[src2] as int */ - OP_JGT_INT, /* jump-gt-int : jump to address dest if registers[src1] as int > registers[src2] as int */ - OP_JLT_INT, /* jump-lt-int : jump to address dest if registers[src1] as int < registers[src2] as int */ - OP_JLE_INT, /* jump-le-int : jump to address dest if registers[src1] as int <= registers[src2] as int */ - OP_JGE_INT, /* jump-ge-int : jump to address dest if registers[src1] as int >= registers[src2] as int */ - OP_JEQ_NAT, /* jump-eq-nat : jump to address dest if registers[src1] as nat == registers[src2] as nat */ - OP_JNEQ_NAT, /* jump-neq-nat : jump to address dest if registers[src1] as nat != registers[src2] as nat */ - OP_JGT_NAT, /* jump-gt-nat : jump to address dest if registers[src1] as nat > registers[src2] as nat */ - OP_JLT_NAT, /* jump-lt-nat : jump to address dest if registers[src1] as nat < registers[src2] as nat */ - OP_JLE_NAT, /* jump-le-nat : jump to address dest if registers[src1] as nat <= registers[src2] as nat */ - OP_JGE_NAT, /* jump-ge-nat : jump to address dest if registers[src1] as nat >= registers[src2] as nat */ - OP_JEQ_REAL, /* jump-eq-real : jump to address dest if registers[src1] as real == registers[src2] as real */ - OP_JNEQ_REAL, /* jump-neq-real : jump to address dest if registers[src1] as real != registers[src2] as real */ - OP_JGE_REAL, /* jump-ge-real : jump to address dest if registers[src1] as real >= registers[src2] as real */ - OP_JGT_REAL, /* jump-gt-real : jump to address dest if registers[src1] as real > registers[src2] as real */ - OP_JLT_REAL, /* jump-lt-real : jump to address dest if registers[src1] as real < registers[src2] as real */ - OP_JLE_REAL, /* jump-le-real : jump to address dest if registers[src1] as real <= registers[src2] as real */ + OP_JMP, /* jump : jump to &dest unconditionally */ + OP_JMPF, /* jump-if-flag : jump to &dest if flag != 0 */ + OP_JEQ_INT, /* jump-eq-int : jump to &dest if registers[src1] as int == registers[src2] as int */ + OP_JNEQ_INT, /* jump-neq-int : jump to &dest if registers[src1] as int != registers[src2] as int */ + OP_JGT_INT, /* jump-gt-int : jump to &dest if registers[src1] as int > registers[src2] as int */ + OP_JLT_INT, /* jump-lt-int : jump to &dest if registers[src1] as int < registers[src2] as int */ + OP_JLE_INT, /* jump-le-int : jump to &dest if registers[src1] as int <= registers[src2] as int */ + OP_JGE_INT, /* jump-ge-int : jump to &dest if registers[src1] as int >= registers[src2] as int */ + OP_JEQ_NAT, /* jump-eq-nat : jump to &dest if registers[src1] as nat == registers[src2] as nat */ + OP_JNEQ_NAT, /* jump-neq-nat : jump to &dest if registers[src1] as nat != registers[src2] as nat */ + OP_JGT_NAT, /* jump-gt-nat : jump to &dest if registers[src1] as nat > registers[src2] as nat */ + OP_JLT_NAT, /* jump-lt-nat : jump to &dest if registers[src1] as nat < registers[src2] as nat */ + OP_JLE_NAT, /* jump-le-nat : jump to &dest if registers[src1] as nat <= registers[src2] as nat */ + OP_JGE_NAT, /* jump-ge-nat : jump to &dest if registers[src1] as nat >= registers[src2] as nat */ + OP_JEQ_REAL, /* jump-eq-real : jump to &dest if registers[src1] as real == registers[src2] as real */ + OP_JNEQ_REAL, /* jump-neq-real : jump to &dest if registers[src1] as real != registers[src2] as real */ + OP_JGE_REAL, /* jump-ge-real : jump to &dest if registers[src1] as real >= registers[src2] as real */ + OP_JGT_REAL, /* jump-gt-real : jump to &dest if registers[src1] as real > registers[src2] as real */ + OP_JLT_REAL, /* jump-lt-real : jump to &dest if registers[src1] as real < registers[src2] as real */ + OP_JLE_REAL, /* jump-le-real : jump to &dest if registers[src1] as real <= registers[src2] as real */ OP_STRLEN, /* string-length : registers[dest] = length of str at src1 ptr */ OP_STREQ, /* string-eq : registers[dest] = src1 ptr string == src2 ptr string */ OP_STRCAT, /* string-concat : registers[dest] = ptr of src1 ptr string + src2 ptr string */ diff --git a/src/vm/vm.c b/src/vm/vm.c index a511262..84bf11f 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -1,7 +1,7 @@ #include "vm.h" #include "device.h" #include "opcodes.h" -#include "str.h" +#include "libc.h" #define COMPARE_AND_JUMP(type, op) \ do { \ @@ -93,6 +93,7 @@ bool step_vm(VM *vm) { switch (opcode) { case OP_HALT: { + vm->flag = read_u32(vm, code, vm->pc); return false; } case OP_CALL: { @@ -721,11 +722,11 @@ bool step_vm(VM *vm) { } return true; } - case OP_SLL: + case OP_BIT_SHIFT_LEFT: BIT_OP(<<); - case OP_SRL: + case OP_BIT_SHIFT_RIGHT: BIT_OP(>>); - case OP_SRE: + case OP_BIT_SHIFT_R_EXT: MATH_OP(i32, >>); case OP_BAND: BIT_OP(&); @@ -741,6 +742,30 @@ bool step_vm(VM *vm) { MATH_OP(i32, *); case OP_DIV_INT: MATH_OP(i32, /); + case OP_ABS_INT: { + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + + value = frame->registers[src1]; + if (value < 0) { + value = -value; + } + + frame->registers[dest] = value; + return true; + } + case OP_NEG_INT: { + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + + value = frame->registers[src1]; + frame->registers[dest] = -value; + return true; + } case OP_ADD_NAT: MATH_OP(u32, +); case OP_SUB_NAT: @@ -901,6 +926,7 @@ bool step_vm(VM *vm) { int_to_string(AS_INT(frame->registers[src1]), buffer); ptr = str_alloc(vm, frame, buffer, strlength(buffer)); frame->registers[dest] = ptr; + set_heap_status(vm, dest, true); /* Mark as heap pointer */ return true; } case OP_NAT_TO_STRING: { @@ -912,6 +938,7 @@ bool step_vm(VM *vm) { nat_to_string(frame->registers[src1], buffer); ptr = str_alloc(vm, frame, buffer, strlength(buffer)); frame->registers[dest] = ptr; + set_heap_status(vm, dest, true); /* Mark as heap pointer */ return true; } case OP_REAL_TO_STRING: { @@ -924,6 +951,7 @@ bool step_vm(VM *vm) { ptr = str_alloc(vm, frame, buffer, strlength(buffer)); /* copy buffer to dest */ frame->registers[dest] = ptr; + set_heap_status(vm, dest, true); /* Mark as heap pointer */ return true; } case OP_STRLEN: { diff --git a/src/vm/vm.h b/src/vm/vm.h index 2898ed0..1f0cff1 100644 --- a/src/vm/vm.h +++ b/src/vm/vm.h @@ -1,12 +1,9 @@ -#ifndef ZRE_VM_H -#define ZRE_VM_H +#ifndef UNDAR_VM_H +#define UNDAR_VM_H #include "opcodes.h" bool step_vm(VM *vm); u32 str_alloc(VM *vm, Frame *frame, const char *str, u32 length); -void fixed_to_string(i32 value, char *buffer); -void int_to_string(i32 value, char *buffer); -void nat_to_string(u32 value, char *buffer); #endif diff --git a/test/add.asm.lisp b/test/add.asm.lisp index e8a0263..488709f 100644 --- a/test/add.asm.lisp +++ b/test/add.asm.lisp @@ -5,7 +5,7 @@ (call &add ($0 $1) $2) (int-to-string $3 $2) (call &pln ($3) nil) - (halt)) + (halt 0)) (label add (add-int $2 $1 $0) @@ -14,10 +14,10 @@ (label pln (load-immediate $1 &terminal-namespace) ; get terminal device (load-immediate $11 0) - (syscall OPEN $1 $1 $11) - (load-immediate $3 &new-line) + (syscall OPEN $1 $1 $11) (string-length $2 $0) - (syscall WRITE $1 $0 $2) + (syscall WRITE $1 $0 $2) + (load-immediate $3 &new-line) (string-length $4 $3) (syscall WRITE $1 $3 $4) (return nil))) diff --git a/test/fib.asm.lisp b/test/fib.asm.lisp index e8f2333..3e18589 100644 --- a/test/fib.asm.lisp +++ b/test/fib.asm.lisp @@ -4,7 +4,7 @@ (call &fib ($0) $0) (int-to-string $1 $0) (call &pln ($1) nil) - (halt)) + (halt 0)) (label fib (load-immediate $1 2) (jump-lt-int &base-case $0 $1) diff --git a/test/hello.asm.lisp b/test/hello.asm.lisp index f410cc5..d5e2a58 100644 --- a/test/hello.asm.lisp +++ b/test/hello.asm.lisp @@ -2,7 +2,7 @@ (label main (load-immediate $1 &hello-str) ; load hello string ptr (call &pln ($1) nil) - (halt)) ; done + (halt 0)) ; done (label pln (load-immediate $1 &terminal-namespace) ; get terminal device (load-immediate $11 0) diff --git a/test/loop.asm.lisp b/test/loop.asm.lisp index f297802..6be6c73 100644 --- a/test/loop.asm.lisp +++ b/test/loop.asm.lisp @@ -27,7 +27,7 @@ (call &pln ($4) nil) (real-to-string $3 $0) (call &pln ($3) nil) - (halt)) + (halt 0)) (label pln (load-immediate $1 &terminal-namespace) ; get terminal device (load-immediate $11 0) diff --git a/test/loop.ul b/test/loop.ul index 8c75fb8..28591b0 100644 --- a/test/loop.ul +++ b/test/loop.ul @@ -18,7 +18,7 @@ function main() { } nat b = a as nat; pln(term, "Enter a string:"); - str user_string = read(term, 32); + str user_string = term.read(32); pln(term, a.str); pln(term, b.str); pln(term, user_string); diff --git a/test/malloc.asm.lisp b/test/malloc.asm.lisp index 1ba7907..382e36a 100644 --- a/test/malloc.asm.lisp +++ b/test/malloc.asm.lisp @@ -12,7 +12,7 @@ (syscall READ $0 $4 $1) ; read the string (call &pln ($0 $4) nil) ; print the string - (halt)) + (halt 0)) (label pln (load-immediate $3 &new-line) (string-length $2 $1) diff --git a/test/paint-bw.asm.lisp b/test/paint-bw.asm.lisp index 92b5785..d927e30 100644 --- a/test/paint-bw.asm.lisp +++ b/test/paint-bw.asm.lisp @@ -67,7 +67,7 @@ (jump &draw-loop)) ; Flush and halt - (halt)) + (halt 0)) (label set-color-if-clicked ; (click_x, click_y, box_x, box_y, color, box_size) diff --git a/test/paint-bw.ul b/test/paint-bw.ul index cfe6c80..9bdec58 100644 --- a/test/paint-bw.ul +++ b/test/paint-bw.ul @@ -17,7 +17,6 @@ plex Screen implements Device { nat handle; nat width; nat height; - nat buffer_size; byte[] buffer; draw() { @@ -50,22 +49,22 @@ function main() { loop { mouse.refresh(); - if (not mouse.left) continue; + if (!mouse.left) continue; - int box_size = 20; - int x = 1; - int y = 1; - byte color = BLACK; - outlined_swatch(screen, color, x, y); - set_color(box_size, x, y, mouse.x, mouse.y, color); + int box_size = 20; + int x = 1; + int y = 1; + byte color = BLACK; + outlined_swatch(screen, color, x, y); + set_color(box_size, x, y, mouse.x, mouse.y, color); - color = WHITE; - x = 21; - outlined_swatch(screen, color, x, y); - set_color(box_size, x, y, mouse.x, mouse.y, color); - screen.draw(); + color = WHITE; + x = 21; + outlined_swatch(screen, color, x, y); + set_color(box_size, x, y, mouse.x, mouse.y, color); + screen.draw(); - rectangle(screen, selected_color, x, y, 5, 5); + rectangle(screen, selected_color, x, y, 5, 5); } exit(0); } diff --git a/test/paint.asm.lisp b/test/paint.asm.lisp index 8e96811..63d3b80 100644 --- a/test/paint.asm.lisp +++ b/test/paint.asm.lisp @@ -154,7 +154,7 @@ (jump &draw-loop)) ; Flush and halt - (halt)) + (halt 0)) (label set-color-if-clicked ; (click_x, click_y, box_x, box_y, color, box_size) diff --git a/test/paint.ul b/test/paint.ul index cfe6c80..9419005 100644 --- a/test/paint.ul +++ b/test/paint.ul @@ -17,12 +17,11 @@ plex Screen implements Device { nat handle; nat width; nat height; - nat buffer_size; byte[] buffer; draw() { unsafe { - write(this, this.buffer, this.buffer_size); + write(this, this.buffer, this.buffer.length); } } } @@ -50,22 +49,22 @@ function main() { loop { mouse.refresh(); - if (not mouse.left) continue; - - int box_size = 20; - int x = 1; - int y = 1; - byte color = BLACK; - outlined_swatch(screen, color, x, y); - set_color(box_size, x, y, mouse.x, mouse.y, color); - - color = WHITE; - x = 21; - outlined_swatch(screen, color, x, y); - set_color(box_size, x, y, mouse.x, mouse.y, color); - screen.draw(); - - rectangle(screen, selected_color, x, y, 5, 5); + if (!mouse.left) continue; + + int box_size = 20; + int x = 1; + int y = 1; + byte color = BLACK; + outlined_swatch(screen, color, x, y); + set_color(box_size, x, y, mouse.x, mouse.y, color); + + color = WHITE; + x = 21; + outlined_swatch(screen, color, x, y); + set_color(box_size, x, y, mouse.x, mouse.y, color); + screen.draw(); + + rectangle(screen, selected_color, x, y, 5, 5); } exit(0); } @@ -105,14 +104,14 @@ function outline_swatch(Device screen, byte color, int x, int y) { * Draw a rectangle */ function rectangle(Device screen, byte color, int x, int y, int width, int height) { - // we need unsafe because we are using pointers `&` and `memset` directly + // we need unsafe because we are using pointers `.ptr` and `memset` directly // unsafe takes the guardrails off and allows you to access/modify memory directly unsafe { - int pixel = y * width + x + &screen.buffer + 4; + int base = y * screen.width + x + screen.buffer.ptr + 4; do (int i = height; i > 0; i--) { - int row = pixel + width; + int row = base + width; memset(screen.buffer, row, color, width); - pixel += width; + base += screen.width; } } return; diff --git a/test/simple.asm.lisp b/test/simple.asm.lisp index c0aae82..faa33ff 100644 --- a/test/simple.asm.lisp +++ b/test/simple.asm.lisp @@ -5,7 +5,7 @@ (add-real $2 $1 $0) (real-to-string $3 $2) (call &pln ($3) nil) - (halt)) + (halt 0)) (label pln (load-immediate $1 &terminal-namespace) ; get terminal device (load-immediate $11 0) diff --git a/test/window.asm.lisp b/test/window.asm.lisp index 5246bab..0340856 100644 --- a/test/window.asm.lisp +++ b/test/window.asm.lisp @@ -52,7 +52,7 @@ (syscall WRITE $0 $21 $22) ; redraw (jump &draw-loop)) - (halt)) + (halt 0)) (label pln (load-immediate $1 &terminal-namespace) ; get terminal device (load-immediate $11 0) diff --git a/test/window.ul b/test/window.ul index 7a6fd91..a946203 100644 --- a/test/window.ul +++ b/test/window.ul @@ -15,11 +15,10 @@ plex Screen { nat handle; nat width; nat height; - nat buffer_size; - byte[] screen_buffer; + byte[] buffer; draw() { - write(&this, this.screen_buffer, this.buffer_size); + write(this, this.buffer, this.buffer_size); } } @@ -42,16 +41,20 @@ function main() { pln(screen.handle.str); pln(screen.width.str); pln(screen.size.str); - pln(screen.screen_buffer.ptr.str); + unsafe { + pln(screen.screen_buffer.ptr.str); + } Mouse mouse = open("/dev/mouse/0", 0); screen.draw(); loop { if (mouse.btn1) { - screen.screen_buffer[mouse.y * width + mouse.x + - screen.screen_buffer.ptr + 4] = WHITE; - screen.draw(); + unsafe { + screen.buffer[mouse.y * width + mouse.x + + screen.buffer.ptr + 4] = WHITE; + screen.draw(); + } } } } @@ -60,7 +63,7 @@ function main() { * Print with a newline */ function pln(str message) { - Terminal term(); + Terminal term = open("/dev/term/0", 0); write(term, message, message.length); write(term, nl, nl.length); }