impotent/parse.c
2025-08-31 16:22:38 +03:00

1054 lines
26 KiB
C

#include"parse.h"
#include"vm.h"
#include<alloca.h>
#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_INDEX,
EX_CALL,
EX_STR,
} ExprKind;
typedef struct Expr {
ExprKind kind;
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");
}
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;
P->scope = P->scope->parent;
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;
}
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 = calloc(1, sizeof(*opex));
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 = calloc(1, sizeof(*opex));
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 = calloc(1, sizeof(*opex));
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_TRUE)) {
e = calloc(1, sizeof(*e));
e->kind = EX_BOOL;
e->b = true;
} else if(maybe(P, TOK_FALSE)) {
e = calloc(1, sizeof(*e));
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 = calloc(1, sizeof(*e));
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 = calloc(1, sizeof(*e));
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 = calloc(1, sizeof(*e));
e->kind = EX_STR;
e->name = str;
} else if(maybe(P, TOK_SQUIGGLY_L)) {
e = calloc(1, sizeof(*e));
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)) {
if(peek(P, -1).type == TOK_PAREN_L) {
Expr *call = calloc(1, sizeof(*call) + sizeof(Expr*));
call->kind = EX_CALL;
call->sub_count = 1;
call->subs[0] = e;
if(!maybe(P, TOK_PAREN_R)) {
while(1) {
call = realloc(call, sizeof(*call) + sizeof(Expr*) * (++call->sub_count));
call->subs[call->sub_count - 1] = 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 = calloc(1, sizeof(*dot));
dot->kind = EX_INDEX;
dot->A = e;
dot->B_tok = expect(P, TOK_NAME);
e = dot;
}
}
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_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);
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);
}
}
}
P->i = old_idx;
} else if(expr->kind == EX_INDEX) {
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 {
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_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);
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;
P->scope = P->scope->parent;
} 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;
P->scope = P->scope->parent;
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;
return unit;
}