#include"parse.h" #include"vm.h" #include #define i_key LInst #include"stc/vec.h" #define i_key int32_t #include"stc/vec.h" #define i_key LFunc #include"stc/vec.h" typedef struct ScopeItem { Token name; int vreg; struct ScopeItem *next; } ScopeItem; typedef struct Scope { struct Scope *parent; ScopeItem *items; } Scope; ScopeItem *scope_get(Scope *scope, const char *name) { for(ScopeItem *si = scope->items; si; si = si->next) { if(!strcmp(si->name.text, name)) { return si; } } return NULL; } ScopeItem *scope_find(Scope *scope, const char *name) { while(scope) { ScopeItem *si = scope_get(scope, name); if(si) { return si; } scope = scope->parent; } return NULL; } void scope_set_direct(Scope *scope, ScopeItem *new) { new->next = scope->items; scope->items = new; } typedef struct { vec_LInst instrs; int used_vregs[256]; } Chunk; typedef struct { size_t i; size_t sz; Token *tokens; LTable *environment; Scope *scope; vec_LFunc unit_functions; size_t abyss_size; uint8_t *abyss; Chunk current_chunk; } Parser; typedef enum ExprKind { EX_LOCAL, EX_GLOBAL, EX_INT, EX_FLOAT, EX_BOOL, EX_ADD, EX_SUB, EX_MUL, EX_DIV, EX_IDIV, EX_MOD, EX_POW, EX_BAND, EX_BOR, EX_BXOR, EX_AND, EX_OR, EX_EQ, EX_NEQ, EX_TBL_LIT, EX_FUNC_LIT, EX_DOT, EX_INDEX, EX_CALL, EX_STR, EX_LENGTH, } ExprKind; typedef struct Expr { ExprKind kind; struct Expr *next_to_die; union { struct { struct Expr *A; union { struct Expr *B; Token B_tok; }; }; Token name; intmax_t i; double f; bool b; struct { uint8_t sub_count; struct Expr *subs[]; }; struct { size_t table_first_token; size_t table_last_token; }; }; } Expr; size_t abyss_insert(Parser *P, uint8_t *data, size_t len) { size_t idx = P->abyss_size; P->abyss = realloc(P->abyss, P->abyss_size += len); if(data) { memcpy(P->abyss + idx, data, len); } return idx; } Token peek(Parser *P, int offset) { if(P->i + offset >= P->sz) { Token t = P->tokens[P->sz - 1]; t.type = TOK_EOF; return t; } return P->tokens[P->i + offset]; } Token get(Parser *P) { Token t = peek(P, 0); P->i++; return t; } Token expect(Parser *P, TokenType type) { Token t = get(P); assert(t.type == type); return t; } bool maybe(Parser *P, TokenType type) { if(peek(P, 0).type == type) { P->i++; return true; } else { return false; } } int find_vreg(Parser *P) { for(int i = 255; i >= 0; i--) { if(!P->current_chunk.used_vregs[i]) { return i; } } assert(false); } void alloc_vreg(Parser *P, int vreg) { P->current_chunk.used_vregs[vreg]++; } void free_vreg(Parser *P, int vreg) { P->current_chunk.used_vregs[vreg]--; assert(P->current_chunk.used_vregs[vreg] >= 0 && "Cannot free unused vreg"); } static void scope_kill(Parser *P) { Scope *parent = P->scope->parent; for(ScopeItem *si = P->scope->items; si;) { ScopeItem *next = si->next; free(si); si = next; } free(P->scope); P->scope = parent; } void parse_chunk(Parser *P); int parse_functiondef(Parser *P, bool can_be_local) { size_t old_idx = P->i; if(!(peek(P, 0).type == TOK_FUNCTION || (can_be_local && peek(P, 0).type == TOK_LOCAL && peek(P, 1).type == TOK_FUNCTION))) { goto err; } bool is_local = maybe(P, TOK_LOCAL); expect(P, TOK_FUNCTION); Token name = {}; if(peek(P, 0).type == TOK_NAME) { name = get(P); } if(!maybe(P, TOK_PAREN_L)) { goto err; } Chunk old_chunk = P->current_chunk; P->current_chunk = (Chunk) {}; Scope *new_scope = calloc(1, sizeof(*new_scope)); new_scope->parent = P->scope; P->scope = new_scope; size_t arg_count = 0; if(!maybe(P, TOK_PAREN_R)) { while(1) { if(peek(P, 0).type != TOK_NAME) { goto err; } ScopeItem *si = calloc(1, sizeof(*si)); si->name = expect(P, TOK_NAME); si->vreg = arg_count++; scope_set_direct(P->scope, si); if(maybe(P, TOK_PAREN_R)) { break; } else { if(peek(P, 0).type != TOK_COMMA) { goto err; } } } } parse_chunk(P); if(P->current_chunk.instrs.data[P->current_chunk.instrs.size - 1].opcode != L_RET) { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_RET, .argb = {0}}); } expect(P, TOK_END); assert(P->unit_functions.size > 0); LFunc lf = {}; lf.unit = P->unit_functions.data[0].unit; lf.is_native = false; lf.lua_instrs = P->current_chunk.instrs.data; lf.env = P->environment; vec_LFunc_push(&P->unit_functions, lf); size_t function_idx = P->unit_functions.size - 1; P->current_chunk = old_chunk; scope_kill(P); int vreg = find_vreg(P); assert(vreg != -1); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETFUNC, .a = vreg, .bc = function_idx}); if(name.text) { if(is_local) { alloc_vreg(P, vreg); ScopeItem *si = calloc(1, sizeof(*si)); si->name = name; si->vreg = vreg; scope_set_direct(P->scope, si); } else { size_t abyss_idx = abyss_insert(P, NULL, sizeof(uint16_t) + strlen(name.text)); *(uint16_t*) &P->abyss[abyss_idx] = strlen(name.text); memcpy(&P->abyss[abyss_idx + sizeof(uint16_t)], name.text, strlen(name.text)); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETGLOBAL, .a = vreg, .bc = abyss_idx}); } } return vreg; err: P->i = old_idx; return -1; } Expr *desc_exp(Parser *P); Expr *desc_subexp(Parser *P, int priority); void emit_expr(Parser *P, int assigned_vreg, Expr *expr); bool parse_functioncall(Parser *P) { size_t old_idx = P->i; Expr *ex = desc_exp(P); if(ex->kind != EX_CALL) { goto err; } emit_expr(P, find_vreg(P), ex); return true; err: P->i = old_idx; return false; } vec_Token parse_namelist(Parser *P) { vec_Token v = {}; vec_Token_push(&v, expect(P, TOK_NAME)); while(maybe(P, TOK_COMMA)) { vec_Token_push(&v, expect(P, TOK_NAME)); } return v; } static Expr *last_desc = NULL; static Expr *mark_for_death(Expr *e) { e->next_to_die = last_desc; last_desc = e; return e; } static Expr *new_expr(size_t space) { Expr *e = calloc(1, sizeof(*e) + space); mark_for_death(e); return e; } Expr *desc_subexp(Parser *P, int priority) { if(priority == 0) { Expr *a = desc_subexp(P, priority + 1); while(maybe(P, TOK_DOUBLE_EQUAL) || maybe(P, TOK_NOT_EQUAL)) { Token op = peek(P, -1); Expr *b = desc_subexp(P, priority + 1); Expr *opex = new_expr(0); opex->A = a; opex->B = b; if(op.type == TOK_DOUBLE_EQUAL) { opex->kind = EX_EQ; } else if(op.type == TOK_NOT_EQUAL) { opex->kind = EX_NEQ; } a = opex; } return a; } else if(priority == 1) { Expr *a = desc_subexp(P, priority + 1); while(peek(P, 0).type == TOK_PLUS || peek(P, 0).type == TOK_MINUS) { Token op = get(P); Expr *b = desc_subexp(P, priority + 1); Expr *opex = new_expr(0); opex->A = a; opex->B = b; if(op.type == TOK_PLUS) { opex->kind = EX_ADD; } else { opex->kind = EX_SUB; } a = opex; } return a; } else if(priority == 2) { Expr *a = desc_subexp(P, priority + 1); while(peek(P, 0).type == TOK_MUL || peek(P, 0).type == TOK_DIV || peek(P, 0).type == TOK_IDIV || peek(P, 0).type == TOK_PERCENT) { Token op = get(P); Expr *b = desc_subexp(P, priority + 1); Expr *opex = new_expr(0); opex->A = a; opex->B = b; if(op.type == TOK_MUL) { opex->kind = EX_MUL; } else if(op.type == TOK_DIV) { opex->kind = EX_DIV; } else if(op.type == TOK_IDIV) { opex->kind = EX_IDIV; } else if(op.type == TOK_PERCENT) { opex->kind = EX_MOD; } a = opex; } return a; } else if(priority == 3) { Expr *e = NULL; if(maybe(P, TOK_SHARP)) { e = new_expr(0); e->kind = EX_LENGTH; e->A = desc_subexp(P, priority); } else if(maybe(P, TOK_TRUE)) { e = new_expr(0); e->kind = EX_BOOL; e->b = true; } else if(maybe(P, TOK_FALSE)) { e = new_expr(0); e->kind = EX_BOOL; e->b = false; } else if(maybe(P, TOK_NUMBER)) { P->i--; Token num = expect(P, TOK_NUMBER); long i = strtol(num.text, NULL, 10); e = new_expr(0); e->kind = EX_INT; e->i = i; } else if(maybe(P, TOK_NAME)) { P->i--; Token name = expect(P, TOK_NAME); ScopeItem *si = scope_find(P->scope, name.text); e = new_expr(0); e->kind = si ? EX_LOCAL : EX_GLOBAL; e->name = name; } else if(maybe(P, TOK_STRING)) { P->i--; Token str = expect(P, TOK_STRING); e = new_expr(0); e->kind = EX_STR; e->name = str; } else if(maybe(P, TOK_FUNCTION)) { e = new_expr(0); e->kind = EX_FUNC_LIT; e->table_first_token = P->i - 1; size_t depth = 1; while(1) { Token t = get(P); if(t.type == TOK_THEN || t.type == TOK_DO) { depth++; } else if(t.type == TOK_END) { depth--; if(depth == 0) { break; } } } e->table_last_token = P->i - 1; } else if(maybe(P, TOK_SQUIGGLY_L)) { e = new_expr(0); e->kind = EX_TBL_LIT; e->table_first_token = P->i - 1; size_t depth = 1; while(1) { Token t = get(P); if(t.type == TOK_SQUIGGLY_L) { depth++; } else if(t.type == TOK_SQUIGGLY_R) { depth--; if(depth == 0) { break; } } } e->table_last_token = P->i - 1; } if(e) { while(maybe(P, TOK_PAREN_L) || maybe(P, TOK_DOT) || maybe(P, TOK_SQUAREN_L)) { if(peek(P, -1).type == TOK_PAREN_L) { Expr *call = new_expr(sizeof(Expr*) + sizeof(Expr*) * 32); call->kind = EX_CALL; call->sub_count = 1; call->subs[0] = e; if(!maybe(P, TOK_PAREN_R)) { while(1) { call->subs[call->sub_count++] = desc_exp(P); if(maybe(P, TOK_PAREN_R)) { break; } else { expect(P, TOK_COMMA); } } } e = call; } else if(peek(P, -1).type == TOK_DOT) { Expr *dot = new_expr(0); dot->kind = EX_DOT; dot->A = e; dot->B_tok = expect(P, TOK_NAME); e = dot; } else if(peek(P, -1).type == TOK_SQUAREN_L) { Expr *index = new_expr(0); index->kind = EX_INDEX; index->A = e; index->B = desc_exp(P); expect(P, TOK_SQUAREN_R); e = index; } } return e; } } return NULL; } Expr *desc_exp(Parser *P) { return desc_subexp(P, 0); } /*void parse_exp_priority(Parser *P, int assigned_vreg, int priority) { if(priority == 0) { parse_exp_priority(P, assigned_vreg, priority + 1); while(peek(P, 0).type == TOK_DOUBLE_EQUAL) { int vreg = find_vreg(P); Token op = get(P); alloc_vreg(P, vreg); parse_exp_priority(P, vreg, priority + 1); free_vreg(P, vreg); if(op.type == TOK_DOUBLE_EQUAL) { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_COND_EQ, .a = assigned_vreg, .b = assigned_vreg, .c = vreg}); } } } else if(priority == 1) { parse_exp_priority(P, assigned_vreg, priority + 1); while(peek(P, 0).type == TOK_MUL || peek(P, 0).type == TOK_DIV || peek(P, 0).type == TOK_PERCENT || peek(P, 0).type == TOK_IDIV) { int vreg = find_vreg(P); Token op = get(P); alloc_vreg(P, vreg); parse_exp_priority(P, vreg, priority + 1); free_vreg(P, vreg); if(op.type == TOK_MUL) { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_MUL, .a = assigned_vreg, .b = assigned_vreg, .c = vreg}); } else if(op.type == TOK_DIV) { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_DIV, .a = assigned_vreg, .b = assigned_vreg, .c = vreg}); } else if(op.type == TOK_PERCENT) { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_MOD, .a = assigned_vreg, .b = assigned_vreg, .c = vreg}); } else { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_IDIV, .a = assigned_vreg, .b = assigned_vreg, .c = vreg}); } } } else if(priority == 2) { parse_exp_priority(P, assigned_vreg, priority + 1); while(peek(P, 0).type == TOK_PLUS || peek(P, 0).type == TOK_MINUS) { int vreg = find_vreg(P); Token op = get(P); alloc_vreg(P, vreg); parse_exp_priority(P, vreg, priority + 1); free_vreg(P, vreg); if(op.type == TOK_PLUS) { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_ADD, .a = assigned_vreg, .b = assigned_vreg, .c = vreg}); } else { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SUB, .a = assigned_vreg, .b = assigned_vreg, .c = vreg}); } } } else if(priority == 3) { if(maybe(P, TOK_TRUE)) { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETBOOL, .a = assigned_vreg, .b = true}); } else if(maybe(P, TOK_FALSE)) { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETBOOL, .a = assigned_vreg, .b = false}); } else if(maybe(P, TOK_NIL)) { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETNIL, .a = assigned_vreg}); } else if(maybe(P, TOK_SQUIGGLY_L)) { expect(P, TOK_SQUIGGLY_R); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETTABLE, .a = assigned_vreg, .bc = 8}); } else if(peek(P, 0).type == TOK_NAME) { Token name = expect(P, TOK_NAME); ScopeItem *si = scope_find(P->scope, name.text); if(!si) { size_t abyss_idx = abyss_insert(P, NULL, sizeof(uint16_t) + strlen(name.text)); *(uint16_t*) &P->abyss[abyss_idx] = strlen(name.text); memcpy(&P->abyss[abyss_idx + sizeof(uint16_t)], name.text, strlen(name.text)); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_GETGLOBAL, .a = assigned_vreg, .b = abyss_idx}); } else { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_MOVE, .a = assigned_vreg, .b = si->vreg}); } } else if(peek(P, 0).type == TOK_NUMBER) { Token num = expect(P, TOK_NUMBER); long i = strtol(num.text, NULL, 10); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETINT16, .a = assigned_vreg, .bc = i}); } else if(peek(P, 0).type == TOK_STRING) { Token str = expect(P, TOK_STRING); size_t abyss_idx = abyss_insert(P, NULL, sizeof(uint16_t) + strlen(str.text)); *(uint16_t*) &P->abyss[abyss_idx] = strlen(str.text); memcpy(&P->abyss[abyss_idx + sizeof(uint16_t)], str.text, strlen(str.text)); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETSTR, .a = assigned_vreg, .bc = abyss_idx}); } else { assert(false); } } }*/ void emit_expr(Parser *P, int assigned_vreg, Expr *expr) { if(expr->kind == EX_LOCAL) { ScopeItem *si = scope_find(P->scope, expr->name.text); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_MOVE, .a = assigned_vreg, .b = si->vreg}); } else if(expr->kind == EX_GLOBAL) { size_t abyss_idx = abyss_insert(P, NULL, sizeof(uint16_t) + strlen(expr->name.text)); *(uint16_t*) &P->abyss[abyss_idx] = strlen(expr->name.text); memcpy(&P->abyss[abyss_idx + sizeof(uint16_t)], expr->name.text, strlen(expr->name.text)); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_GETGLOBAL, .a = assigned_vreg, .b = abyss_idx}); } else if(expr->kind == EX_INT) { if(expr->i <= 32767 && expr->i >= -32768) { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETINT16, .a = assigned_vreg, .bc = expr->i}); } else { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETINT32, .a = assigned_vreg, .bc = abyss_insert(P, (uint8_t*) &expr->i, 4)}); } } else if(expr->kind == EX_FLOAT) { assert(false); } else if(expr->kind == EX_BOOL) { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETBOOL, .a = assigned_vreg, .bc = expr->b}); } else if(expr->kind == EX_STR) { size_t abyss_idx = abyss_insert(P, NULL, sizeof(uint16_t) + strlen(expr->name.text)); *(uint16_t*) &P->abyss[abyss_idx] = strlen(expr->name.text); memcpy(&P->abyss[abyss_idx + sizeof(uint16_t)], expr->name.text, strlen(expr->name.text)); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETSTR, .a = assigned_vreg, .bc = abyss_idx}); } else if(expr->kind == EX_CALL) { int vreg = find_vreg(P); assert(vreg != -1); emit_expr(P, vreg, expr->subs[0]); alloc_vreg(P, vreg); uint8_t buf[258] = {}; uint8_t *ret_vreg = buf + 0; uint8_t *arg_count = buf + 1; uint8_t *args = buf + 2; for(size_t i = 1; i < expr->sub_count; i++) { int av = find_vreg(P); emit_expr(P, av, expr->subs[i]); args[(*arg_count)++] = av; alloc_vreg(P, av); } *ret_vreg = find_vreg(P); free_vreg(P, vreg); for(int i = 0; i < *arg_count; i++) { free_vreg(P, args[i]); } vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_CALL, .a = vreg, .bc = abyss_insert(P, buf, 2 + *arg_count)}); } else if(expr->kind == EX_FUNC_LIT) { size_t old_idx = P->i; P->i = expr->table_first_token; expect(P, TOK_FUNCTION); expect(P, TOK_PAREN_L); Chunk old_chunk = P->current_chunk; P->current_chunk = (Chunk) {}; Scope *new_scope = calloc(1, sizeof(*new_scope)); new_scope->parent = P->scope; P->scope = new_scope; size_t arg_count = 0; if(!maybe(P, TOK_PAREN_R)) { while(1) { expect(P, TOK_NAME); P->i--; ScopeItem *si = calloc(1, sizeof(*si)); si->name = expect(P, TOK_NAME); si->vreg = arg_count++; scope_set_direct(P->scope, si); if(maybe(P, TOK_PAREN_R)) { break; } else { expect(P, TOK_COMMA); } } } parse_chunk(P); if(P->current_chunk.instrs.data[P->current_chunk.instrs.size - 1].opcode != L_RET) { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_RET, .argb = {0}}); } expect(P, TOK_END); assert(P->unit_functions.size > 0); LFunc lf = {}; lf.unit = P->unit_functions.data[0].unit; lf.is_native = false; lf.lua_instrs = P->current_chunk.instrs.data; lf.env = P->environment; vec_LFunc_push(&P->unit_functions, lf); size_t function_idx = P->unit_functions.size - 1; P->current_chunk = old_chunk; scope_kill(P); P->i = old_idx; vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETFUNC, .a = assigned_vreg, .bc = function_idx}); } else if(expr->kind == EX_TBL_LIT) { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETTABLE, .a = assigned_vreg, .bc = 16}); size_t old_idx = P->i; P->i = expr->table_first_token; expect(P, TOK_SQUIGGLY_L); alloc_vreg(P, assigned_vreg); if(!maybe(P, TOK_SQUIGGLY_R)) { while(1) { int keyv = find_vreg(P); assert(keyv != -1); if(peek(P, 0).type == TOK_NAME) { Token name = get(P); size_t abyss_idx = abyss_insert(P, NULL, sizeof(uint16_t) + strlen(name.text)); *(uint16_t*) &P->abyss[abyss_idx] = strlen(name.text); memcpy(&P->abyss[abyss_idx + sizeof(uint16_t)], name.text, strlen(name.text)); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETSTR, .a = keyv, .bc = abyss_idx}); } else { expect(P, TOK_SQUAREN_L); emit_expr(P, keyv, desc_exp(P)); expect(P, TOK_SQUAREN_R); } expect(P, TOK_EQUAL); alloc_vreg(P, keyv); int valv = find_vreg(P); emit_expr(P, valv, desc_exp(P)); free_vreg(P, keyv); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETFIELD, .a = assigned_vreg, .b = keyv, .c = valv}); if(maybe(P, TOK_SQUIGGLY_R)) { break; } else { expect(P, TOK_COMMA); } } } free_vreg(P, assigned_vreg); P->i = old_idx; } else if(expr->kind == EX_DOT) { Token field = expr->B_tok; emit_expr(P, assigned_vreg, expr->A); alloc_vreg(P, assigned_vreg); size_t abyss_idx = abyss_insert(P, NULL, sizeof(uint16_t) + strlen(field.text)); *(uint16_t*) &P->abyss[abyss_idx] = strlen(field.text); memcpy(&P->abyss[abyss_idx + sizeof(uint16_t)], field.text, strlen(field.text)); int keyv = find_vreg(P); assert(keyv != -1); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETSTR, .a = keyv, .bc = abyss_idx}); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_GETFIELD, .a = assigned_vreg, .b = assigned_vreg, .c = keyv}); free_vreg(P, assigned_vreg); } else if(expr->kind == EX_INDEX) { emit_expr(P, assigned_vreg, expr->A); alloc_vreg(P, assigned_vreg); int keyv = find_vreg(P); emit_expr(P, keyv, expr->B); free_vreg(P, assigned_vreg); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_GETFIELD, .a = assigned_vreg, .b = assigned_vreg, .c = keyv}); } else if(expr->kind == EX_LENGTH) { emit_expr(P, assigned_vreg, expr->A); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_LEN, .a = assigned_vreg, .b = assigned_vreg, .c = 0}); } else { assert(expr->kind == EX_ADD || expr->kind == EX_SUB || expr->kind == EX_MUL || expr->kind == EX_DIV || expr->kind == EX_IDIV || expr->kind == EX_MOD || expr->kind == EX_POW || expr->kind == EX_BAND || expr->kind == EX_BOR || expr->kind == EX_BXOR || expr->kind == EX_AND || expr->kind == EX_OR || expr->kind == EX_EQ || expr->kind == EX_NEQ); assert(expr->A); assert(expr->B); emit_expr(P, assigned_vreg, expr->A); alloc_vreg(P, assigned_vreg); int b_vreg = find_vreg(P); emit_expr(P, b_vreg, expr->B); free_vreg(P, assigned_vreg); uint8_t opcode; switch(expr->kind) { case EX_ADD: opcode = L_ADD; break; case EX_SUB: opcode = L_SUB; break; case EX_MUL: opcode = L_MUL; break; case EX_DIV: opcode = L_DIV; break; case EX_IDIV: opcode = L_IDIV; break; case EX_MOD: opcode = L_MOD; break; case EX_POW: opcode = L_POW; break; case EX_EQ: opcode = L_COND_EQ; break; case EX_NEQ: opcode = L_COND_NEQ; break; default: assert(false); } vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = opcode, .a = assigned_vreg, .b = assigned_vreg, .c = b_vreg}); } } int parse_exp(Parser *P, int assigned_vreg) { bool owned = false; if(assigned_vreg == -1) { owned = true; assigned_vreg = find_vreg(P); alloc_vreg(P, assigned_vreg); } emit_expr(P, assigned_vreg, desc_exp(P)); if(owned) { free_vreg(P, assigned_vreg); } return assigned_vreg; } bool parse_assignment(Parser *P) { size_t old_idx = P->i; const size_t max_exprs = 8; Expr *lhs[max_exprs]; size_t lhsi = 0; Expr *rhs[max_exprs]; int rhsv[max_exprs]; size_t rhsi = 0; while(1) { lhs[lhsi++] = desc_exp(P); if(!lhs[lhsi - 1]) { goto err; } if(lhs[lhsi - 1]->kind != EX_LOCAL && lhs[lhsi - 1]->kind != EX_GLOBAL && lhs[lhsi - 1]->kind != EX_DOT && lhs[lhsi - 1]->kind != EX_INDEX) { goto err; } if(maybe(P, TOK_EQUAL)) { break; } else { expect(P, TOK_COMMA); } } rhs[rhsi++] = desc_exp(P); while(1) { if(!maybe(P, TOK_COMMA)) { break; } rhs[rhsi++] = desc_exp(P); } for(size_t i = 0; i < rhsi; i++) { rhsv[i] = find_vreg(P); emit_expr(P, rhsv[i], rhs[i]); alloc_vreg(P, rhsv[i]); } assert(rhsi == lhsi); for(size_t i = 0; i < lhsi; i++) { if(lhs[i]->kind == EX_LOCAL) { ScopeItem *si = scope_find(P->scope, lhs[i]->name.text); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_MOVE, .a = si->vreg, .b = rhsv[i]}); } else if(lhs[i]->kind == EX_GLOBAL) { size_t abyss_idx = abyss_insert(P, NULL, sizeof(uint16_t) + strlen(lhs[i]->name.text)); *(uint16_t*) &P->abyss[abyss_idx] = strlen(lhs[i]->name.text); memcpy(&P->abyss[abyss_idx + sizeof(uint16_t)], lhs[i]->name.text, strlen(lhs[i]->name.text)); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETGLOBAL, .a = rhsv[i], .bc = abyss_idx}); } else if(lhs[i]->kind == EX_INDEX) { int lhsv = find_vreg(P); assert(lhsv != -1); emit_expr(P, lhsv, lhs[i]->A); alloc_vreg(P, lhsv); int keyv = find_vreg(P); assert(keyv != -1); emit_expr(P, keyv, lhs[i]->B); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETFIELD, .a = lhsv, .b = keyv, .c = rhsv[i]}); free_vreg(P, lhsv); } else if(lhs[i]->kind == EX_DOT) { int lhsv = find_vreg(P); assert(lhsv != -1); emit_expr(P, lhsv, lhs[i]->A); alloc_vreg(P, lhsv); Token field = lhs[i]->B_tok; size_t abyss_idx = abyss_insert(P, NULL, sizeof(uint16_t) + strlen(field.text)); *(uint16_t*) &P->abyss[abyss_idx] = strlen(field.text); memcpy(&P->abyss[abyss_idx + sizeof(uint16_t)], field.text, strlen(field.text)); int keyv = find_vreg(P); assert(keyv != -1); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETSTR, .a = keyv, .bc = abyss_idx}); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETFIELD, .a = lhsv, .b = keyv, .c = rhsv[i]}); free_vreg(P, lhsv); } else { assert(false); } } for(size_t i = 0; i < rhsi; i++) { free_vreg(P, rhsv[i]); } return true; err: P->i = old_idx; return false; } void parse_chunk(Parser *P); bool parse_stat(Parser *P) { if(parse_functiondef(P, true) != -1) { } else if(maybe(P, TOK_LOCAL)) { vec_Token names = parse_namelist(P); int i = 0; if(maybe(P, TOK_EQUAL)) { do { int vreg = parse_exp(P, -1); if(i < names.size) { alloc_vreg(P, vreg); ScopeItem *si = calloc(1, sizeof(*si)); *si = (ScopeItem) {.name = names.data[i], .vreg = vreg}; scope_set_direct(P->scope, si); } i++; } while(maybe(P, TOK_COMMA)); } for(; i < names.size; i++) { int vreg = find_vreg(P); alloc_vreg(P, vreg); ScopeItem *si = calloc(1, sizeof(*si)); *si = (ScopeItem) {.name = names.data[i], .vreg = vreg}; scope_set_direct(P->scope, si); } vec_Token_drop(&names); } else if(maybe(P, TOK_IF)) { int vreg = parse_exp(P, -1); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_JNOTCOND, .a = vreg, .bc = 0}); size_t jump2else = P->current_chunk.instrs.size - 1; expect(P, TOK_THEN); parse_chunk(P); bool isElse = maybe(P, TOK_ELSE); size_t jump2end; if(isElse) { vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_JUMP, .a = 0, .bc = 0}); jump2end = P->current_chunk.instrs.size - 1; } P->current_chunk.instrs.data[jump2else].bc = P->current_chunk.instrs.size - 1 - jump2else; if(isElse) { parse_chunk(P); P->current_chunk.instrs.data[jump2end].bc = P->current_chunk.instrs.size - 1 - jump2end; } expect(P, TOK_END); } else if(maybe(P, TOK_WHILE)) { Expr *condition = desc_exp(P); int vreg = find_vreg(P); assert(vreg != -1); size_t start_idx = P->current_chunk.instrs.size; emit_expr(P, vreg, condition); size_t jump2end = P->current_chunk.instrs.size; vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_JNOTCOND, .a = vreg, .bc = 0}); Scope *new_scope = calloc(1, sizeof(*new_scope)); new_scope->parent = P->scope; expect(P, TOK_DO); parse_chunk(P); expect(P, TOK_END); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_JUMP, .a = 0, .bc = start_idx - P->current_chunk.instrs.size - 1}); P->current_chunk.instrs.data[jump2end].bc = P->current_chunk.instrs.size - 1 - jump2end; scope_kill(P); } else if(maybe(P, TOK_FOR)) { if(peek(P, 0).type == TOK_NAME && peek(P, 1).type == TOK_EQUAL) { // Range loop Token name = expect(P, TOK_NAME); expect(P, TOK_EQUAL); int fromVreg = parse_exp(P, -1); alloc_vreg(P, fromVreg); expect(P, TOK_COMMA); int toVreg = parse_exp(P, -1); alloc_vreg(P, toVreg); int stepVreg; if(maybe(P, TOK_COMMA)) { stepVreg = parse_exp(P, -1); } else { stepVreg = find_vreg(P); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SETINT16, .a = stepVreg, .bc = 1}); } alloc_vreg(P, stepVreg); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_SUB, .a = fromVreg, .b = fromVreg, .c = stepVreg}); expect(P, TOK_DO); Scope *new_scope = calloc(1, sizeof(*new_scope)); new_scope->parent = P->scope; ScopeItem *si = calloc(1, sizeof(*si)); si->name = name; si->vreg = fromVreg; scope_set_direct(new_scope, si); P->scope = new_scope; size_t start_idx = P->current_chunk.instrs.size; vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_ADD, .a = fromVreg, .b = fromVreg, .c = stepVreg}); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_ADVANCETEST, .a = fromVreg, .b = toVreg, .c = stepVreg}); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_JUMP, .a = 0, .bc = 0}); size_t jump2end = P->current_chunk.instrs.size - 1; parse_chunk(P); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_JUMP, .a = 0, .bc = start_idx - P->current_chunk.instrs.size - 1}); P->current_chunk.instrs.data[jump2end].bc = P->current_chunk.instrs.size - 1 - jump2end; scope_kill(P); expect(P, TOK_END); free_vreg(P, fromVreg); free_vreg(P, toVreg); free_vreg(P, stepVreg); } else { assert(0 && "Iterator for loop not yet supported"); } } else if(maybe(P, TOK_RETURN)) { int vreg = parse_exp(P, -1); vec_LInst_push(&P->current_chunk.instrs, (LInst) {.opcode = L_RET, .argb = {vreg}}); return false; } else if(peek(P, 0).type == TOK_END || peek(P, 0).type == TOK_ELSE || peek(P, 0).type == TOK_ELSEIF || peek(P, 0).type == TOK_EOF) { return false; } else if(parse_functioncall(P)) { } else if(parse_assignment(P)) { } else { assert(false); } return true; } void parse_chunk(Parser *P) { while(parse_stat(P)); } LUnit *lparse(size_t sz, Token *tokens, LTable *environment) { LUnit *unit = calloc(1, sizeof(*unit)); Parser P = { .i = 0, .sz = sz, .tokens = tokens, .environment = environment, .unit_functions = {}, .scope = calloc(1, sizeof(Scope)), }; LFunc func = {}; func.unit = unit; func.is_native = false; func.upvalue_count = 0; func.env = environment; vec_LFunc_push(&P.unit_functions, func); parse_chunk(&P); if(P.current_chunk.instrs.data[P.current_chunk.instrs.size - 1].opcode != L_RET) { vec_LInst_push(&P.current_chunk.instrs, (LInst) {.opcode = L_RET, .argb = {0}}); } P.unit_functions.data[0].lua_instrs = P.current_chunk.instrs.data; unit->abyss = P.abyss; unit->func_count = 1; unit->funcs = P.unit_functions.data; for(Expr *e = last_desc; e;) { Expr *n = e->next_to_die; free(e); e = n; } last_desc = NULL; return unit; }