fix minor things, add inital opcode, add mem2mem test
This commit is contained in:
parent
f1f84e0fe5
commit
5d15aa1c57
20
README.org
20
README.org
|
@ -1,13 +1,13 @@
|
||||||
#+OPTIONS: toc:nil
|
#+OPTIONS: toc:nil
|
||||||
|
|
||||||
* Zongor's Universe Machine
|
* Zongor's Reality Engine
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: zongors-universe-machine
|
:CUSTOM_ID: zongors-universe-machine
|
||||||
:END:
|
:END:
|
||||||
|
|
||||||
* Overview
|
* Overview
|
||||||
ZTL is a lightweight, portable programming language for permacomputing, game preservation, and indie game development.
|
ZRE is a lightweight, portable programming language for permacomputing, game preservation, and indie game development.
|
||||||
Built in **C99** for cross-platform compatibility (desktop, microcontrollers, and web via Emscripten).
|
Built in **C89** for cross-platform compatibility (desktop, microcontrollers, and web via Emscripten).
|
||||||
Designed for simplicity, performance, and creative exploration.
|
Designed for simplicity, performance, and creative exploration.
|
||||||
It is inspired by [[https://wiki.xxiivv.com/site/uxn.html][uxn]], [[http://duskos.org/][Dusk OS]], [[https://lua.org][Lua]], [[https://en.wikipedia.org/wiki/Lisp_(programming_language)][Lisp]], [[https://en.wikipedia.org/wiki/C_(programming_language)][C]], and [[https://ziglang.org/][Zig]].
|
It is inspired by [[https://wiki.xxiivv.com/site/uxn.html][uxn]], [[http://duskos.org/][Dusk OS]], [[https://lua.org][Lua]], [[https://en.wikipedia.org/wiki/Lisp_(programming_language)][Lisp]], [[https://en.wikipedia.org/wiki/C_(programming_language)][C]], and [[https://ziglang.org/][Zig]].
|
||||||
|
|
||||||
|
@ -30,30 +30,32 @@
|
||||||
- Emacs major mode included; Vim, VSCode, and Lite XL support planned.
|
- Emacs major mode included; Vim, VSCode, and Lite XL support planned.
|
||||||
|
|
||||||
** Language Design
|
** Language Design
|
||||||
- Dynamically typed with optional type hints in function signatures.
|
- Strongly typed with optional type hints in function signatures.
|
||||||
- Unified =real= type (=f64= by default) with =byte= for interop (u8, i32, f32, etc.).
|
- Unified =real= type (=f64= by default) for floating point/fixed point numbers with =byte= for integer numbers (u8, i32, etc.).
|
||||||
- 3D math primitives: =vec=, =mat=, =quat=, and more.
|
- 3D math primitives: =vec=, =mat=, =quat=, and more.
|
||||||
- Strings with interpolation, =split=, =replace=, =trim=, etc.
|
- Strings with interpolation, =split=, =replace=, =trim=, etc.
|
||||||
- Error handling:
|
- Error handling:
|
||||||
- Go-style explicit errors.
|
- Go-style explicit errors.
|
||||||
- Null coalescing (=??=) and null checks (=?.=).
|
- Null coalescing (=??=) and null checks (=?.=).
|
||||||
- Lightweight coroutines with event-loop-driven multitasking.
|
- Lightweight coroutines with event-loop-driven multitasking.
|
||||||
- FFI via C-defined "native functions" (examples provided in VM).
|
- FFI via C-defined "system calls" (examples provided in VM).
|
||||||
|
|
||||||
** Modularity & Ecosystem
|
** Modularity & Ecosystem
|
||||||
- Unified table type (like Lua) for lists, maps, and tuples.
|
- Unified table type (like Lua) for lists, maps, and tuples.
|
||||||
|
- Higher performance array type.
|
||||||
- Standard library: math, networking, 3D rendering, minimal GUI.
|
- Standard library: math, networking, 3D rendering, minimal GUI.
|
||||||
- =use= keyword for modular code organization via file-based namespaces.
|
- =use= keyword for modular code organization via file-based namespaces.
|
||||||
|
|
||||||
* Technical Details
|
* Technical Details
|
||||||
|
|
||||||
** VM Architecture
|
** VM Architecture
|
||||||
- Stack-based bytecode interpreter written in C99.
|
- Stack-based bytecode interpreter written in C89.
|
||||||
- Portable to new systems, microcontrollers, and web via Emscripten.
|
- Portable to new systems, microcontrollers, and web via Emscripten.
|
||||||
|
|
||||||
** Memory Management
|
** Memory Management
|
||||||
- Reference counting for globally scoped objects.
|
- Reference counting for globally scoped objects.
|
||||||
- =weak= keyword to avoid cyclical references.
|
- =weak= keyword to avoid cyclical references.
|
||||||
|
- garbage collection as a system call (choose when to free memory)
|
||||||
- Arena allocators for short-lived, scoped memory (e.g., function-local objects).
|
- Arena allocators for short-lived, scoped memory (e.g., function-local objects).
|
||||||
|
|
||||||
** Rendering & I/O
|
** Rendering & I/O
|
||||||
|
@ -84,9 +86,9 @@
|
||||||
|
|
||||||
* Motivation
|
* Motivation
|
||||||
|
|
||||||
ZTL bridges retro-inspired creativity with modern portability for:
|
ZRE bridges retro-inspired creativity with modern portability for:
|
||||||
- Game jams (rapid prototyping + 3D engine).
|
- Game jams (rapid prototyping + 3D engine).
|
||||||
- Indie games (5th/6th-gen aesthetics).
|
- Indie games (5th/6th-gen aesthetics).
|
||||||
- Permacomputing (low-resource, sustainable code).
|
- Permacomputing (low-resource, sustainable code).
|
||||||
- Education (simple VM/language design).
|
- Education (simple VM/language design), a language which scales to the developers level.
|
||||||
|
|
||||||
|
|
|
@ -91,3 +91,38 @@ be something like the backend dac for ORCA.
|
||||||
9p filesystem/network by default.
|
9p filesystem/network by default.
|
||||||
|
|
||||||
Have an easy way to network.
|
Have an easy way to network.
|
||||||
|
|
||||||
|
*** opcodes
|
||||||
|
|
||||||
|
|---------------------------------------------------------------------------------------+------------------------------------------------------------------|
|
||||||
|
| opcode | description |
|
||||||
|
|---------------------------------------------------------------------------------------+------------------------------------------------------------------|
|
||||||
|
| nil | noop/nil/eos |
|
||||||
|
| *bbbb call | calls the address as a function |
|
||||||
|
| b syscall | calls a system call based on the opcode |
|
||||||
|
| bbbb pushReal - | allocates Q16.16 bits on the stack |
|
||||||
|
| - popReal bbbb | deallocates Q16.16 bits from the stack |
|
||||||
|
| b *bbbb storeByte - | stores 8 bits from the stack to the address |
|
||||||
|
| bbbb *bbbb storeReal - | stores 64 bits from the stack to the address |
|
||||||
|
| *bbbb loadByte b | loads 8 bits from the address to the stack |
|
||||||
|
| *bbbb loadReal bbbb | loads 64 bits from the address to the stack |
|
||||||
|
| bbbb bbbb addReal bbbb | adds 64 bits from the stack |
|
||||||
|
| bbbb bbbb subReal bbbb | subtracts 64 bits from the stack |
|
||||||
|
| bbbb bbbb mulReal bbbb | multiplies 64 bits from the stack |
|
||||||
|
| bbbb bbbb divReal bbbb | divides 64 bits from the stack |
|
||||||
|
| bbbb [bbbb bbbb bbbb] scalevec3 [bbbb bbbb bbbb] | scales the vec3 by the f64 on the stack |
|
||||||
|
| [bbbb bbbb bbbb] [bbbb bbbb bbbb] addvec3 [bbbb bbbb bbbb] | adds 2 vec3 together from the stack |
|
||||||
|
| [bbbb bbbb bbbb] [bbbb bbbb bbbb] subvec3 [bbbb bbbb bbbb] | subtracts 2 vec3 together from the stack |
|
||||||
|
| [bbbb bbbb bbbb] [bbbb bbbb bbbb] mulvec3 [bbbb bbbb bbbb] | multiplies 2 vec3 together from the stack |
|
||||||
|
| [bbbb bbbb bbbb] [bbbb bbbb bbbb] dotvec3 bbbb | dot product of 2 vec3 together from the stack |
|
||||||
|
| [bbbb bbbb bbbb] [bbbb bbbb bbbb] crossvec3 [bbbb bbbb bbbb] | cross product of 2 vec3 together from the stack |
|
||||||
|
| [bbbb bbbb bbbb] normvec3 [bbbb bbbb bbbb] | normalizes a vec3 |
|
||||||
|
| [[bbbb bbbb bbbb bbbb]*4] invmat4 [[bbbb bbbb bbbb bbbb]*4] | inverts a mat4 from the stack |
|
||||||
|
| [[bbbb bbbb bbbb bbbb]*4] [[bbbb bbbb bbbb bbbb]*4] mulmat4 [[bbbb bbbb bbbb bbbb]*4] | multiplies 2 mat4's from the stack |
|
||||||
|
| *triangle-array-ptr nnnn drawtriangles - | drawn 'n' many triangles using a array of vertices and its color |
|
||||||
|
| *str1 *str2 streq b | checks 2 strings returns a bool of if they are the same |
|
||||||
|
| *str1 *str2 strcat *str3 | concatinates 2 strings and returns the address of the new string |
|
||||||
|
| *str strlen bbbb | pushes the length of the string onto the stack |
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
|---------------------------------------------------------------------------------------+------------------------------------------------------------------|
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
* /ZTL/ (Zongors Transpiler Language) Design parameters
|
* /ZRE/ (Zongors Reality Engine) Design parameters
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: ztl-zongors-transpiler-language-design-parameters
|
:CUSTOM_ID: zre-zongors-transpiler-language-design-parameters
|
||||||
:END:
|
:END:
|
||||||
** What is /ztl/?
|
** What is /zre/?
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: what-is-ztl
|
:CUSTOM_ID: what-is-zre
|
||||||
:END:
|
:END:
|
||||||
/ztl/ is an domain specific language for 3d games with C/Lua style syntax.
|
/zre/ is an domain specific language for 3d games with C/Lua style syntax.
|
||||||
The compiler is written in C which should make it easy to port to other
|
The compiler is written in C which should make it easy to port to other
|
||||||
systems.
|
systems.
|
||||||
|
|
||||||
* /ZTL/ Grammar and Specification
|
* /ZRE/ Grammar and Specification
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: ztl-grammar-and-specification
|
:CUSTOM_ID: zre-grammar-and-specification
|
||||||
:END:
|
:END:
|
||||||
** Types
|
** Types
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
@ -23,13 +23,13 @@ systems.
|
||||||
are coming from object oriented languages you can think of self as
|
are coming from object oriented languages you can think of self as
|
||||||
"primitive types"
|
"primitive types"
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
type «token» {
|
type «token» {
|
||||||
init() {
|
init() {
|
||||||
// values
|
// values
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
* Basic Types
|
* Basic Types
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
@ -40,10 +40,12 @@ type «token» {
|
||||||
:CUSTOM_ID: numeric
|
:CUSTOM_ID: numeric
|
||||||
:END:
|
:END:
|
||||||
- =real=
|
- =real=
|
||||||
- 64 bit floating point (Double)
|
- 64 bit floating point (Double) by default for modern CPUs that have a FPU
|
||||||
- Is it slow and takes up a lot of space? yeah it does,
|
- 32 bit 16.16 for microcontrollers/hardware without a FPU like a raspberry pi pico, retro hardware like a Mac 68k
|
||||||
but because it is the only numeric type it makes it so that you do not have to worry about type casting which actually ends up speeding up processing
|
- 16 bit 12.4 for older retro hardware like PS1 or UXN.
|
||||||
This is also how Lua, Lox, and Wren programming language handles numbers. Also because ZTL is intended to be used for Games, floats are used more for
|
- Is it slow and takes up a lot of space? yeah, kinda, maybe,
|
||||||
|
the nice part of a unified numeric type is that makes it so that you do not have to worry about type casting which actually ends up speeding up processing
|
||||||
|
This is also how Lua, Lox, and Wren programming language handles numbers. Also because ZRE is intended to be used for Games, floats are used more for
|
||||||
3D graphics than other numeric types.
|
3D graphics than other numeric types.
|
||||||
|
|
||||||
** string
|
** string
|
||||||
|
@ -66,7 +68,7 @@ string interpolation
|
||||||
:CUSTOM_ID: binary
|
:CUSTOM_ID: binary
|
||||||
:END:
|
:END:
|
||||||
- =byte=
|
- =byte=
|
||||||
- same as uint8 or c char, used for interop
|
- same as uint8 or c char, also used for interop
|
||||||
|
|
||||||
** logical
|
** logical
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
@ -85,11 +87,11 @@ monad above and is unwrapped in a similar way. You could also think of
|
||||||
it as every variable being able to have "the type" and also "error" as a
|
it as every variable being able to have "the type" and also "error" as a
|
||||||
possible value.
|
possible value.
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
let rr = err("something borked");
|
let rr = err("something borked");
|
||||||
let var = rr ?? 0; // value is 0
|
let var = rr ?? 0; // value is 0
|
||||||
let other_var = rr ?? panic(rr); // will panic
|
let other_var = rr ?? panic(rr); // will panic
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
** datastructure
|
** datastructure
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
@ -108,13 +110,13 @@ Types that can be indexes are numbers and strings (no objects);
|
||||||
syntax (yes I was nice and kept the syntax the same as most C like
|
syntax (yes I was nice and kept the syntax the same as most C like
|
||||||
langs)
|
langs)
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
/* array same as a map of int to «type» */
|
/* array same as a map of int to «type» */
|
||||||
let «variable» = [val1, val2, ...];
|
let «variable» = [val1, val2, ...];
|
||||||
|
|
||||||
/* or as a map */
|
/* or as a map */
|
||||||
let «variable» = {key1: val1, key2: val2, ...};
|
let «variable» = {key1: val1, key2: val2, ...};
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
*** tunnel
|
*** tunnel
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
@ -202,19 +204,19 @@ The following is a list of global operators and their effect:
|
||||||
|
|
||||||
let operator
|
let operator
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
let «token» = true;
|
let «token» = true;
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
=is=
|
=is=
|
||||||
|
|
||||||
checks if a object is of that type
|
checks if a object is of that type
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
if («token» is real) {
|
if («token» is real) {
|
||||||
print("hello yes self is a real?");
|
print("hello yes self is a real?");
|
||||||
}
|
}
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
also used for letting constants
|
also used for letting constants
|
||||||
|
|
||||||
|
@ -222,26 +224,26 @@ also used for letting constants
|
||||||
|
|
||||||
coerces a type as another type if possible
|
coerces a type as another type if possible
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
let «token» = 0; /* default is real */
|
let «token» = 0; /* default is real */
|
||||||
some_functon(«token» as byte); /* needs an byte */
|
some_functon(«token» as byte); /* needs an byte */
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
=in=
|
=in=
|
||||||
|
|
||||||
checks if a object's type, or a type impls another type
|
checks if a object's type, or a type impls another type
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
if («token» in Tunnel) {
|
if («token» in Tunnel) {
|
||||||
print("im tunnel-able");
|
print("im tunnel-able");
|
||||||
}
|
}
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
also used inside of the for loops
|
also used inside of the for loops
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
for («token» in «collection») { «body» }
|
for («token» in «collection») { «body» }
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
** Object
|
** Object
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
@ -249,9 +251,9 @@ for («token» in «collection») { «body» }
|
||||||
:END:
|
:END:
|
||||||
An object is an invoked type.
|
An object is an invoked type.
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
let «variable» = «type»(«fields», …);
|
let «variable» = «type»(«fields», …);
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
** Tunnel
|
** Tunnel
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
@ -305,7 +307,7 @@ connected tunnel
|
||||||
=success? : tunnel_object.walk(path_or_endpoint)= -> moves around the
|
=success? : tunnel_object.walk(path_or_endpoint)= -> moves around the
|
||||||
filesystem or through the graph
|
filesystem or through the graph
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
/* client */
|
/* client */
|
||||||
let endpoint = `protocol://path/to/source`;
|
let endpoint = `protocol://path/to/source`;
|
||||||
let tunnel = endpoint.attach(user, auth);
|
let tunnel = endpoint.attach(user, auth);
|
||||||
|
@ -320,7 +322,7 @@ s.bind("/some/resource", fn () str {
|
||||||
return "hello world";
|
return "hello world";
|
||||||
})
|
})
|
||||||
server.start();
|
server.start();
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
** Functions
|
** Functions
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
@ -331,11 +333,11 @@ always have a "default type" for all constant values or a developer can
|
||||||
use the =as= keyword we do not have to define all values like in C,
|
use the =as= keyword we do not have to define all values like in C,
|
||||||
while keeping the same type safety as a more strongly typed language.
|
while keeping the same type safety as a more strongly typed language.
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
fn «token» («parameter» «type», ...) «return_type» {
|
fn «token» («parameter» «type», ...) «return_type» {
|
||||||
«body»
|
«body»
|
||||||
}
|
}
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
- Built in transtypes
|
- Built in transtypes
|
||||||
- sort
|
- sort
|
||||||
|
@ -352,27 +354,27 @@ fn «token» («parameter» «type», ...) «return_type» {
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: loops
|
:CUSTOM_ID: loops
|
||||||
:END:
|
:END:
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
for («token» in «collection») { «body» }
|
for («token» in «collection») { «body» }
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
iterates through each object in the collection setting it to token
|
iterates through each object in the collection setting it to token
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
while («boolean expression») { «body» }
|
while («boolean expression») { «body» }
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
loops until the expression is false
|
loops until the expression is false
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
loop { «body» }
|
loop { «body» }
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
loops infinitely until break or return
|
loops infinitely until break or return
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
do («variable» = initial_value, end_value, increment) { «body» }
|
do («variable» = initial_value, end_value, increment) { «body» }
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
loops from initial value to end value by increment value
|
loops from initial value to end value by increment value
|
||||||
|
|
||||||
|
@ -380,7 +382,7 @@ loops from initial value to end value by increment value
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: branching
|
:CUSTOM_ID: branching
|
||||||
:END:
|
:END:
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
if («boolean expression») {
|
if («boolean expression») {
|
||||||
|
|
||||||
} else if («boolean expression») {
|
} else if («boolean expression») {
|
||||||
|
@ -388,7 +390,7 @@ if («boolean expression») {
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
*** exceptions
|
*** exceptions
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
@ -396,11 +398,11 @@ if («boolean expression») {
|
||||||
:END:
|
:END:
|
||||||
take a look at error's, but you can panic on an error like self:
|
take a look at error's, but you can panic on an error like self:
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
panic(err("error message"));
|
panic(err("error message"));
|
||||||
panic(err(3));
|
panic(err(3));
|
||||||
panic(«some_error_token»);
|
panic(«some_error_token»);
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
** Localization
|
** Localization
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
@ -408,9 +410,9 @@ panic(«some_error_token»);
|
||||||
:END:
|
:END:
|
||||||
will look up the text of «token» in the linked localization.json file
|
will look up the text of «token» in the linked localization.json file
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
#«token»
|
#«token»
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
#+begin_src json
|
#+begin_src json
|
||||||
{
|
{
|
||||||
|
@ -436,13 +438,13 @@ can even use localization tokens to create config files. Since
|
||||||
everything is lazily compiled jit anyways it (in theory) doesn't hurt
|
everything is lazily compiled jit anyways it (in theory) doesn't hurt
|
||||||
pertypeance much
|
pertypeance much
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
use `https://example.com/some_library/some_file.ztl`
|
use `https://example.com/some_library/some_file.zre`
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
use `./some_local_file.ztl`
|
use `./some_local_file.zre`
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
** Testing
|
** Testing
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
@ -452,9 +454,9 @@ use `./some_local_file.ztl`
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: assertion
|
:CUSTOM_ID: assertion
|
||||||
:END:
|
:END:
|
||||||
#+begin_src ztl
|
#+begin_src zre
|
||||||
assert(«expression», «expected output») /* returns «error or none» */
|
assert(«expression», «expected output») /* returns «error or none» */
|
||||||
#+end_src ztl
|
#+end_src zre
|
||||||
|
|
||||||
** Measurements
|
** Measurements
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MEMORY_SIZE 65536 // 64KB memory (adjustable)
|
||||||
|
uint32_t memory[MEMORY_SIZE]; // Memory array
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
OP_ADD, // dest = src1 + src2
|
||||||
|
OP_MOV, // dest = src1
|
||||||
|
OP_JMP, // jump to address
|
||||||
|
OP_HALT // terminate execution
|
||||||
|
} Opcode;
|
||||||
|
|
||||||
|
void run_vm() {
|
||||||
|
uint32_t pc = 0; // Program counter
|
||||||
|
while (1) {
|
||||||
|
// Fetch instruction
|
||||||
|
Opcode opcode = memory[pc];
|
||||||
|
uint32_t src1_addr = memory[pc + 1];
|
||||||
|
uint32_t src2_addr = memory[pc + 2];
|
||||||
|
uint32_t dest_addr = memory[pc + 3];
|
||||||
|
pc += 4; // Advance to next instruction
|
||||||
|
|
||||||
|
// Validate addresses (safety check)
|
||||||
|
if (src1_addr >= MEMORY_SIZE || src2_addr >= MEMORY_SIZE || dest_addr >= MEMORY_SIZE) {
|
||||||
|
printf("Invalid memory address!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute instruction
|
||||||
|
switch (opcode) {
|
||||||
|
case OP_ADD:
|
||||||
|
memory[dest_addr] = memory[src1_addr] + memory[src2_addr];
|
||||||
|
break;
|
||||||
|
case OP_MOV:
|
||||||
|
memory[dest_addr] = memory[src1_addr];
|
||||||
|
break;
|
||||||
|
case OP_JMP:
|
||||||
|
pc = src1_addr; // Jump to address
|
||||||
|
break;
|
||||||
|
case OP_HALT:
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
printf("Unknown opcode: %d\n", opcode);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Initialize memory
|
||||||
|
memory[0] = OP_ADD; // Opcode
|
||||||
|
memory[1] = 100; // A (src1)
|
||||||
|
memory[2] = 101; // B (src2)
|
||||||
|
memory[3] = 102; // C (dest)
|
||||||
|
memory[100] = 5; // Value of A
|
||||||
|
memory[101] = 7; // Value of B
|
||||||
|
memory[4] = OP_HALT; // Terminate after ADD
|
||||||
|
|
||||||
|
run_vm();
|
||||||
|
|
||||||
|
printf("Result at address 102: %u\n", memory[102]); // Output: 12
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,210 @@
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// Q16.16 fixed-point macros
|
||||||
|
#define Q16_16_SCALE 16
|
||||||
|
#define Q16_16_FRACTION_MASK 0x0000FFFF
|
||||||
|
#define TO_Q16_16(x) \
|
||||||
|
((int32_t)((x) << Q16_16_SCALE)) // Convert integer to Q16.16
|
||||||
|
#define FROM_Q16_16(x) \
|
||||||
|
((int32_t)((x) >> Q16_16_SCALE)) // Convert Q16.16 to integer
|
||||||
|
|
||||||
|
#define MEMORY_SIZE 65536
|
||||||
|
int32_t memory[MEMORY_SIZE]; // Changed to signed for fixed-point support
|
||||||
|
|
||||||
|
typedef enum { OP_ADD, OP_MOV, OP_JMP, OP_HALT } Opcode;
|
||||||
|
|
||||||
|
|
||||||
|
// Convert string to Q16.16 fixed-point
|
||||||
|
int32_t string_to_q16_16(const char *str) {
|
||||||
|
int32_t result = 0;
|
||||||
|
int sign = 1;
|
||||||
|
|
||||||
|
// Handle sign
|
||||||
|
if (*str == '-') {
|
||||||
|
sign = -1;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse integer part
|
||||||
|
int32_t integer_part = 0;
|
||||||
|
while (*str != '.' && *str != '\0') {
|
||||||
|
if (*str < '0' || *str > '9') {
|
||||||
|
return 0; // Invalid character
|
||||||
|
}
|
||||||
|
integer_part = integer_part * 10 + (*str - '0');
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp integer part to 16-bit range
|
||||||
|
if (integer_part > 32767) {
|
||||||
|
integer_part = 32767; // Overflow clamp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse fractional part
|
||||||
|
uint32_t frac_digits = 0;
|
||||||
|
int frac_count = 0;
|
||||||
|
|
||||||
|
if (*str == '.') {
|
||||||
|
str++; // Skip decimal point
|
||||||
|
while (*str != '\0' && frac_count < 6) {
|
||||||
|
if (*str < '0' || *str > '9') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
frac_digits = frac_digits * 10 + (*str - '0');
|
||||||
|
frac_count++;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale fractional part to Q16.16
|
||||||
|
// frac_q16 = (frac_digits * 65536 + 500000) / 1000000
|
||||||
|
// This avoids floating-point by using integer arithmetic
|
||||||
|
uint32_t scaled_frac = 0;
|
||||||
|
if (frac_count > 0) {
|
||||||
|
// Pad with zeros if less than 6 digits
|
||||||
|
while (frac_count < 6) {
|
||||||
|
frac_digits *= 10;
|
||||||
|
frac_count++;
|
||||||
|
}
|
||||||
|
// Compute scaled fractional part with rounding
|
||||||
|
scaled_frac = (frac_digits * 65536 + 500000) / 1000000;
|
||||||
|
if (scaled_frac > 0xFFFF) {
|
||||||
|
scaled_frac = 0xFFFF; // Clamp to 16-bit range
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine integer and fractional parts
|
||||||
|
result = (integer_part << Q16_16_SCALE) | (scaled_frac & Q16_16_FRACTION_MASK);
|
||||||
|
return result * sign;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert Q16.16 to string using integer-only arithmetic
|
||||||
|
int q16_16_to_string(int32_t value, char *buffer, size_t size) {
|
||||||
|
if (size < 13) { // Minimum buffer size for "-32768.000000\0"
|
||||||
|
if (size > 0)
|
||||||
|
buffer[0] = '\0';
|
||||||
|
return -1; // Buffer too small
|
||||||
|
}
|
||||||
|
|
||||||
|
char *buf = buffer;
|
||||||
|
size_t remaining = size;
|
||||||
|
|
||||||
|
// Handle sign
|
||||||
|
if (value < 0) {
|
||||||
|
*buf++ = '-';
|
||||||
|
value = -value;
|
||||||
|
remaining--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract integer and fractional parts
|
||||||
|
int32_t integer_part = value >> Q16_16_SCALE;
|
||||||
|
uint32_t frac = value & Q16_16_FRACTION_MASK;
|
||||||
|
|
||||||
|
// Convert integer part to string
|
||||||
|
char int_buf[11]; // Max 10 digits for 32-bit int
|
||||||
|
char *int_end = int_buf + sizeof(int_buf);
|
||||||
|
char *int_ptr = int_end;
|
||||||
|
|
||||||
|
// Special case for zero
|
||||||
|
if (integer_part == 0) {
|
||||||
|
*--int_ptr = '0';
|
||||||
|
} else {
|
||||||
|
while (integer_part > 0 && int_ptr > int_buf) {
|
||||||
|
*--int_ptr = '0' + (integer_part % 10);
|
||||||
|
integer_part /= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy integer part to output buffer
|
||||||
|
while (int_ptr < int_end && remaining > 1) {
|
||||||
|
*buf++ = *int_ptr++;
|
||||||
|
remaining--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add decimal point
|
||||||
|
if (remaining > 7) { // Need space for .000000
|
||||||
|
*buf++ = '.';
|
||||||
|
remaining--;
|
||||||
|
} else {
|
||||||
|
if (remaining > 0)
|
||||||
|
*buf = '\0';
|
||||||
|
return size - remaining; // Truncate if insufficient space
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert fractional part to 6 digits
|
||||||
|
for (int i = 0; i < 6 && remaining > 1; i++) {
|
||||||
|
frac *= 10;
|
||||||
|
uint32_t digit = frac >> 16;
|
||||||
|
frac &= 0xFFFF;
|
||||||
|
*buf++ = '0' + digit;
|
||||||
|
remaining--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Null-terminate
|
||||||
|
*buf = '\0';
|
||||||
|
return buf - buffer; // Return length written
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_vm() {
|
||||||
|
uint32_t pc = 0;
|
||||||
|
while (1) {
|
||||||
|
Opcode opcode = memory[pc];
|
||||||
|
uint32_t src1_addr = memory[pc + 1];
|
||||||
|
uint32_t src2_addr = memory[pc + 2];
|
||||||
|
uint32_t dest_addr = memory[pc + 3];
|
||||||
|
pc += 4;
|
||||||
|
|
||||||
|
if (src1_addr >= MEMORY_SIZE || src2_addr >= MEMORY_SIZE ||
|
||||||
|
dest_addr >= MEMORY_SIZE) {
|
||||||
|
printf("Invalid memory address!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case OP_ADD:
|
||||||
|
// Q16.16 addition requires no scaling adjustment
|
||||||
|
memory[dest_addr] = memory[src1_addr] + memory[src2_addr];
|
||||||
|
break;
|
||||||
|
case OP_MOV:
|
||||||
|
// Direct copy preserves fixed-point representation
|
||||||
|
memory[dest_addr] = memory[src1_addr];
|
||||||
|
break;
|
||||||
|
case OP_JMP:
|
||||||
|
pc = src1_addr;
|
||||||
|
break;
|
||||||
|
case OP_HALT:
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
printf("Unknown opcode: %d\n", opcode);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Initialize memory with Q16.16 values
|
||||||
|
memory[0] = OP_ADD;
|
||||||
|
memory[1] = 100;
|
||||||
|
memory[2] = 101;
|
||||||
|
memory[3] = 102;
|
||||||
|
const char *input = "-5.0";
|
||||||
|
memory[100] = string_to_q16_16(input); // Convert "-5.0" to Q16.16
|
||||||
|
const char *input2 = "10.0";
|
||||||
|
memory[101] = string_to_q16_16(input2); // Convert "10.0" to Q16.16
|
||||||
|
memory[4] = OP_HALT;
|
||||||
|
|
||||||
|
run_vm();
|
||||||
|
|
||||||
|
char buffer[13]; // Sufficient for Q16.16 format
|
||||||
|
|
||||||
|
// Convert result back to integer
|
||||||
|
q16_16_to_string(memory[102], buffer, sizeof(buffer));
|
||||||
|
printf("Result at address 102: %s\n", buffer); // Output: 5.0
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ fn main(argc real, argv str[]) {
|
||||||
let username = argv[0];
|
let username = argv[0];
|
||||||
let password = argv[1];
|
let password = argv[1];
|
||||||
|
|
||||||
let me = Player(username, (0.0, 1.0, 2.0), PURPLE);
|
let me = Player(username, Vec3(0.0, 1.0, 2.0), PURPLE);
|
||||||
|
|
||||||
let running = true;
|
let running = true;
|
||||||
while (running) {
|
while (running) {
|
||||||
|
@ -22,12 +22,12 @@ fn main(argc real, argv str[]) {
|
||||||
}
|
}
|
||||||
splitbox(parent.size * 0.75) {
|
splitbox(parent.size * 0.75) {
|
||||||
canvas("3D") {
|
canvas("3D") {
|
||||||
model(Floor((0, 0, 0), 30));
|
model(Floor(Vec3(0, 0, 0), 30));
|
||||||
me.update();
|
me.update();
|
||||||
model(Cube(me.pos, (0.5, 0.5, 0.5), me.appearance));
|
model(Cube(me.pos, Vec3(0.5, 0.5, 0.5), me.appearance));
|
||||||
if (let players = me.server.read("players")) {
|
if (let players = me.server.read("players")) {
|
||||||
for (p in players) {
|
for (p in players) {
|
||||||
model(Cube(p.pos, (0.5, 0.5, 0.5), p.apperance));
|
model(Cube(p.pos, Vec3(0.5, 0.5, 0.5), p.apperance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ type Camera {
|
||||||
init(pos Vec3, look Vec3) {
|
init(pos Vec3, look Vec3) {
|
||||||
this.setting = "CAMERA_PERSPECTIVE";
|
this.setting = "CAMERA_PERSPECTIVE";
|
||||||
this.pov = 45.0;
|
this.pov = 45.0;
|
||||||
this.up = (0.0, 1.0, 0.0);
|
this.up = Vec3(0.0, 1.0, 0.0);
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
this.look = look;
|
this.look = look;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ type Player {
|
||||||
Camera((this.pos.x + 10.0, this.pos.y + 10.0, this.pos.z), this.pos);
|
Camera((this.pos.x + 10.0, this.pos.y + 10.0, this.pos.z), this.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
login(password str) Player[] {
|
login(str password) Player[] {
|
||||||
this.server.attach(this.username, password);
|
this.server.attach(this.username, password);
|
||||||
this.players = server.open("players");
|
this.players = server.open("players");
|
||||||
return players.read();
|
return players.read();
|
||||||
|
@ -59,6 +59,6 @@ type Player {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const RED is[255, 0, 0];
|
const RED is [255, 0, 0];
|
||||||
const WHITE is[0, 0, 0];
|
const WHITE is [0, 0, 0];
|
||||||
const PURPLE is[255, 255, 0];
|
const PURPLE is [255, 255, 0];
|
||||||
|
|
|
@ -3,7 +3,7 @@ use "common.ztl";
|
||||||
fn main(argc real, argv str[]) {
|
fn main(argc real, argv str[]) {
|
||||||
let s = Server("tcp://0.0.0.0:25565");
|
let s = Server("tcp://0.0.0.0:25565");
|
||||||
let running = true;
|
let running = true;
|
||||||
let players = [Player("user", (0, 0, 0), RED)];
|
let players = [Player("user", [0, 0, 0], RED)];
|
||||||
while (running) {
|
while (running) {
|
||||||
if (let client = s.accept("players")) {
|
if (let client = s.accept("players")) {
|
||||||
if (let message = client.get()) {
|
if (let message = client.get()) {
|
||||||
|
|
Loading…
Reference in New Issue