WIP function calls
This commit is contained in:
parent
e968cb6725
commit
bb764a3017
120
compiler.c
120
compiler.c
|
|
@ -17,8 +17,10 @@ scope_push()
|
|||
Scope *child = aalloc(arena, sizeof(Scope));
|
||||
child->symbols = List_init(arena);
|
||||
child->parent = parser.current_scope;
|
||||
child->locals_offset = 0;
|
||||
|
||||
parser.current_scope = child;
|
||||
parser.depth++;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -26,6 +28,7 @@ scope_pop()
|
|||
{
|
||||
Scope *prev = parser.current_scope->parent;
|
||||
parser.current_scope = prev;
|
||||
parser.depth--;
|
||||
}
|
||||
|
||||
Symbol *
|
||||
|
|
@ -37,7 +40,7 @@ scope_get_symbol(Scope *scope, const char *name, u32 name_length)
|
|||
count = scope->symbols->count;
|
||||
for(i = 0; i < count; i++) {
|
||||
Symbol *sym = List_get(scope->symbols, i);
|
||||
if(sleq(sym->name, name, name_length)) return sym;
|
||||
if(sym->name_length == name_length && sleq(sym->name, name, name_length)) return sym;
|
||||
}
|
||||
|
||||
return scope_get_symbol(scope->parent, name, name_length);
|
||||
|
|
@ -47,7 +50,12 @@ Symbol *
|
|||
scope_add_symbol(const char *name, u32 name_length, SymbolType type, u32 size)
|
||||
{
|
||||
Symbol *sym = scope_get_symbol(parser.current_scope, name, name_length);
|
||||
if(sym != nil) return sym;
|
||||
if(sym != nil) {
|
||||
if(parser.pass)
|
||||
return sym;
|
||||
else
|
||||
emitter.error("duplicate found", 14, parser.previous.line);
|
||||
}
|
||||
|
||||
sym = aalloc(arena, sizeof(Symbol));
|
||||
scpy(sym->name, name, name_length);
|
||||
|
|
@ -55,12 +63,16 @@ scope_add_symbol(const char *name, u32 name_length, SymbolType type, u32 size)
|
|||
sym->type = type;
|
||||
sym->secondary_type = SYMBOL_VOID;
|
||||
sym->size = size;
|
||||
sym->ref = 0;
|
||||
if(type == SYMBOL_PLEX || type == SYMBOL_METHOD || type == SYMBOL_TRAIT) {
|
||||
sym->ref = parser.current_scope->locals_offset;
|
||||
parser.current_scope->locals_offset += size;
|
||||
if(type == SYMBOL_PLEX || type == SYMBOL_METHOD || type == SYMBOL_TRAIT ||
|
||||
type == SYMBOL_FUNCTION) {
|
||||
sym->args = List_init(arena);
|
||||
sym->fields = List_init(arena);
|
||||
}
|
||||
|
||||
if(type == SYMBOL_PLEX || type == SYMBOL_METHOD || type == SYMBOL_TRAIT)
|
||||
sym->fields = List_init(arena);
|
||||
|
||||
List_push(arena, parser.current_scope->symbols, sym, sizeof(Symbol));
|
||||
|
||||
return sym;
|
||||
|
|
@ -80,7 +92,7 @@ is_type()
|
|||
}
|
||||
|
||||
SymbolType
|
||||
tokt_to_symt(TokenType t)
|
||||
token_type_to_sym_type(TokenType t)
|
||||
{
|
||||
switch(t) {
|
||||
case TOKEN_TYPE_BOOL:
|
||||
|
|
@ -153,7 +165,7 @@ match(TokenType type)
|
|||
void
|
||||
expect(TokenType type)
|
||||
{
|
||||
if(!match(type)) {
|
||||
if(!consume(type)) {
|
||||
emitter.error(parser.previous.start, parser.previous.length,
|
||||
parser.previous.line);
|
||||
}
|
||||
|
|
@ -185,21 +197,31 @@ define_function()
|
|||
scope_push();
|
||||
|
||||
expect(TOKEN_LPAREN);
|
||||
advance();
|
||||
|
||||
/* parse the args */
|
||||
while(!match(TOKEN_RPAREN)) size += variable_declaration(fn);
|
||||
while(!check(TOKEN_LBRACE)) {
|
||||
size += variable_declaration(fn);
|
||||
advance();
|
||||
advance();
|
||||
}
|
||||
|
||||
if(!match(TOKEN_LBRACE)) {
|
||||
fn->secondary_type = tokt_to_symt(parser.previous.type);
|
||||
if(is_type()) {
|
||||
/* get return slot */
|
||||
fn->secondary_type = token_type_to_sym_type(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);
|
||||
while(!match(TOKEN_RBRACE)) {
|
||||
if(is_type() && parser.current.type == TOKEN_IDENTIFIER)
|
||||
size += variable_declaration(fn);
|
||||
advance();
|
||||
}
|
||||
|
||||
fn->size = size;
|
||||
scope_pop();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -330,6 +352,11 @@ variable()
|
|||
parser.previous.line);
|
||||
}
|
||||
|
||||
if (sym->type == SYMBOL_FUNCTION) {
|
||||
parser.call_fn = sym;
|
||||
return;
|
||||
}
|
||||
|
||||
parser.current_type = sym->type;
|
||||
if(match(TOKEN_EQ)) {
|
||||
expression();
|
||||
|
|
@ -435,23 +462,22 @@ variable_declaration(Symbol *def)
|
|||
i32 size = 0;
|
||||
TokenType tt = parser.previous.type;
|
||||
Token var = parser.current;
|
||||
SymbolType st = tokt_to_symt(tt);
|
||||
Symbol *arg;
|
||||
SymbolType st = token_type_to_sym_type(tt);
|
||||
Symbol *variable;
|
||||
|
||||
if(st != SYMBOL_UNDEFINED) {
|
||||
size = emitter.get_size(st);
|
||||
arg = scope_add_symbol(parser.current.start, parser.current.length,
|
||||
st, size);
|
||||
variable =
|
||||
scope_add_symbol(parser.current.start, parser.current.length, st, size);
|
||||
if(def) {
|
||||
List_push(arena, def->args, arg, sizeof(Symbol));
|
||||
List_push(arena, def->args, variable, sizeof(Symbol));
|
||||
} else {
|
||||
emitter.emit_type(st, parser.current.start, parser.current.length,
|
||||
parser.depth);
|
||||
emitter.emit_type(variable, parser.depth);
|
||||
parser.current_type = st;
|
||||
}
|
||||
} else {
|
||||
/* we need to look up the type */
|
||||
|
||||
emitter.error("Not implemented", 16, parser.previous.line);
|
||||
}
|
||||
|
||||
advance();
|
||||
|
|
@ -476,16 +502,12 @@ variable_declaration(Symbol *def)
|
|||
void
|
||||
declaration()
|
||||
{
|
||||
/**
|
||||
* maybe a Plex?
|
||||
* lookup plex defs
|
||||
* if not then
|
||||
*/
|
||||
if(is_type())
|
||||
if(is_type()) {
|
||||
variable_declaration(nil);
|
||||
else
|
||||
}else{
|
||||
statement();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_statement()
|
||||
|
|
@ -552,6 +574,33 @@ block()
|
|||
consume(TOKEN_RBRACE);
|
||||
}
|
||||
|
||||
void
|
||||
function()
|
||||
{
|
||||
Symbol *sym = scope_get_symbol(parser.current_scope, parser.previous.start,
|
||||
parser.previous.length);
|
||||
emitter.emit_function(sym);
|
||||
while(!check(TOKEN_LBRACE)) {
|
||||
advance();
|
||||
}
|
||||
block();
|
||||
emitter.emit_arena_fn_return();
|
||||
}
|
||||
|
||||
void call() {
|
||||
if (!check(TOKEN_RPAREN)) {
|
||||
do {
|
||||
expression();
|
||||
} while (match(TOKEN_COMMA));
|
||||
}
|
||||
consume(TOKEN_RPAREN);
|
||||
|
||||
emitter.emit_arena_fn_call(parser.call_fn);
|
||||
parser.current_type = parser.call_fn->secondary_type;
|
||||
advance();
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
statement()
|
||||
{
|
||||
|
|
@ -559,6 +608,9 @@ statement()
|
|||
scope_push();
|
||||
block();
|
||||
scope_pop();
|
||||
} else if(match(TOKEN_KEYWORD_FN)) {
|
||||
advance();
|
||||
function();
|
||||
} else if(match(TOKEN_KEYWORD_IF)) {
|
||||
if_statement();
|
||||
} else if(match(TOKEN_KEYWORD_WHILE)) {
|
||||
|
|
@ -618,6 +670,12 @@ unary()
|
|||
ParseRule rules[] = {
|
||||
/* TOKEN_ERROR */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_EOF */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_LPAREN */ {grouping, call, PREC_CALL},
|
||||
/* TOKEN_RPAREN */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_LBRACE */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_RBRACE */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_LBRACKET */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_RBRACKET */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_IDENTIFIER */ {variable, nil, PREC_NONE},
|
||||
/* TOKEN_LITERAL_INT */ {number, nil, PREC_NONE},
|
||||
/* TOKEN_LITERAL_NAT */ {number, nil, PREC_NONE},
|
||||
|
|
@ -689,12 +747,6 @@ ParseRule rules[] = {
|
|||
/* TOKEN_COLON */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_CARET */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_SEMICOLON */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_LPAREN */ {grouping, nil, PREC_NONE},
|
||||
/* TOKEN_RPAREN */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_LBRACE */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_RBRACE */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_LBRACKET */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_RBRACKET */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_ARROW_RIGHT */ {nil, nil, PREC_NONE},
|
||||
/* TOKEN_SLL */ {nil, binary, PREC_NONE},
|
||||
/* TOKEN_SRL */ {nil, binary, PREC_NONE},
|
||||
|
|
@ -730,7 +782,6 @@ emit_program(char *source)
|
|||
{
|
||||
init_lexer(source);
|
||||
advance();
|
||||
scope_push();
|
||||
|
||||
emitter.prolog();
|
||||
|
||||
|
|
@ -746,6 +797,7 @@ compile(Arena *a, Emitter e, char *source)
|
|||
emitter = e;
|
||||
|
||||
build_symbol_table(source);
|
||||
parser.pass++;
|
||||
emit_program(source);
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ typedef struct parse_rule_s ParseRule;
|
|||
struct scope_s {
|
||||
Scope *parent; /* pointer to this scopes parent to "bubble up"*/
|
||||
List *symbols; /* list of symbols that live in this scope */
|
||||
u32 locals_offset;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
|
|
@ -38,11 +39,14 @@ struct parse_rule_s {
|
|||
};
|
||||
|
||||
struct parser_s {
|
||||
Symbol *call_fn;
|
||||
Scope *current_scope;
|
||||
Token current;
|
||||
Token previous;
|
||||
SymbolType current_type;
|
||||
u32 depth;
|
||||
u8 pass;
|
||||
bool main_found;
|
||||
};
|
||||
|
||||
bool compile(Arena *a, Emitter e, char *source);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
A permacomputing & game oriented language.
|
||||
A permacomputing and game oriented language designed for constrained systems.
|
||||
|
||||
> Permacomputing is a design practice that encourages the maximization of hardware lifespan, minimization of energy usage and focuses on the use of already available computational resources. It values maintenance and refactoring of systems to keep them efficient, instead of planned obsolescence, permacomputing practices planned longevity. It is about using computation only when it has a strengthening effect on ecosystems.
|
||||
|
||||
|
|
|
|||
8
emit.h
8
emit.h
|
|
@ -9,7 +9,6 @@ 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 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);
|
||||
|
|
@ -43,9 +42,9 @@ struct emitter_s {
|
|||
StrArgEmit emit_real;
|
||||
StrArgEmit emit_byte;
|
||||
StrArgEmit emit_str;
|
||||
TypeVariableEmit emit_type;
|
||||
VarEmit emit_type;
|
||||
VoidArgEmit emit_array;
|
||||
VoidArgEmit emit_function;
|
||||
SymbolEmit emit_function;
|
||||
VoidArgEmit emit_plex;
|
||||
VoidArgEmit emit_method;
|
||||
VoidArgEmit emit_trait;
|
||||
|
|
@ -80,7 +79,8 @@ struct emitter_s {
|
|||
VoidArgEmit emit_strbuf_init;
|
||||
VoidArgEmit emit_strbuf_append;
|
||||
VoidArgEmit emit_strbuf_to_str;
|
||||
VoidArgEmit emit_arena_fn_call;
|
||||
SymbolEmit emit_arena_fn_call;
|
||||
VoidArgEmit emit_arena_fn_return;
|
||||
VoidArgEmit emit_arena_fn_return_plex;
|
||||
VoidArgEmit emit_arena_fn_return_array;
|
||||
VoidArgEmit emit_arena_fn_return_strbuf;
|
||||
|
|
|
|||
154
emit/rer/emit.c
154
emit/rer/emit.c
|
|
@ -1,12 +1,12 @@
|
|||
|
||||
#include "../../emit.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
void
|
||||
rer_emit_error(const char *str, i32 length, i32 line)
|
||||
{
|
||||
printf("Error at line: %d > %.*s\n ", line, length, str);
|
||||
fprintf(stderr, "\n===\nError at line: %d > %.*s\n===\n", line, length, str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
@ -28,7 +28,6 @@ rer_epilogue()
|
|||
printf("BRK\n\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rer_emit_add()
|
||||
{
|
||||
|
|
@ -128,121 +127,103 @@ u32
|
|||
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;
|
||||
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)
|
||||
rer_emit_primitive_type(Symbol *sym, bool local)
|
||||
{
|
||||
switch(t) {
|
||||
case SYMBOL_BOOL: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
if(sym->ref)
|
||||
printf("STH2kr #%04x ADD2 STA2\n", sym->ref);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
printf("STH2kr STA2\n");
|
||||
else
|
||||
switch(sym->type) {
|
||||
case SYMBOL_BOOL: {
|
||||
printf("!{ @%.*s $2 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_BYTE: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
printf("!{ @%.*s $1 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_INT: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
printf("!{ @%.*s $2 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_NAT: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
printf("!{ @%.*s $2 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_REAL: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
printf("!{ @%.*s $2 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_STR: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
printf("!{ @%.*s $2 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_U8: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
printf("!{ @%.*s $1 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_I8: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
printf("!{ @%.*s $1 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_I16: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
printf("!{ @%.*s $2 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_U16: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
printf("!{ @%.*s $2 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_I32: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
printf("!{ @%.*s $4 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_U32: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
printf("!{ @%.*s $4 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_F32: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
printf("!{ @%.*s $4 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
void
|
||||
|
|
@ -303,8 +284,21 @@ rer_emit_array()
|
|||
}
|
||||
|
||||
void
|
||||
rer_emit_function()
|
||||
rer_emit_function(Symbol *sym)
|
||||
{
|
||||
USED(sym);
|
||||
}
|
||||
|
||||
void
|
||||
rer_emit_arena_fn_return()
|
||||
{
|
||||
printf("&return\n\t\tPOP2r JMP2r\n\n");
|
||||
}
|
||||
|
||||
void
|
||||
rer_emit_arena_fn_call(Symbol *sym)
|
||||
{
|
||||
USED(sym);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -353,7 +347,10 @@ void
|
|||
rer_emit_variable(Symbol *sym, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf(",/%.*s LDR2 ", sym->name_length, sym->name);
|
||||
if(sym->ref)
|
||||
printf("STH2kr #%04x ADD2 LDA2 ", sym->ref);
|
||||
else
|
||||
printf("STH2kr LDA2 ");
|
||||
else
|
||||
printf(";%.*s LDA2 ", sym->name_length, sym->name);
|
||||
}
|
||||
|
|
@ -362,7 +359,10 @@ void
|
|||
rer_emit_set_variable(Symbol *sym, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf(",/%.*s STR2 ", sym->name_length, sym->name);
|
||||
if(sym->ref)
|
||||
printf("STH2kr #%04x ADD2 STA2 ", sym->ref);
|
||||
else
|
||||
printf("STH2kr STA2 ");
|
||||
else
|
||||
printf(";%.*s STA2 ", sym->name_length, sym->name);
|
||||
}
|
||||
|
|
@ -477,11 +477,6 @@ rer_emit_strbuf_to_str()
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
rer_emit_arena_fn_call()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rer_emit_arena_fn_return_plex()
|
||||
{
|
||||
|
|
@ -656,6 +651,7 @@ rer_emitter()
|
|||
rer_emit_strbuf_append,
|
||||
rer_emit_strbuf_to_str,
|
||||
rer_emit_arena_fn_call,
|
||||
rer_emit_arena_fn_return,
|
||||
rer_emit_arena_fn_return_plex,
|
||||
rer_emit_arena_fn_return_array,
|
||||
rer_emit_arena_fn_return_strbuf,
|
||||
|
|
|
|||
238
emit/uxn/emit.c
238
emit/uxn/emit.c
|
|
@ -7,18 +7,42 @@
|
|||
#define UXN_OP_K (1 << 7)
|
||||
|
||||
enum uxn_opcode {
|
||||
/* Stack I */ /* Logic */ /* Memory I */ /* Arithmetic*/
|
||||
BRK = 0x00, EQU = 0x08, LDZ = 0x10, ADD = 0x18,
|
||||
INC = 0x01, NEQ = 0x09, STZ = 0x11, SUB = 0x19,
|
||||
POP = 0x02, GTH = 0x0A, LDR = 0x12, MUL = 0x1A,
|
||||
NIP = 0x03, LTH = 0x0B, STR = 0x13, DIV = 0x1B,
|
||||
/* Stack II */ /* Stash */ /* Memory II */ /* Bitwise */
|
||||
SWP = 0x04, JMP = 0x0C, LDA = 0x14, AND = 0x1C,
|
||||
ROT = 0x05, JCN = 0x0D, STA = 0x15, ORA = 0x1D,
|
||||
DUP = 0x06, JSR = 0x0E, DEI = 0x16, EOR = 0x1E,
|
||||
OVR = 0x07, STH = 0x0F, DEO = 0x17, SFT = 0x1F,
|
||||
|
||||
LIT = 0x80, JCI = 0x20, JMI = 0x40, JSI = 0x60,
|
||||
BRK = 0x00,
|
||||
EQU = 0x08,
|
||||
LDZ = 0x10,
|
||||
ADD = 0x18,
|
||||
INC = 0x01,
|
||||
NEQ = 0x09,
|
||||
STZ = 0x11,
|
||||
SUB = 0x19,
|
||||
POP = 0x02,
|
||||
GTH = 0x0A,
|
||||
LDR = 0x12,
|
||||
MUL = 0x1A,
|
||||
NIP = 0x03,
|
||||
LTH = 0x0B,
|
||||
STR = 0x13,
|
||||
DIV = 0x1B,
|
||||
SWP = 0x04,
|
||||
JMP = 0x0C,
|
||||
LDA = 0x14,
|
||||
AND = 0x1C,
|
||||
ROT = 0x05,
|
||||
JCN = 0x0D,
|
||||
STA = 0x15,
|
||||
ORA = 0x1D,
|
||||
DUP = 0x06,
|
||||
JSR = 0x0E,
|
||||
DEI = 0x16,
|
||||
EOR = 0x1E,
|
||||
OVR = 0x07,
|
||||
STH = 0x0F,
|
||||
DEO = 0x17,
|
||||
SFT = 0x1F,
|
||||
LIT = 0x80,
|
||||
JCI = 0x20,
|
||||
JMI = 0x40,
|
||||
JSI = 0x60,
|
||||
};
|
||||
|
||||
unsigned char __lib_undar[] = {
|
||||
|
|
@ -141,14 +165,13 @@ unsigned char __lib_undar[] = {
|
|||
0x20, 0x49, 0x4e, 0x43, 0x32, 0x20, 0x21, 0x2f, 0x3c, 0x70, 0x72, 0x69,
|
||||
0x6e, 0x74, 0x3e, 0x0a, 0x0a, 0x40, 0x6d, 0x65, 0x6d, 0x5f, 0x6c, 0x65,
|
||||
0x6e, 0x67, 0x74, 0x68, 0x5f, 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x0a,
|
||||
0x40, 0x6d, 0x65, 0x6d, 0x5f
|
||||
};
|
||||
0x40, 0x6d, 0x65, 0x6d, 0x5f};
|
||||
unsigned int __lib_undar_len = 1433;
|
||||
|
||||
void
|
||||
uxn_emit_error(const char *str, i32 length, i32 line)
|
||||
{
|
||||
printf("Error at line: %d > %.*s\n ", line, length, str);
|
||||
fprintf(stderr, "\n===\nError at line: %d '%.*s'\n===\n", line, length, str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
@ -161,13 +184,12 @@ uxn_mem(u32 a)
|
|||
void
|
||||
uxn_prolog()
|
||||
{
|
||||
printf("|100\n");
|
||||
printf("|100\n\tLIT2r 0000 main POP2r BRK\n\n");
|
||||
}
|
||||
|
||||
void
|
||||
uxn_epilogue()
|
||||
{
|
||||
printf("BRK\n\n");
|
||||
for(u32 i = 0; i < __lib_undar_len; i++) putchar(__lib_undar[i]);
|
||||
}
|
||||
|
||||
|
|
@ -270,121 +292,103 @@ u32
|
|||
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;
|
||||
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)
|
||||
uxn_emit_type(Symbol *sym, bool local)
|
||||
{
|
||||
switch(t) {
|
||||
case SYMBOL_BOOL: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
if(sym->ref)
|
||||
printf("\tSTH2kr #%04x ADD2 LDA2\n", sym->ref);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
printf("\tSTH2kr LDA2\n");
|
||||
else
|
||||
switch(sym->type) {
|
||||
case SYMBOL_BOOL: {
|
||||
printf("!{ @%.*s $2 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_BYTE: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
printf("!{ @%.*s $1 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_INT: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
printf("!{ @%.*s $2 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_NAT: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
printf("!{ @%.*s $2 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_REAL: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
printf("!{ @%.*s $2 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_STR: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
printf("!{ @%.*s $2 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_U8: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
printf("!{ @%.*s $1 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_I8: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $1 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $1 } ", length, str);
|
||||
printf("!{ @%.*s $1 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_I16: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
printf("!{ @%.*s $2 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_U16: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $2 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $2 } ", length, str);
|
||||
printf("!{ @%.*s $2 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_I32: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
printf("!{ @%.*s $4 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_U32: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
printf("!{ @%.*s $4 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
case SYMBOL_F32: {
|
||||
if(local)
|
||||
printf("!{ &%.*s $4 } ", length, str);
|
||||
else
|
||||
printf("!{ @%.*s $4 } ", length, str);
|
||||
printf("!{ @%.*s $4 } ", sym->name_length, sym->name);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
void
|
||||
|
|
@ -444,9 +448,51 @@ uxn_emit_array()
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
uxn_emit_function()
|
||||
bool
|
||||
fn_loop_emit_args(void *data)
|
||||
{
|
||||
Symbol *sym = ((Symbol *)data);
|
||||
|
||||
if(sym->ref)
|
||||
printf("\tSTH2kr #%04x ADD2 STA2\n", sym->ref);
|
||||
else
|
||||
printf("\tSTH2kr STA2\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
fn_loop_emit_args_comment(void *data)
|
||||
{
|
||||
Symbol *sym = ((Symbol *)data);
|
||||
printf("%.*s ", sym->name_length, sym->name);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
uxn_emit_function(Symbol *sym)
|
||||
{
|
||||
printf("@%.*s_ ( ", sym->name_length, sym->name);
|
||||
List_map(sym->args, fn_loop_emit_args_comment);
|
||||
printf(" -- ");
|
||||
if(sym->secondary_type != SYMBOL_UNDEFINED &&
|
||||
sym->secondary_type != SYMBOL_VOID)
|
||||
printf(" res ");
|
||||
printf(")\n");
|
||||
printf("\tOVR2r LIT2r #%04x SUB2r\n", sym->size);
|
||||
List_map(sym->args, fn_loop_emit_args);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void
|
||||
uxn_emit_arena_fn_return()
|
||||
{
|
||||
printf("\t&return\n\t\tPOP2r JMP2r\n\n");
|
||||
}
|
||||
|
||||
void
|
||||
uxn_emit_arena_fn_call(Symbol *sym)
|
||||
{
|
||||
printf("%.*s_ ", sym->name_length, sym->name);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -495,7 +541,10 @@ void
|
|||
uxn_emit_variable(Symbol *sym, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf(",/%.*s LDR2 ", sym->name_length, sym->name);
|
||||
if(sym->ref)
|
||||
printf("\tSTH2kr #%04x ADD2 LDA2 ", sym->ref);
|
||||
else
|
||||
printf("\tSTH2kr LDA2 ");
|
||||
else
|
||||
printf(";%.*s LDA2 ", sym->name_length, sym->name);
|
||||
}
|
||||
|
|
@ -504,7 +553,10 @@ void
|
|||
uxn_emit_set_variable(Symbol *sym, bool local)
|
||||
{
|
||||
if(local)
|
||||
printf(",/%.*s STR2 ", sym->name_length, sym->name);
|
||||
if(sym->ref)
|
||||
printf("\tSTH2kr #%04x ADD2 STA2 ", sym->ref);
|
||||
else
|
||||
printf("\tSTH2kr STA2 ");
|
||||
else
|
||||
printf(";%.*s STA2 ", sym->name_length, sym->name);
|
||||
}
|
||||
|
|
@ -619,11 +671,6 @@ uxn_emit_strbuf_to_str()
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
uxn_emit_arena_fn_call()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
uxn_emit_arena_fn_return_plex()
|
||||
{
|
||||
|
|
@ -760,7 +807,7 @@ uxn_emitter()
|
|||
uxn_emit_real,
|
||||
uxn_emit_byte,
|
||||
uxn_emit_str,
|
||||
uxn_emit_primitive_type,
|
||||
uxn_emit_type,
|
||||
uxn_emit_array,
|
||||
uxn_emit_function,
|
||||
uxn_emit_plex,
|
||||
|
|
@ -798,6 +845,7 @@ uxn_emitter()
|
|||
uxn_emit_strbuf_append,
|
||||
uxn_emit_strbuf_to_str,
|
||||
uxn_emit_arena_fn_call,
|
||||
uxn_emit_arena_fn_return,
|
||||
uxn_emit_arena_fn_return_plex,
|
||||
uxn_emit_arena_fn_return_array,
|
||||
uxn_emit_arena_fn_return_strbuf,
|
||||
|
|
|
|||
12
lexer.h
12
lexer.h
|
|
@ -6,6 +6,12 @@
|
|||
typedef enum {
|
||||
TOKEN_ERROR,
|
||||
TOKEN_EOF,
|
||||
TOKEN_LPAREN,
|
||||
TOKEN_RPAREN,
|
||||
TOKEN_LBRACE,
|
||||
TOKEN_RBRACE,
|
||||
TOKEN_LBRACKET,
|
||||
TOKEN_RBRACKET,
|
||||
TOKEN_IDENTIFIER,
|
||||
TOKEN_LITERAL_INT,
|
||||
TOKEN_LITERAL_NAT,
|
||||
|
|
@ -77,12 +83,6 @@ typedef enum {
|
|||
TOKEN_COLON,
|
||||
TOKEN_CARET,
|
||||
TOKEN_SEMICOLON,
|
||||
TOKEN_LPAREN,
|
||||
TOKEN_RPAREN,
|
||||
TOKEN_LBRACE,
|
||||
TOKEN_RBRACE,
|
||||
TOKEN_LBRACKET,
|
||||
TOKEN_RBRACKET,
|
||||
TOKEN_ARROW_RIGHT,
|
||||
TOKEN_SLL,
|
||||
TOKEN_SRL,
|
||||
|
|
|
|||
18
list.c
18
list.c
|
|
@ -41,9 +41,7 @@ List_push(Arena *arena, List *list, void *data, u32 data_size)
|
|||
list->count++;
|
||||
|
||||
dest = node_value(node);
|
||||
if (data && data_size > 0) {
|
||||
mcpy(dest, data, data_size);
|
||||
}
|
||||
if(data && data_size > 0) mcpy(dest, data, data_size);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
|
@ -69,9 +67,7 @@ List_get(List *list, u32 index)
|
|||
if(!list || index >= list->count) return nil;
|
||||
|
||||
curr = list->head;
|
||||
for (i = 0; i < index; i++) {
|
||||
curr = curr->next;
|
||||
}
|
||||
for(i = 0; i < index; i++) curr = curr->next;
|
||||
|
||||
return node_value(curr);
|
||||
}
|
||||
|
|
@ -95,10 +91,14 @@ List_find(List *list, compare_fn compare, void *target)
|
|||
curr = list->head;
|
||||
while(curr) {
|
||||
data = node_value(curr);
|
||||
if (compare(data, target)) {
|
||||
return data;
|
||||
}
|
||||
if(compare(data, target)) return data;
|
||||
curr = curr->next;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
void *
|
||||
List_last(List *list)
|
||||
{
|
||||
return node_value(list->tail);
|
||||
}
|
||||
|
|
|
|||
1
list.h
1
list.h
|
|
@ -26,5 +26,6 @@ void List_map(List *list, list_iter_fn func);
|
|||
void *List_find(List *list, compare_fn compare, void *target);
|
||||
void *List_get(List *list, u32 index);
|
||||
void List_set(List *list, u32 index, void *data, u32 size);
|
||||
void *List_last(List *list);
|
||||
|
||||
#endif
|
||||
14
test/add.ul
14
test/add.ul
|
|
@ -1,10 +1,12 @@
|
|||
/**
|
||||
* Add two numbers together
|
||||
*/
|
||||
function add(int a, int b) int {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
function main() {
|
||||
print(add(1, 1) as str);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add two numbers together
|
||||
*/
|
||||
function add(nat a, nat b) nat {
|
||||
return a + b;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
str msg = " damage inflicted!\n"
|
||||
nat AT = 14;
|
||||
nat accuracy = 150;
|
||||
|
||||
nat dmg = ((AT * accuracy) / 20) - 3;
|
||||
|
||||
print(dmg as str);
|
||||
print(msg);
|
||||
|
|
@ -1,8 +1,109 @@
|
|||
str msg = " damage inflicted!\n"
|
||||
nat AT = 14;
|
||||
nat accuracy = 150;
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
const str nl = "\n";
|
||||
const str terminal_namespace = "/dev/term/0";
|
||||
|
||||
nat dmg = ((AT * accuracy) / 20) - 3;
|
||||
plex Terminal {
|
||||
nat handle;
|
||||
}
|
||||
|
||||
print(dmg as str);
|
||||
print(msg);
|
||||
/**
|
||||
* Print with a newline
|
||||
*/
|
||||
function pln(str string) {
|
||||
Terminal term = open(terminal_namespace, 0);
|
||||
write(term, string, string.length);
|
||||
write(term, nl, nl.length);
|
||||
// implied return because it is a void function.
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatinates 2 strings
|
||||
*/
|
||||
function concat(str src1, str src2) str {
|
||||
str result = malloc(src1.length + src2.length);
|
||||
// note result[0].ref is much different than result.ref[0] !
|
||||
// result[0].ref means the pointer at char 0 (pointer to first char)
|
||||
memcpy(result[0].ref, src1.ref);
|
||||
memcpy(result[src1.length].ref, src2.ref);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* finds index of string, -1 if not found
|
||||
*/
|
||||
function str_index_of(str haystack, byte needle) int {
|
||||
int i = -1;
|
||||
for (byte c in haystack) {
|
||||
if (c == needle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if 2 strings are equal
|
||||
*/
|
||||
function str_eq(str src1, str src2) bool {
|
||||
if (src1.length != src2.length) return false;
|
||||
do (int i=0; src1.length; i++) {
|
||||
if (src1[i] != src2[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Slice string
|
||||
*/
|
||||
function str_slice(str src, int start, int stop) str {
|
||||
int len = stop - start;
|
||||
str result = malloc(len);
|
||||
do (int i=start; i<stop; i++) {
|
||||
result[i] = src[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* int to string
|
||||
*/
|
||||
function itos(int src) str {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* nat to string
|
||||
*/
|
||||
function ntos(nat src) str {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* real to string
|
||||
*/
|
||||
function rtos(real src) str {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* string to int
|
||||
*/
|
||||
function stoi(str src) int {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* string to nat
|
||||
*/
|
||||
function ston(str src) nat {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* string to real
|
||||
*/
|
||||
function stor(str src) real {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,15 @@ const byte WHITE = 255;
|
|||
/**
|
||||
* Devices
|
||||
*/
|
||||
plex Terminal {
|
||||
interface Device {
|
||||
nat handle;
|
||||
}
|
||||
|
||||
plex Screen {
|
||||
plex Terminal implements Device {
|
||||
nat handle;
|
||||
}
|
||||
|
||||
plex Screen implements Device {
|
||||
nat handle;
|
||||
nat width;
|
||||
nat height;
|
||||
|
|
@ -25,7 +29,7 @@ plex Screen {
|
|||
}
|
||||
}
|
||||
|
||||
plex Mouse {
|
||||
plex Mouse implements Device {
|
||||
nat handle;
|
||||
nat x;
|
||||
nat y;
|
||||
|
|
@ -45,7 +49,7 @@ function main() {
|
|||
print(screen.width as str);
|
||||
print(screen.size as str);
|
||||
unsafe {
|
||||
print(screen.buffer.ptr as str);
|
||||
pln(screen.buffer.ptr as str);
|
||||
}
|
||||
|
||||
Mouse mouse = open(mouse_namespace, 0);
|
||||
|
|
@ -65,7 +69,7 @@ function main() {
|
|||
/**
|
||||
* Print with a newline
|
||||
*/
|
||||
function print(str message) {
|
||||
function pln(str message) {
|
||||
Terminal term = open(terminal_namespace, 0);
|
||||
write(term, message, message.length);
|
||||
write(term, nl, nl.length);
|
||||
|
|
|
|||
Loading…
Reference in New Issue