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; 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 * Parser
***************************************************/ ***************************************************/
@ -120,6 +150,84 @@ match(TokenType type)
return true; 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 expression();
void statement(); void statement();
void declaration(); void declaration();
@ -321,103 +429,38 @@ cast_type()
} }
} }
void u32
variable_declaration() variable_declaration(Symbol *def)
{ {
i32 size = 0; i32 size = 0;
TokenType tt = parser.previous.type; TokenType tt = parser.previous.type;
Token var = parser.current; Token var = parser.current;
SymbolType st = tokt_to_symt(tt);
Symbol *arg;
switch(tt) { if (st != SYMBOL_UNDEFINED) {
case TOKEN_TYPE_INT: { size = emitter.get_size(st);
size = emitter.emit_int_type(parser.current.start, parser.current.length, 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.depth);
scope_add_symbol(parser.current.start, parser.current.length, SYMBOL_INT, parser.current_type = st;
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;
} }
} else {
/* we need to look up the type */
} }
advance(); 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)) { if(match(TOKEN_EQ)) {
emitter.emit_set_value(); emitter.emit_set_value();
expression(); expression();
@ -427,6 +470,7 @@ variable_declaration()
consume(TOKEN_SEMICOLON); consume(TOKEN_SEMICOLON);
emitter.emit_end_statement(); emitter.emit_end_statement();
parser.current_type = SYMBOL_UNDEFINED; parser.current_type = SYMBOL_UNDEFINED;
return size;
} }
void void
@ -438,7 +482,7 @@ declaration()
* if not then * if not then
*/ */
if(is_type()) if(is_type())
variable_declaration(); variable_declaration(nil);
else else
statement(); statement();
} }
@ -681,11 +725,9 @@ get_rule(TokenType type)
return &rules[type]; return &rules[type];
} }
bool void
compile(Arena *a, Emitter e, char *source) emit_program(char *source)
{ {
arena = a;
emitter = e;
init_lexer(source); init_lexer(source);
advance(); advance();
scope_push(); scope_push();
@ -695,6 +737,16 @@ compile(Arena *a, Emitter e, char *source)
while(!match(TOKEN_EOF)) declaration(); while(!match(TOKEN_EOF)) declaration();
emitter.epilogue(); emitter.epilogue();
}
bool
compile(Arena *a, Emitter e, char *source)
{
arena = a;
emitter = e;
build_symbol_table(source);
emit_program(source);
return true; 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 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 Built in Types
Type Description Type Description

18
emit.h
View File

@ -4,11 +4,12 @@
#include "common.h" #include "common.h"
#include "libc.h" #include "libc.h"
typedef u32 (*SymbolSize)(SymbolType t);
typedef void (*SymbolEmit)(Symbol *sym); typedef void (*SymbolEmit)(Symbol *sym);
typedef void (*ErrorMsg)(const char *str, i32 length, i32 line); typedef void (*ErrorMsg)(const char *str, i32 length, i32 line);
typedef void (*VoidArgEmit)(); typedef void (*VoidArgEmit)();
typedef void (*StrArgEmit)(const char *str, i32 length); 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 (*ConstEmit)(const char *str, i32 length, bool local);
typedef void (*VarEmit)(Symbol *sym, bool local); typedef void (*VarEmit)(Symbol *sym, bool local);
typedef void (*I32ArgEmit)(i32 val); typedef void (*I32ArgEmit)(i32 val);
@ -20,6 +21,7 @@ struct emitter_s {
i32 loops; i32 loops;
i32 loop_depth; i32 loop_depth;
ErrorMsg error; ErrorMsg error;
SymbolSize get_size;
VoidArgEmit prolog; VoidArgEmit prolog;
VoidArgEmit epilogue; VoidArgEmit epilogue;
VoidArgEmit emit_add; VoidArgEmit emit_add;
@ -41,19 +43,7 @@ struct emitter_s {
StrArgEmit emit_real; StrArgEmit emit_real;
StrArgEmit emit_byte; StrArgEmit emit_byte;
StrArgEmit emit_str; StrArgEmit emit_str;
TypeVariableEmit emit_bool_type; TypeVariableEmit emit_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;
VoidArgEmit emit_array; VoidArgEmit emit_array;
VoidArgEmit emit_function; VoidArgEmit emit_function;
VoidArgEmit emit_plex; VoidArgEmit emit_plex;

View File

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

View File

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

21
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 s1 = lexer.current - lexer.start;
i32 s2 = start + length; i32 s2 = start + length;
if(s1 == s2 && sleq(lexer.start + start, rest, length)) { if(s1 == s2 && sleq(lexer.start + start, rest, length)) return type;
return type;
}
return TOKEN_IDENTIFIER; return TOKEN_IDENTIFIER;
} }
@ -284,7 +282,14 @@ identifierType()
case 'h': case 'h':
return check_keyword(2, 2, "is", TOKEN_KEYWORD_THIS); return check_keyword(2, 2, "is", TOKEN_KEYWORD_THIS);
case 'r': 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; break;
@ -432,9 +437,13 @@ next_token()
case '=': case '=':
return make_token(match('=') ? TOKEN_EQ_EQ : TOKEN_EQ); return make_token(match('=') ? TOKEN_EQ_EQ : TOKEN_EQ);
case '<': case '<':
return make_token(match('=') ? TOKEN_LTE : match('<') ? TOKEN_SLL : TOKEN_LT); return make_token(match('=') ? TOKEN_LTE
: match('<') ? TOKEN_SLL
: TOKEN_LT);
case '>': case '>':
return make_token(match('=') ? TOKEN_GTE : match('>') ? TOKEN_SRL : TOKEN_GT); return make_token(match('=') ? TOKEN_GTE
: match('>') ? TOKEN_SRL
: TOKEN_GT);
case '"': case '"':
return string(); return string();
} }

View File

@ -86,7 +86,8 @@ typedef enum {
TOKEN_ARROW_RIGHT, TOKEN_ARROW_RIGHT,
TOKEN_SLL, TOKEN_SLL,
TOKEN_SRL, TOKEN_SRL,
TOKEN_KEYWORD_PRINT TOKEN_KEYWORD_PRINT,
TOKEN_KEYWORD_TRAIT
} TokenType; } TokenType;
typedef struct token_s Token; 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;
}