WIP functions def

This commit is contained in:
zongor 2026-05-16 12:47:01 -07:00
parent 490b869919
commit e968cb6725
8 changed files with 492 additions and 426 deletions

View File

@ -79,6 +79,36 @@ is_type()
parser.previous.type <= TOKEN_TYPE_PTR;
}
SymbolType
tokt_to_symt(TokenType t)
{
switch(t) {
case TOKEN_TYPE_BOOL:
return SYMBOL_BOOL;
case TOKEN_TYPE_BYTE:
return SYMBOL_BYTE;
case TOKEN_TYPE_INT:
return SYMBOL_INT;
case TOKEN_TYPE_NAT:
return SYMBOL_NAT;
case TOKEN_TYPE_REAL:
return SYMBOL_REAL;
case TOKEN_TYPE_STR:
return SYMBOL_STR;
case TOKEN_TYPE_U8:
return SYMBOL_U8;
case TOKEN_TYPE_I8:
return SYMBOL_I8;
case TOKEN_TYPE_I16:
return SYMBOL_I16;
case TOKEN_TYPE_U16:
return SYMBOL_U16;
default:
break;
}
return SYMBOL_UNDEFINED;
}
/****************************************************
* Parser
***************************************************/
@ -120,6 +150,84 @@ match(TokenType type)
return true;
}
void
expect(TokenType type)
{
if(!match(type)) {
emitter.error(parser.previous.start, parser.previous.length,
parser.previous.line);
}
}
u32 variable_declaration(Symbol *def);
void
define_plex()
{
}
void
define_trait()
{
}
void
define_function()
{
Symbol *fn;
u32 size = 0;
advance();
fn = scope_add_symbol(parser.previous.start, parser.previous.length,
SYMBOL_FUNCTION, 0);
/* need to push scope early because the variables need to be a part of the fn
* scope */
scope_push();
expect(TOKEN_LPAREN);
/* parse the args */
while(!match(TOKEN_RPAREN)) size += variable_declaration(fn);
if(!match(TOKEN_LBRACE)) {
fn->secondary_type = tokt_to_symt(parser.previous.type);
/* now parse the fn body */
expect(TOKEN_LBRACE);
}
/* get the size of all the locals for the function in the body */
while(!match(TOKEN_RBRACE))
if(is_type()) size += variable_declaration(fn);
fn->size = size;
}
void
build_symbol_table(char *source)
{
init_lexer(source);
advance();
scope_push();
while(!match(TOKEN_EOF)) {
if(match(TOKEN_LBRACE)) {
scope_push();
} else if(match(TOKEN_RBRACE)) {
scope_pop();
} else if(match(TOKEN_KEYWORD_FN)) {
define_function();
} else if(match(TOKEN_KEYWORD_PLEX)) {
define_plex();
} else if(match(TOKEN_KEYWORD_TRAIT)) {
define_trait();
} else {
/* in binary bytecode output mode we need to count the bytes here */
/* otherwise ignore everything */
}
}
}
void expression();
void statement();
void declaration();
@ -321,103 +429,38 @@ cast_type()
}
}
void
variable_declaration()
u32
variable_declaration(Symbol *def)
{
i32 size = 0;
TokenType tt = parser.previous.type;
Token var = parser.current;
SymbolType st = tokt_to_symt(tt);
Symbol *arg;
switch(tt) {
case TOKEN_TYPE_INT: {
size = emitter.emit_int_type(parser.current.start, parser.current.length,
parser.depth);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_INT,
size);
parser.current_type = SYMBOL_INT;
break;
}
case TOKEN_TYPE_NAT: {
size = emitter.emit_nat_type(parser.current.start, parser.current.length,
parser.depth);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_NAT,
size);
parser.current_type = SYMBOL_NAT;
break;
}
case TOKEN_TYPE_REAL: {
size = emitter.emit_real_type(parser.current.start, parser.current.length,
parser.depth);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_REAL,
size);
parser.current_type = SYMBOL_REAL;
break;
}
case TOKEN_TYPE_STR: {
size = emitter.emit_str_type(parser.current.start, parser.current.length,
parser.depth);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_STR,
size);
parser.current_type = SYMBOL_STR;
break;
}
case TOKEN_TYPE_BOOL: {
size = emitter.emit_bool_type(parser.current.start, parser.current.length,
parser.depth);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_BOOL,
size);
parser.current_type = SYMBOL_BOOL;
break;
}
case TOKEN_TYPE_BYTE: {
size = emitter.emit_byte_type(parser.current.start, parser.current.length,
parser.depth);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_U8,
size);
parser.current_type = SYMBOL_BYTE;
break;
}
case TOKEN_TYPE_U8: {
size = emitter.emit_u8_type(parser.current.start, parser.current.length,
parser.depth);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_U8,
size);
parser.current_type = SYMBOL_U8;
break;
}
case TOKEN_TYPE_I8: {
size = emitter.emit_i8_type(parser.current.start, parser.current.length,
parser.depth);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_I8,
size);
parser.current_type = SYMBOL_I8;
break;
}
case TOKEN_TYPE_U16: {
size = emitter.emit_u16_type(parser.current.start, parser.current.length,
parser.depth);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_U16,
size);
parser.current_type = SYMBOL_U16;
break;
}
case TOKEN_TYPE_I16: {
size = emitter.emit_i16_type(parser.current.start, parser.current.length,
parser.depth);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_I16,
size);
parser.current_type = SYMBOL_I16;
break;
}
default: {
/* probably a plex */
break;
}
if (st != SYMBOL_UNDEFINED) {
size = emitter.get_size(st);
arg = scope_add_symbol(parser.current.start, parser.current.length,
st, size);
if(def) {
List_push(arena, def->args, arg, sizeof(Symbol));
} else {
emitter.emit_type(st, parser.current.start, parser.current.length,
parser.depth);
parser.current_type = st;
}
} else {
/* we need to look up the type */
}
advance();
if(def && (check(TOKEN_COMMA) || check(TOKEN_RPAREN))) return size;
if(def)
emitter.error(parser.previous.start, parser.previous.length,
parser.previous.line);
if(match(TOKEN_EQ)) {
emitter.emit_set_value();
expression();
@ -427,6 +470,7 @@ variable_declaration()
consume(TOKEN_SEMICOLON);
emitter.emit_end_statement();
parser.current_type = SYMBOL_UNDEFINED;
return size;
}
void
@ -438,7 +482,7 @@ declaration()
* if not then
*/
if(is_type())
variable_declaration();
variable_declaration(nil);
else
statement();
}
@ -681,11 +725,9 @@ get_rule(TokenType type)
return &rules[type];
}
bool
compile(Arena *a, Emitter e, char *source)
void
emit_program(char *source)
{
arena = a;
emitter = e;
init_lexer(source);
advance();
scope_push();
@ -695,6 +737,16 @@ compile(Arena *a, Emitter e, char *source)
while(!match(TOKEN_EOF)) declaration();
emitter.epilogue();
}
bool
compile(Arena *a, Emitter e, char *source)
{
arena = a;
emitter = e;
build_symbol_table(source);
emit_program(source);
return true;
}

View File

@ -8,29 +8,54 @@ This is similar to Java's "build once run anywhere" but even more flexable, a Un
Memory Management
Memory is handled deterministically by the compiler following RAII style rules. Unless the devloper is doing some fine grained optimization they will need to think about memory as much as any GC language developer would.
System Specification: Frame-Scoped Region Allocator with Handle References
** Overview
Memory is partitioned into a C style "heap" and "stack". the difference is the behavior of the heap matches that of the stack which are laid out as a "region per call frame". A frame is made up of N many "locals" in the stack (bottom up) and a handle to the beginning of that frames allocated memory in the heap (top down).
A single-threaded, deterministic memory model where each call frame owns a dedicated memory region. References are strictly scoped to the call tree, complex types use length-prefixed handles, and memory is reclaimed immediately on frame teardown. Designed for fixed-size actors communicating via serialized message passing.
** Memory Layout
When a function gets called, it creates a new region in heap memory starting at the end of the previous frame. (or at the beginning of memory if no function has been called). And a new static region for "locals" on the stack.
Logical Heap: Partitioned into one region per call frame, laid out top-down from the previous frame's end (or memory start for the first call).
Stack: Holds frame locals (bottom-up).
Frame Metadata: Stores a handle/pointer to its heap region base, plus frame state.
Allocation: Bump-style allocation within the region. No free-lists or fragmentation tracking within a live frame.
Variables allocated in the frame's region are owned by default by the frame they are allocated in.
** Ownership & Lifecycle
When variables get modified within the current frame they will get updated in that frame in their current location in memory.
All allocations are owned by the frame that created them.
Variables are modified in-place within their frame's region.
On function return, the frame's region is immediately deallocated, deterministically freeing all owned memory.
All complex types (Plex, arrays, strings) use reference handles. Allocations prepend the length to the allocation, its to make sure that its impossible to have the kind of buffer overflow bugs common in C like languages. It also optimizes copy speed since you do not have to do a O(n) search for the size of the block.
** References, Handles & Complex Types
If the size of the variable changes (like adding a value to the end of a array), a new block is allocated at the end of the region of the size of that value + the old value.
Complex types (structs, arrays, strings) use reference handles instead of raw pointers.
Every dynamic allocation prepends a length field to prevent buffer overflows and enable O(1) size queries.
Handles are strictly scoped: they can be passed down to child frames but cannot outlive their frame. If a value must escape, it must be explicitly returned.
No sharing or aliasing exists between frames. The structure is a strict tree (parent → child). Handles become invalid upon frame return.
When a variable is passed to a child function primitive types are pass by value, complex types (Arrays, Plexes, Strings) are pass by reference.
** Resizing & Fragmentation Strategy
Variables passed as arguments to the child follow the same rules except when the size of a complex type changes, the new value is allocated at the end of the childs frame and the owner is now the child. This is the same as C++/Rust "move".
When a complex type grows, a new block is allocated at the end of the region, and ownership transfers to the new allocation. The old block becomes dead space.
Fragmentation is mitigated by design: the system encourages short-lived frames and compositional patterns (building up via smaller, focused functions) to ensure dead space is reclaimed quickly.
Static-size complex types are pre-allocated upfront, so they never need to move on return.
When a function "returns" the frame is deallocated and all values allocated by it is freed; thus freeing memory deterministically.
** Parameter Passing & Returns
When a variable is returned if it is primitive it is just passed back to the parent. If it is complex the value it is copied back to the parent.
Primitives: Passed by value.
Complex types: Passed by handle/reference.
If a passed complex type is modified/grown in a child frame, the new allocation occurs in the child's region, and ownership moves to the child (move semantics).
Returns: Primitives are copied back. Complex types are returned via handle. Since return space is pre-allocated in the caller, the callee writes directly into it, making "move" and "copy" functionally identical for returns.
This allows for the low resource usage of a C but the convenience of a garbage collected language like C# or Go but without the GC pauses.
** Concurrency Model
Not thread-safe. Designed for a single-threaded actor model where fixed-size actors communicate via serialized message passing. Each actor maintains its own isolated call-tree region.
** Key Constraints & Guarantees
References cannot outlive their frame.
No cross-frame sharing; strict parent→child data flow.
Deterministic, O(1) deallocation on frame exit.
Prepend length on all dynamic allocations for safety & performance.
Region reuse encouraged via short-lived frames and compositional design.
Built in Types
Type Description

18
emit.h
View File

@ -4,11 +4,12 @@
#include "common.h"
#include "libc.h"
typedef u32 (*SymbolSize)(SymbolType t);
typedef void (*SymbolEmit)(Symbol *sym);
typedef void (*ErrorMsg)(const char *str, i32 length, i32 line);
typedef void (*VoidArgEmit)();
typedef void (*StrArgEmit)(const char *str, i32 length);
typedef i32 (*TypeVariableEmit)(const char *str, i32 length, bool local);
typedef void (*TypeVariableEmit)(SymbolType t, const char *str, i32 length, bool local);
typedef void (*ConstEmit)(const char *str, i32 length, bool local);
typedef void (*VarEmit)(Symbol *sym, bool local);
typedef void (*I32ArgEmit)(i32 val);
@ -20,6 +21,7 @@ struct emitter_s {
i32 loops;
i32 loop_depth;
ErrorMsg error;
SymbolSize get_size;
VoidArgEmit prolog;
VoidArgEmit epilogue;
VoidArgEmit emit_add;
@ -41,19 +43,7 @@ struct emitter_s {
StrArgEmit emit_real;
StrArgEmit emit_byte;
StrArgEmit emit_str;
TypeVariableEmit emit_bool_type;
TypeVariableEmit emit_byte_type;
TypeVariableEmit emit_int_type;
TypeVariableEmit emit_nat_type;
TypeVariableEmit emit_real_type;
TypeVariableEmit emit_str_type;
TypeVariableEmit emit_u8_type;
TypeVariableEmit emit_i8_type;
TypeVariableEmit emit_i16_type;
TypeVariableEmit emit_u16_type;
TypeVariableEmit emit_i32_type;
TypeVariableEmit emit_u32_type;
TypeVariableEmit emit_f32_type;
TypeVariableEmit emit_type;
VoidArgEmit emit_array;
VoidArgEmit emit_function;
VoidArgEmit emit_plex;

View File

@ -28,6 +28,7 @@ rer_epilogue()
printf("BRK\n\n");
}
void
rer_emit_add()
{
@ -123,137 +124,127 @@ rer_emit_void()
{
}
i32
rer_emit_bool_type(const char *str, i32 length, bool local)
u32
rer_get_size(SymbolType t)
{
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
switch(t) {
case SYMBOL_BOOL: return 1;
case SYMBOL_BYTE: return 1;
case SYMBOL_INT: return 2;
case SYMBOL_NAT: return 2;
case SYMBOL_REAL: return 2;
case SYMBOL_STR: return 2;
case SYMBOL_U8: return 1;
case SYMBOL_I8: return 1;
case SYMBOL_I16: return 2;
case SYMBOL_U16: return 2;
case SYMBOL_I32: return 4;
case SYMBOL_U32: return 4;
case SYMBOL_F32: return 4;
default: break;
}
return 2;
return 0;
}
i32
rer_emit_byte_type(const char *str, i32 length, bool local)
void
rer_emit_primitive_type(SymbolType t, const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $1 } ", length, str);
else
printf("!{ @%.*s $1 } ", length, str);
return 1;
switch(t) {
case SYMBOL_BOOL: {
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
break;
}
case SYMBOL_BYTE: {
if(local)
printf("!{ &%.*s $1 } ", length, str);
else
printf("!{ @%.*s $1 } ", length, str);
break;
}
case SYMBOL_INT: {
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
break;
}
case SYMBOL_NAT: {
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
break;
}
case SYMBOL_REAL: {
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
break;
}
case SYMBOL_STR: {
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
break;
}
case SYMBOL_U8: {
if(local)
printf("!{ &%.*s $1 } ", length, str);
else
printf("!{ @%.*s $1 } ", length, str);
break;
}
case SYMBOL_I8: {
if(local)
printf("!{ &%.*s $1 } ", length, str);
else
printf("!{ @%.*s $1 } ", length, str);
break;
}
case SYMBOL_I16: {
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
break;
}
case SYMBOL_U16: {
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
break;
}
case SYMBOL_I32: {
if(local)
printf("!{ &%.*s $4 } ", length, str);
else
printf("!{ @%.*s $4 } ", length, str);
break;
}
case SYMBOL_U32: {
if(local)
printf("!{ &%.*s $4 } ", length, str);
else
printf("!{ @%.*s $4 } ", length, str);
break;
}
case SYMBOL_F32: {
if(local)
printf("!{ &%.*s $4 } ", length, str);
else
printf("!{ @%.*s $4 } ", length, str);
break;
}
default: break;
}
}
i32
rer_emit_int_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
return 2;
}
i32
rer_emit_nat_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
return 2;
}
i32
rer_emit_real_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
return 2;
}
i32
rer_emit_str_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
return 2;
}
i32
rer_emit_u8_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $1 } ", length, str);
else
printf("!{ @%.*s $1 } ", length, str);
return 1;
}
i32
rer_emit_i8_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $1 } ", length, str);
else
printf("!{ @%.*s $1 } ", length, str);
return 1;
}
i32
rer_emit_i16_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
return 2;
}
i32
rer_emit_u16_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
return 2;
}
i32
rer_emit_i32_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $4 } ", length, str);
else
printf("!{ @%.*s $4 } ", length, str);
return 4;
}
i32
rer_emit_u32_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $4 } ", length, str);
else
printf("!{ @%.*s $4 } ", length, str);
return 4;
}
i32
rer_emit_f32_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $4 } ", length, str);
else
printf("!{ @%.*s $4 } ", length, str);
return 4;
}
void
rer_emit_int(const char *str, i32 length)
{
@ -376,7 +367,6 @@ rer_emit_set_variable(Symbol *sym, bool local)
printf(";%.*s STA2 ", sym->name_length, sym->name);
}
void
rer_emit_write()
{
@ -564,42 +554,41 @@ rer_emit_print()
void
rer_emit_if()
{
printf("#03 JCN !{ ");
printf("#03 JCN !{ \n");
}
void
rer_emit_patch_if(i32 local_ifs)
{
printf("!&if_end.%d } ", local_ifs);
printf("!&if_end.%d } ", local_ifs);
}
void
rer_emit_patch_if_done(i32 local_ifs)
{
printf("&if_end.%d ", local_ifs);
printf("&if_end.%d \n", local_ifs);
}
void
rer_emit_while(i32 local_whiles)
{
printf("&while.%d ", local_whiles);
printf("&while.%d ", local_whiles);
}
void
rer_emit_while_postfix()
{
printf("#03 JCN !{ ");
printf("#03 JCN !{ \n");
}
void
rer_emit_patch_while(i32 local_whiles)
{
printf("!&while.%d } ", local_whiles);
printf("!&while.%d } \n", local_whiles);
}
Emitter rer_emitter()
Emitter
rer_emitter()
{
return (Emitter){
0,
@ -607,6 +596,7 @@ Emitter rer_emitter()
0,
0,
rer_emit_error,
rer_get_size,
rer_prolog,
rer_epilogue,
rer_emit_add,
@ -628,19 +618,7 @@ Emitter rer_emitter()
rer_emit_real,
rer_emit_byte,
rer_emit_str,
rer_emit_bool_type,
rer_emit_byte_type,
rer_emit_int_type,
rer_emit_nat_type,
rer_emit_real_type,
rer_emit_str_type,
rer_emit_u8_type,
rer_emit_i8_type,
rer_emit_i16_type,
rer_emit_u16_type,
rer_emit_i32_type,
rer_emit_u32_type,
rer_emit_f32_type,
rer_emit_primitive_type,
rer_emit_array,
rer_emit_function,
rer_emit_plex,

View File

@ -145,7 +145,6 @@ unsigned char __lib_undar[] = {
};
unsigned int __lib_undar_len = 1433;
void
uxn_emit_error(const char *str, i32 length, i32 line)
{
@ -169,9 +168,7 @@ void
uxn_epilogue()
{
printf("BRK\n\n");
for (u32 i = 0; i < __lib_undar_len; i++) {
putchar(__lib_undar[i]);
}
for(u32 i = 0; i < __lib_undar_len; i++) putchar(__lib_undar[i]);
}
void
@ -269,137 +266,127 @@ uxn_emit_void()
{
}
i32
uxn_emit_bool_type(const char *str, i32 length, bool local)
u32
uxn_get_size(SymbolType t)
{
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
switch(t) {
case SYMBOL_BOOL: return 1;
case SYMBOL_BYTE: return 1;
case SYMBOL_INT: return 2;
case SYMBOL_NAT: return 2;
case SYMBOL_REAL: return 2;
case SYMBOL_STR: return 2;
case SYMBOL_U8: return 1;
case SYMBOL_I8: return 1;
case SYMBOL_I16: return 2;
case SYMBOL_U16: return 2;
case SYMBOL_I32: return 4;
case SYMBOL_U32: return 4;
case SYMBOL_F32: return 4;
default: break;
}
return 2;
return 0;
}
i32
uxn_emit_byte_type(const char *str, i32 length, bool local)
void
uxn_emit_primitive_type(SymbolType t, const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $1 } ", length, str);
else
printf("!{ @%.*s $1 } ", length, str);
return 1;
switch(t) {
case SYMBOL_BOOL: {
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
break;
}
case SYMBOL_BYTE: {
if(local)
printf("!{ &%.*s $1 } ", length, str);
else
printf("!{ @%.*s $1 } ", length, str);
break;
}
case SYMBOL_INT: {
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
break;
}
case SYMBOL_NAT: {
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
break;
}
case SYMBOL_REAL: {
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
break;
}
case SYMBOL_STR: {
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
break;
}
case SYMBOL_U8: {
if(local)
printf("!{ &%.*s $1 } ", length, str);
else
printf("!{ @%.*s $1 } ", length, str);
break;
}
case SYMBOL_I8: {
if(local)
printf("!{ &%.*s $1 } ", length, str);
else
printf("!{ @%.*s $1 } ", length, str);
break;
}
case SYMBOL_I16: {
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
break;
}
case SYMBOL_U16: {
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
break;
}
case SYMBOL_I32: {
if(local)
printf("!{ &%.*s $4 } ", length, str);
else
printf("!{ @%.*s $4 } ", length, str);
break;
}
case SYMBOL_U32: {
if(local)
printf("!{ &%.*s $4 } ", length, str);
else
printf("!{ @%.*s $4 } ", length, str);
break;
}
case SYMBOL_F32: {
if(local)
printf("!{ &%.*s $4 } ", length, str);
else
printf("!{ @%.*s $4 } ", length, str);
break;
}
default: break;
}
}
i32
uxn_emit_int_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
return 2;
}
i32
uxn_emit_nat_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
return 2;
}
i32
uxn_emit_real_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
return 2;
}
i32
uxn_emit_str_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
return 2;
}
i32
uxn_emit_u8_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $1 } ", length, str);
else
printf("!{ @%.*s $1 } ", length, str);
return 1;
}
i32
uxn_emit_i8_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $1 } ", length, str);
else
printf("!{ @%.*s $1 } ", length, str);
return 1;
}
i32
uxn_emit_i16_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
return 2;
}
i32
uxn_emit_u16_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $2 } ", length, str);
else
printf("!{ @%.*s $2 } ", length, str);
return 2;
}
i32
uxn_emit_i32_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $4 } ", length, str);
else
printf("!{ @%.*s $4 } ", length, str);
return 4;
}
i32
uxn_emit_u32_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $4 } ", length, str);
else
printf("!{ @%.*s $4 } ", length, str);
return 4;
}
i32
uxn_emit_f32_type(const char *str, i32 length, bool local)
{
if(local)
printf("!{ &%.*s $4 } ", length, str);
else
printf("!{ @%.*s $4 } ", length, str);
return 4;
}
void
uxn_emit_int(const char *str, i32 length)
{
@ -715,36 +702,35 @@ uxn_emit_if()
void
uxn_emit_patch_if(i32 local_ifs)
{
printf("!&if_end.%d } ", local_ifs);
printf("!&if_end.%d } ", local_ifs);
}
void
uxn_emit_patch_if_done(i32 local_ifs)
{
printf("&if_end.%d \n", local_ifs);
printf("&if_end.%d \n", local_ifs);
}
void
uxn_emit_while(i32 local_whiles)
{
printf("&while.%d ", local_whiles);
printf("&while.%d ", local_whiles);
}
void
uxn_emit_while_postfix()
{
printf("#03 JCN !{ \n");
printf("#03 JCN !{ \n");
}
void
uxn_emit_patch_while(i32 local_whiles)
{
printf("!&while.%d } \n", local_whiles);
printf("!&while.%d } \n", local_whiles);
}
Emitter uxn_emitter()
Emitter
uxn_emitter()
{
return (Emitter){
0,
@ -752,6 +738,7 @@ Emitter uxn_emitter()
0,
0,
uxn_emit_error,
uxn_get_size,
uxn_prolog,
uxn_epilogue,
uxn_emit_add,
@ -773,19 +760,7 @@ Emitter uxn_emitter()
uxn_emit_real,
uxn_emit_byte,
uxn_emit_str,
uxn_emit_bool_type,
uxn_emit_byte_type,
uxn_emit_int_type,
uxn_emit_nat_type,
uxn_emit_real_type,
uxn_emit_str_type,
uxn_emit_u8_type,
uxn_emit_i8_type,
uxn_emit_i16_type,
uxn_emit_u16_type,
uxn_emit_i32_type,
uxn_emit_u32_type,
uxn_emit_f32_type,
uxn_emit_primitive_type,
uxn_emit_array,
uxn_emit_function,
uxn_emit_plex,

25
lexer.c
View File

@ -134,9 +134,7 @@ check_keyword(i32 start, i32 length, const char *rest, TokenType type)
{
i32 s1 = lexer.current - lexer.start;
i32 s2 = start + length;
if(s1 == s2 && sleq(lexer.start + start, rest, length)) {
return type;
}
if(s1 == s2 && sleq(lexer.start + start, rest, length)) return type;
return TOKEN_IDENTIFIER;
}
@ -234,9 +232,9 @@ identifierType()
case 'l':
return check_keyword(2, 2, "ex", TOKEN_KEYWORD_PLEX);
case 'u':
return check_keyword(2, 5, "tchar", TOKEN_KEYWORD_PUTCHAR);
return check_keyword(2, 5, "tchar", TOKEN_KEYWORD_PUTCHAR);
case 'r':
return check_keyword(2, 3, "int", TOKEN_KEYWORD_PRINT);
return check_keyword(2, 3, "int", TOKEN_KEYWORD_PRINT);
}
}
break;
@ -284,7 +282,14 @@ identifierType()
case 'h':
return check_keyword(2, 2, "is", TOKEN_KEYWORD_THIS);
case 'r':
return check_keyword(2, 2, "ue", TOKEN_KEYWORD_TRUE);
if(lexer.current - lexer.start > 2) {
switch(lexer.start[2]) {
case 'u':
return check_keyword(3, 1, "e", TOKEN_KEYWORD_TRUE);
case 'a':
return check_keyword(3, 2, "it", TOKEN_KEYWORD_TRAIT);
}
}
}
}
break;
@ -432,9 +437,13 @@ next_token()
case '=':
return make_token(match('=') ? TOKEN_EQ_EQ : TOKEN_EQ);
case '<':
return make_token(match('=') ? TOKEN_LTE : match('<') ? TOKEN_SLL : TOKEN_LT);
return make_token(match('=') ? TOKEN_LTE
: match('<') ? TOKEN_SLL
: TOKEN_LT);
case '>':
return make_token(match('=') ? TOKEN_GTE : match('>') ? TOKEN_SRL : TOKEN_GT);
return make_token(match('=') ? TOKEN_GTE
: match('>') ? TOKEN_SRL
: TOKEN_GT);
case '"':
return string();
}

View File

@ -86,7 +86,8 @@ typedef enum {
TOKEN_ARROW_RIGHT,
TOKEN_SLL,
TOKEN_SRL,
TOKEN_KEYWORD_PRINT
TOKEN_KEYWORD_PRINT,
TOKEN_KEYWORD_TRAIT
} TokenType;
typedef struct token_s Token;

36
test/mat-search.ul Normal file
View File

@ -0,0 +1,36 @@
nat[3,3,3] matrix = [1, 1, 1,
1, 1, 1,
1, 1, 1,
1, 1, 1,
1, 0, 1,
1, 1, 1,
1, 1, 1,
1, 1, 1,
1, 1, 1];
nat xSize = 3;
nat ySize = 3;
nat zSize = 3;
bool found = false;
for (nat x = 0; x < xSize; x++) {
for (nat y = 0; y < ySize; y++) {
for (nat z = 0; z < zSize; z++) {
if (matrix[x][y][z] == 0) {
print("found: [");
print(x as str);
print(",");
print(y as str);
print(",");
print(z as str);
print("]\n");
found = true;
break;
}
}
if (found) break;
}
if (found) break;
}