diff --git a/.gitattributes b/.gitattributes index 321ac7a..54386f4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ -*.ul linguist-language=fortran \ No newline at end of file +*.ul linguist-language=fortran +*.zl linguist-language=zig \ No newline at end of file diff --git a/README.org b/README.org index df9a323..39d928f 100644 --- a/README.org +++ b/README.org @@ -1,4 +1,4 @@ -#+TITLE: A Language for Enduring Realities +#+TITLE: The Reality Engine #+AUTHOR: Zongor #+EMAIL: archive@undar-lang.org #+DATE: [2025-04-05] @@ -15,8 +15,6 @@ · · · ᚾ] #+END_SRC -* The Reality Engine - The =Reality Engine= is a register-based virtual machine designed to render not just graphics, but persistent, inspectable, reproducible computational worlds. It is: @@ -55,16 +53,16 @@ Undâr is a permacomputing oriented, statically-typed language with **first-clas It runs on the =Reality Engine=, a minimal C89 VM inspired by Uxn, Plan 9, and Forth - but built for =spatial software=, =deterministic execution=, and =software that lasts=. -Sċieppan is a bytecode assembler that is inspired by Webassemblys WAT format. +Sċieppan is a minimal lisp inpsired by sectorlisp. You can view some examples in the =.lisp= files in =/test= **Core Types** -| Type | Description | -|------+-------------------------------------------| +| Type | Description | +|--------+-------------------------------------------| | =int= | 32-bit signed integer | | =nat= | 32-bit natural number | -| =real= | Q16.16 fixed-point real number | +| =real= | Float/Q16.16 fixed-point real number | | =str= | 4-byte packed string or fat pointer | | =bool= | Compile-time flag | | =ref= | Reference prefix for passing by reference | @@ -105,7 +103,6 @@ A =plex= is a **Platonic form** - a structured definition of a kind of being in #+BEGIN_SRC ul plex Player { - version 1; str name; real[3] pos; @@ -120,36 +117,8 @@ plex Player { - Not a class: no inheritance, no vtables - Methods are functions with implicit =this= argument -- Instances are **atoms** - persistent, versioned, serializable -- Stored in the internal graph - -> *"A plex defines what a thing is. An atom is its instance in that reality."* - -* Versioning & Shadowing (Forth-Inspired) - -When you redefine a =plex=, the old version is **shadowed but preserved** - unless explicitly discarded. - -#+BEGIN_SRC ul -plex Counter { version 1; nat value; inc() { value += 1; } } -plex Counter { version 2; nat value; inc() { value += 2; } } ! shadows v1 - -Counter c1 = Counter(); ! uses v2 (latest) -Counter c2 = Counter.v1(); ! uses v1 - still available - -discard Counter.v1; ! optional: free memory -#+END_SRC - -Internally, plex versions form a **linked version chain**: -- =head= -> latest version -- =tail= -> oldest retained version -- =migrate(obj, Counter)= -> converts data layout -- =versions(Counter)= -> list available versions - -This enables: -- Non-destructive evolution -- Safe refactoring -- Historical reproducibility -- Code archaeology +- Instances are **atoms** +- A plex defines what a thing is. An atom is its instance. * Graphics & Devices @@ -213,23 +182,8 @@ if (server.attach(auth)) { Tunnels make I/O **uniform, composable, and archival**. -* Development Environment - - supports **live coding** and **temporal development**: - **Live Coding Features** -- Hot module reloading: inject code while VM runs - REPL-style interaction: inspect memory, call functions, test logic -- Shadowing: redefine =plex=es without restarting -- Symbol table manipulation: runtime introspection and patching - -**Final Binaries** -- Are **snapshots** of: - - Memory state - - Symbol table - - Version chains -- Can be saved, restored, or archived as =.zbin= files -- Are fully deterministic and reproducible * Getting Started diff --git a/src/opcodes.h b/src/opcodes.h index 028d43c..2915301 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -71,9 +71,6 @@ typedef enum { #define OP(opcode, dest, src1, src2) \ ((opcode << 24) | (dest << 16) | (src1 << 8) | (src2)) -#define OP_SYSCALL_OPCODE(syscall_id, arg_count, src) \ - ((OP_SYSCALL << 24) | ((syscall_id & 0xFF) << 16) | (arg_count & 0xFF) | src) - typedef union value_u { int32_t i; /* Integers */ float f; /* Float */ diff --git a/src/vm.c b/src/vm.c index 49d7f13..25711c4 100644 --- a/src/vm.c +++ b/src/vm.c @@ -189,6 +189,10 @@ bool step_vm(VM *vm) { case OP_GET_PC: { vm->frames[vm->fp].registers[dest].u = vm->pc; return true; + } + case OP_JMP: { + vm->pc = vm->frames[vm->fp].registers[dest].u; /* Jump to address */ + return true; } case OP_SYSCALL: { uint32_t syscall_id = dest; @@ -385,10 +389,6 @@ bool step_vm(VM *vm) { (float)(vm->frames[vm->fp].registers[src1].u); return true; } - case OP_JMP: { - vm->pc = vm->frames[vm->fp].registers[dest].u; /* Jump to address */ - return true; - } case OP_JEQ_UINT: { COMPARE_AND_JUMP(uint32_t, u, ==); } @@ -458,6 +458,28 @@ bool step_vm(VM *vm) { vm->frames[vm->fp].registers[dest].u = ptr; return true; } + case OP_STRING_TO_INT: { + uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u; + uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u; + char *endptr; + int32_t value = (int32_t)strtol((char*)&vm->memory[src_addr], &endptr, 10); + vm->memory[dest_addr].i = value; + return true; + } + case OP_STRING_TO_UINT: { + uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u; + uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u; + long value = atol((char*)&vm->memory[src_addr]); + vm->memory[dest_addr].u = value; + return true; + } + case OP_STRING_TO_REAL: { + uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u; + uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u; + float value = atof((char*)&vm->memory[src_addr]); + vm->memory[dest_addr].u = value; + return true; + } case OP_DBG_READ_STRING: { uint32_t str_addr = vm->mp++; uint32_t length = 0; diff --git a/test/hello.asm b/test/hello.asm index 35d4626..b69d985 100644 --- a/test/hello.asm +++ b/test/hello.asm @@ -1 +1,5 @@ -(puts "nuqneH 'u'?") +hello: + "nuqneH 'u'?" + puts &hello + halt + \ No newline at end of file