#include "cvm_core.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
static const char *token_name(int t) {
switch (t) {
case TK_EOF: return "EOF";
case TK_NUM: return "数字";
case TK_STR: return "字符串";
case TK_IDENT: return "标识符";
case TK_LET: return "let";
case TK_IF: return "if";
case TK_ELSE: return "else";
case TK_WHILE: return "while";
case TK_FOR: return "for";
case TK_FUNC: return "func";
case TK_RETURN: return "return";
case TK_BREAK: return "break";
case TK_CONTINUE:return "continue";
case TK_TRUE: return "true";
case TK_FALSE: return "false";
case TK_NIL: return "nil";
case TK_AND: return "and";
case TK_OR: return "or";
case TK_NOT: return "not";
case TK_EQEQ: return "==";
case TK_NOTEQ: return "!=";
case TK_LE: return "<=";
case TK_GE: return ">=";
case TK_LT: return "<";
case TK_GT: return ">";
case TK_ASSIGN: return "=";
case TK_PLUS: return "+";
case TK_MINUS: return "-";
case TK_STAR: return "*";
case TK_SLASH: return "/";
case TK_PERCENT:return "%";
case TK_LPAREN: return "(";
case TK_RPAREN: return ")";
case TK_LBRACE: return "{";
case TK_RBRACE: return "}";
case TK_SEMI: return ";";
case TK_COMMA: return ",";
case TK_LBRACKET: return "[";
case TK_RBRACKET: return "]";
case TK_COLON: return ":";
case TK_DOT: return ".";
case TK_IN: return "in";
default: return "?";
}
}
Expr *expr_num(Arena *a, int is_int, int64_t ival, double fval, int line) {
Expr *e = (Expr *)arena_alloc(a, sizeof(Expr));
e->kind = EXPR_NUM; e->line = line;
e->u.numlit.is_int = is_int;
if (is_int) e->u.numlit.ival = ival;
else e->u.numlit.fval = fval;
return e;
}
Expr *expr_str(Arena *a, char *s, int line) {
Expr *e = (Expr *)arena_alloc(a, sizeof(Expr));
e->kind = EXPR_STR; e->line = line; e->u.str = s; return e;
}
Expr *expr_bool(Arena *a, int b, int line) {
Expr *e = (Expr *)arena_alloc(a, sizeof(Expr));
e->kind = EXPR_BOOL; e->line = line; e->u.boolean = b; return e;
}
Expr *expr_nil(Arena *a, int line) {
Expr *e = (Expr *)arena_alloc(a, sizeof(Expr));
e->kind = EXPR_NIL; e->line = line; return e;
}
Expr *expr_var(Arena *a, char *name, int line) {
Expr *e = (Expr *)arena_alloc(a, sizeof(Expr));
e->kind = EXPR_VAR; e->line = line; e->u.name = name; return e;
}
Expr *expr_unary(Arena *a, int op, Expr *inner, int line) {
Expr *e = (Expr *)arena_alloc(a, sizeof(Expr));
e->kind = EXPR_UNARY; e->line = line; e->u.unary.op = op; e->u.unary.inner = inner; return e;
}
Expr *expr_binary(Arena *a, int op, Expr *l, Expr *r, int line) {
Expr *e = (Expr *)arena_alloc(a, sizeof(Expr));
e->kind = EXPR_BINARY; e->line = line;
e->u.binary.op = op; e->u.binary.left = l; e->u.binary.right = r; return e;
}
Expr *expr_call(Arena *a, Expr *callee, Expr **args, int argc, int line) {
Expr *e = (Expr *)arena_alloc(a, sizeof(Expr));
e->kind = EXPR_CALL; e->line = line;
e->u.call.callee = callee; e->u.call.args = args; e->u.call.argc = argc; return e;
}
Expr *expr_member(Arena *a, Expr *obj, char *name, int line) {
Expr *e = (Expr *)arena_alloc(a, sizeof(Expr));
e->kind = EXPR_MEMBER; e->line = line;
e->u.member.obj = obj; e->u.member.name = name; return e;
}
Expr *expr_assign(Arena *a, char *name, Expr *value, int line) {
Expr *e = (Expr *)arena_alloc(a, sizeof(Expr));
e->kind = EXPR_ASSIGN; e->line = line;
e->u.assign.name = name; e->u.assign.value = value; return e;
}
Expr *expr_index(Arena *a, Expr *obj, Expr *index, int line) {
Expr *e = (Expr *)arena_alloc(a, sizeof(Expr));
e->kind = EXPR_INDEX; e->line = line;
e->u.idx.obj = obj; e->u.idx.index = index; return e;
}
Expr *expr_index_assign(Arena *a, Expr *target, Expr *value, int line) {
Expr *e = (Expr *)arena_alloc(a, sizeof(Expr));
e->kind = EXPR_INDEX_ASSIGN; e->line = line;
e->u.index_assign.target = target; e->u.index_assign.value = value; return e;
}
Expr *expr_array(Arena *a, Expr **keys, Expr **vals, int *haskey, int count, int line) {
Expr *e = (Expr *)arena_alloc(a, sizeof(Expr));
e->kind = EXPR_ARRAY; e->line = line;
e->u.array.keys = keys; e->u.array.vals = vals;
e->u.array.haskey = haskey; e->u.array.count = count; return e;
}
Expr *expr_lambda(Arena *a, Stmt *funcDef, int line) {
Expr *e = (Expr *)arena_alloc(a, sizeof(Expr));
e->kind = EXPR_LAMBDA; e->line = line; e->u.lambda = funcDef; return e;
}
Stmt *stmt_let(Arena *a, char *name, Expr *init, int line) {
Stmt *s = (Stmt *)arena_alloc(a, sizeof(Stmt));
s->kind = STMT_LET; s->line = line; s->u.let.name = name; s->u.let.init = init; return s;
}
Stmt *stmt_assign(Arena *a, char *name, Expr *value, int line) {
Stmt *s = (Stmt *)arena_alloc(a, sizeof(Stmt));
s->kind = STMT_ASSIGN; s->line = line; s->u.assign.name = name; s->u.assign.value = value; return s;
}
Stmt *stmt_if(Arena *a, Expr *cond, Stmt *thenb, Stmt *elseb, int line) {
Stmt *s = (Stmt *)arena_alloc(a, sizeof(Stmt));
s->kind = STMT_IF; s->line = line;
s->u.ifs.cond = cond; s->u.ifs.then_b = thenb; s->u.ifs.else_b = elseb; return s;
}
Stmt *stmt_while(Arena *a, Expr *cond, Stmt *body, int line) {
Stmt *s = (Stmt *)arena_alloc(a, sizeof(Stmt));
s->kind = STMT_WHILE; s->line = line; s->u.whiles.cond = cond; s->u.whiles.body = body; return s;
}
Stmt *stmt_for(Arena *a, Stmt *init, Expr *cond, Expr *step, Stmt *body, int line) {
Stmt *s = (Stmt *)arena_alloc(a, sizeof(Stmt));
s->kind = STMT_FOR; s->line = line;
s->u.fors.init = init; s->u.fors.cond = cond; s->u.fors.step = step; s->u.fors.body = body; return s;
}
Stmt *stmt_for_in(Arena *a, char *var, Expr *iterable, Stmt *body, int line) {
Stmt *s = (Stmt *)arena_alloc(a, sizeof(Stmt));
s->kind = STMT_FOR_IN; s->line = line;
s->u.for_in.iter_var = var; s->u.for_in.iterable = iterable; s->u.for_in.body = body; return s;
}
Stmt *stmt_break(Arena *a, int line) {
Stmt *s = (Stmt *)arena_alloc(a, sizeof(Stmt));
s->kind = STMT_BREAK; s->line = line; return s;
}
Stmt *stmt_continue(Arena *a, int line) {
Stmt *s = (Stmt *)arena_alloc(a, sizeof(Stmt));
s->kind = STMT_CONTINUE; s->line = line; return s;
}
Stmt *stmt_return(Arena *a, Expr *value, int line) {
Stmt *s = (Stmt *)arena_alloc(a, sizeof(Stmt));
s->kind = STMT_RETURN; s->line = line; s->u.returns.value = value; return s;
}
Stmt *stmt_block(Arena *a, Stmt **stmts, int count, int line) {
Stmt *s = (Stmt *)arena_alloc(a, sizeof(Stmt));
s->kind = STMT_BLOCK; s->line = line; s->u.block.stmts = stmts; s->u.block.count = count; return s;
}
Stmt *stmt_func(Arena *a, char *name, char **params, int pcount, Stmt *body, int line) {
Stmt *s = (Stmt *)arena_alloc(a, sizeof(Stmt));
s->kind = STMT_FUNC; s->line = line;
s->u.func.name = name; s->u.func.params = params; s->u.func.pcount = pcount; s->u.func.body = body; return s;
}
Stmt *stmt_expr(Arena *a, Expr *e, int line) {
Stmt *s = (Stmt *)arena_alloc(a, sizeof(Stmt));
s->kind = STMT_EXPR; s->line = line; s->u.expr = e; return s;
}
Stmt *stmt_try(Arena *a, Stmt *body, char *catchvar, Stmt *catchbody, Stmt *finallybody, int line) {
Stmt *s = (Stmt *)arena_alloc(a, sizeof(Stmt));
s->kind = STMT_TRY; s->line = line;
s->u.trys.body = body; s->u.trys.catchvar = catchvar;
s->u.trys.catchbody = catchbody; s->u.trys.finallybody = finallybody; return s;
}
Stmt *stmt_throw(Arena *a, Expr *value, int line) {
Stmt *s = (Stmt *)arena_alloc(a, sizeof(Stmt));
s->kind = STMT_THROW; s->line = line; s->u.throws.value = value; return s;
}
Stmt *stmt_nil(Arena *a, int line) {
return stmt_block(a, NULL, 0, line);
}
typedef struct {
TokenList *tl;
int pos;
Arena *a;
Program prog;
} Parser;
static Token *peek(Parser *p) { return &p->tl->tokens[p->pos]; }
static Token *adv(Parser *p) { return &p->tl->tokens[p->pos++]; }
static int check(Parser *p, int t) { return peek(p)->type == t; }
static int match(Parser *p, int t) { if (check(p, t)) { adv(p); return 1; } return 0; }
static void perr(Parser *p, const char *fmt, ...) {
va_list ap; va_start(ap, fmt);
vsnprintf(p->prog.err, sizeof(p->prog.err), fmt, ap);
va_end(ap);
p->prog.has_error = 1;
}
static void expect(Parser *p, int t, const char *what) {
if (!check(p, t)) {
if (peek(p)->type == TK_EOF)
perr(p, "incomplete: 期望 %s", what);
else
perr(p, "行 %d: 期望 %s, 但遇到 '%s'", peek(p)->line, what,
peek(p)->text ? peek(p)->text : token_name(peek(p)->type));
return;
}
adv(p);
}
static void stmt_push(Arena *a, Stmt ***arr, int *count, int *cap, Stmt *s) {
if (*count == *cap) {
int ncap = *cap ? *cap * 2 : 8;
Stmt **na = (Stmt **)arena_alloc(a, (size_t)ncap * sizeof(Stmt *));
if (*count) memcpy(na, *arr, (size_t)(*count) * sizeof(Stmt *));
*arr = na; *cap = ncap;
}
(*arr)[(*count)++] = s;
}
static void expr_push(Arena *a, Expr ***arr, int *count, int *cap, Expr *e) {
if (*count == *cap) {
int ncap = *cap ? *cap * 2 : 8;
Expr **na = (Expr **)arena_alloc(a, (size_t)ncap * sizeof(Expr *));
if (*count) memcpy(na, *arr, (size_t)(*count) * sizeof(Expr *));
*arr = na; *cap = ncap;
}
(*arr)[(*count)++] = e;
}
static void param_push(Arena *a, char ***arr, int *count, int *cap, char *s) {
if (*count == *cap) {
int ncap = *cap ? *cap * 2 : 4;
char **na = (char **)arena_alloc(a, (size_t)ncap * sizeof(char *));
if (*count) memcpy(na, *arr, (size_t)(*count) * sizeof(char *));
*arr = na; *cap = ncap;
}
(*arr)[(*count)++] = s;
}
static Stmt *parse_statement(Parser *p);
static Expr *parse_expression(Parser *p);
static Stmt *parse_block(Parser *p);
static Stmt *parse_for_in(Parser *p);
static Expr *parse_postfix(Parser *p, Expr *e, int line) {
while (1) {
if (match(p, TK_LBRACKET)) {
Expr *idx = parse_expression(p);
expect(p, TK_RBRACKET, "']'");
e = expr_index(p->a, e, idx, line);
} else if (match(p, TK_DOT)) {
if (!check(p, TK_IDENT)) { perr(p, "行 %d: '.' 后期望成员名", peek(p)->line); return e; }
char *m = adv(p)->text;
e = expr_member(p->a, e, m, line);
} else if (match(p, TK_LPAREN)) {
Expr **args = NULL; int argc = 0, cap = 0;
if (!check(p, TK_RPAREN)) {
expr_push(p->a, &args, &argc, &cap, parse_expression(p));
while (match(p, TK_COMMA)) expr_push(p->a, &args, &argc, &cap, parse_expression(p));
}
expect(p, TK_RPAREN, "')'");
e = expr_call(p->a, e, args, argc, line);
} else {
break;
}
}
return e;
}
static Expr *parse_array_literal(Parser *p, int line) {
int cap = 8;
Expr **keys = (Expr **)arena_alloc(p->a, (size_t)cap * sizeof(Expr *));
Expr **vals = (Expr **)arena_alloc(p->a, (size_t)cap * sizeof(Expr *));
int *haskey = (int *)arena_alloc(p->a, (size_t)cap * sizeof(int));
int count = 0;
if (!check(p, TK_RBRACKET)) {
do {
if (count == cap) {
int ncap = cap * 2;
Expr **nk = (Expr **)arena_alloc(p->a, (size_t)ncap * sizeof(Expr *));
Expr **nv = (Expr **)arena_alloc(p->a, (size_t)ncap * sizeof(Expr *));
int *nh = (int *)arena_alloc(p->a, (size_t)ncap * sizeof(int));
memcpy(nk, keys, (size_t)count * sizeof(Expr *));
memcpy(nv, vals, (size_t)count * sizeof(Expr *));
memcpy(nh, haskey, (size_t)count * sizeof(int));
keys = nk; vals = nv; haskey = nh; cap = ncap;
}
Expr *first = parse_expression(p);
if (match(p, TK_COLON)) {
keys[count] = first; haskey[count] = 1;
vals[count] = parse_expression(p);
} else {
keys[count] = NULL; haskey[count] = 0;
vals[count] = first;
}
count++;
} while (match(p, TK_COMMA));
}
expect(p, TK_RBRACKET, "']'");
return expr_array(p->a, keys, vals, haskey, count, line);
}
static Stmt *parse_block(Parser *p);
static Expr *parse_lambda(Parser *p, int line);
static Expr *parse_primary(Parser *p) {
Token *t = peek(p);
if (match(p, TK_NUM)) {
if (t->is_int) return expr_num(p->a, 1, t->inum, 0.0, t->line);
return expr_num(p->a, 0, 0, t->num, t->line);
}
if (match(p, TK_STR)) return expr_str(p->a, t->text, t->line);
if (match(p, TK_TRUE)) return expr_bool(p->a, 1, t->line);
if (match(p, TK_FALSE)) return expr_bool(p->a, 0, t->line);
if (match(p, TK_NIL)) return expr_nil(p->a, t->line);
if (match(p, TK_LBRACKET)) return parse_array_literal(p, t->line);
if (check(p, TK_FUNC)) { int line = adv(p)->line; return parse_lambda(p, line); }
if (match(p, TK_IDENT)) {
char *name = t->text;
Expr *e = expr_var(p->a, name, t->line);
return parse_postfix(p, e, t->line);
}
if (match(p, TK_LPAREN)) {
Expr *e = parse_expression(p);
expect(p, TK_RPAREN, "')'");
return e;
}
perr(p, "行 %d: 意外的符号 '%s'", t->line, t->text ? t->text : token_name(t->type));
return expr_nil(p->a, t->line);
}
static Expr *parse_unary(Parser *p) {
Token *t = peek(p);
if (t->type == TK_NOT || t->type == TK_MINUS) {
adv(p);
Expr *inner = parse_unary(p);
return expr_unary(p->a, t->type, inner, t->line);
}
return parse_primary(p);
}
static Expr *parse_factor(Parser *p) {
Expr *left = parse_unary(p);
while (check(p, TK_STAR) || check(p, TK_SLASH) || check(p, TK_PERCENT)) {
int op = adv(p)->type;
Expr *right = parse_unary(p);
left = expr_binary(p->a, op, left, right, left->line);
}
return left;
}
static Expr *parse_term(Parser *p) {
Expr *left = parse_factor(p);
while (check(p, TK_PLUS) || check(p, TK_MINUS)) {
int op = adv(p)->type;
Expr *right = parse_factor(p);
left = expr_binary(p->a, op, left, right, left->line);
}
return left;
}
static Expr *parse_comparison(Parser *p) {
Expr *left = parse_term(p);
while (check(p, TK_LT) || check(p, TK_GT) || check(p, TK_LE) || check(p, TK_GE)) {
int op = adv(p)->type;
Expr *right = parse_term(p);
left = expr_binary(p->a, op, left, right, left->line);
}
return left;
}
static Expr *parse_equality(Parser *p) {
Expr *left = parse_comparison(p);
while (check(p, TK_EQEQ) || check(p, TK_NOTEQ)) {
int op = adv(p)->type;
Expr *right = parse_comparison(p);
left = expr_binary(p->a, op, left, right, left->line);
}
return left;
}
static Expr *parse_and(Parser *p) {
Expr *left = parse_equality(p);
while (match(p, TK_AND)) {
Expr *right = parse_equality(p);
left = expr_binary(p->a, TK_AND, left, right, left->line);
}
return left;
}
static Expr *parse_or(Parser *p) {
Expr *left = parse_and(p);
while (match(p, TK_OR)) {
Expr *right = parse_and(p);
left = expr_binary(p->a, TK_OR, left, right, left->line);
}
return left;
}
static Expr *parse_assignment(Parser *p) {
Expr *left = parse_or(p);
if (match(p, TK_ASSIGN)) {
Expr *right = parse_assignment(p);
if (left->kind == EXPR_VAR)
return expr_assign(p->a, left->u.name, right, left->line);
if (left->kind == EXPR_INDEX)
return expr_index_assign(p->a, left, right, left->line);
perr(p, "行 %d: 赋值目标必须是变量或数组下标", left->line);
return left;
}
return left;
}
static Expr *parse_expression(Parser *p) { return parse_assignment(p); }
static Stmt *parse_let(Parser *p) {
int line = adv(p)->line;
if (!check(p, TK_IDENT)) { perr(p, "行 %d: let 后期望变量名", line); return stmt_nil(p->a, line); }
char *name = adv(p)->text;
Expr *init = NULL;
if (match(p, TK_ASSIGN)) init = parse_expression(p);
expect(p, TK_SEMI, "';'");
return stmt_let(p->a, name, init, line);
}
static Stmt *parse_assign(Parser *p) {
int line = peek(p)->line;
char *name = adv(p)->text;
adv(p);
Expr *value = parse_expression(p);
expect(p, TK_SEMI, "';'");
return stmt_assign(p->a, name, value, line);
}
static Stmt *parse_if(Parser *p) {
int line = adv(p)->line;
expect(p, TK_LPAREN, "'('");
Expr *cond = parse_expression(p);
expect(p, TK_RPAREN, "')'");
Stmt *thenb = parse_statement(p);
Stmt *elseb = NULL;
if (match(p, TK_ELSE)) {
if (check(p, TK_IF)) elseb = parse_if(p);
else elseb = parse_statement(p);
}
return stmt_if(p->a, cond, thenb, elseb, line);
}
static Stmt *parse_while(Parser *p) {
int line = adv(p)->line;
expect(p, TK_LPAREN, "'('");
Expr *cond = parse_expression(p);
expect(p, TK_RPAREN, "')'");
Stmt *body = parse_statement(p);
return stmt_while(p->a, cond, body, line);
}
static Stmt *parse_for(Parser *p) {
int line = adv(p)->line;
if (!check(p, TK_LPAREN)) return parse_for_in(p);
expect(p, TK_LPAREN, "'('");
Stmt *init = NULL; Expr *cond = NULL; Expr *step = NULL;
if (match(p, TK_LET)) {
char *name = adv(p)->text;
Expr *v = NULL;
if (match(p, TK_ASSIGN)) v = parse_expression(p);
init = stmt_let(p->a, name, v, line);
expect(p, TK_SEMI, "';'");
} else if (!match(p, TK_SEMI)) {
Expr *e = parse_expression(p);
init = stmt_expr(p->a, e, line);
expect(p, TK_SEMI, "';'");
}
if (!match(p, TK_SEMI)) { cond = parse_expression(p); expect(p, TK_SEMI, "';'"); }
if (!match(p, TK_RPAREN)) { step = parse_expression(p); expect(p, TK_RPAREN, "')'"); }
Stmt *body = parse_statement(p);
return stmt_for(p->a, init, cond, step, body, line);
}
static Stmt *parse_return(Parser *p) {
int line = adv(p)->line;
Expr *v = NULL;
if (!match(p, TK_SEMI)) { v = parse_expression(p); expect(p, TK_SEMI, "';'"); }
return stmt_return(p->a, v, line);
}
static Stmt *parse_break(Parser *p) {
int line = adv(p)->line;
expect(p, TK_SEMI, "';' after break");
return stmt_break(p->a, line);
}
static Stmt *parse_continue(Parser *p) {
int line = adv(p)->line;
expect(p, TK_SEMI, "';' after continue");
return stmt_continue(p->a, line);
}
static Stmt *parse_for_in(Parser *p) {
int line = peek(p)->line;
if (!check(p, TK_IDENT)) { perr(p, "行 %d: for-in 后期望变量名", line); return stmt_nil(p->a, line); }
char *var = adv(p)->text;
if (!match(p, TK_IN)) { perr(p, "行 %d: for-in 期望 'in'", peek(p)->line); return stmt_nil(p->a, line); }
Expr *iterable = parse_expression(p);
Stmt *body = parse_statement(p);
return stmt_for_in(p->a, var, iterable, body, line);
}
static Expr *parse_lambda(Parser *p, int line) {
expect(p, TK_LPAREN, "'('");
char **params = NULL; int pcount = 0, pcap = 0;
if (!check(p, TK_RPAREN)) {
if (!check(p, TK_IDENT)) { perr(p, "行 %d: 参数应为标识符", line); }
else {
param_push(p->a, ¶ms, &pcount, &pcap, adv(p)->text);
while (match(p, TK_COMMA)) param_push(p->a, ¶ms, &pcount, &pcap, adv(p)->text);
}
}
expect(p, TK_RPAREN, "')'");
Stmt *body = parse_block(p);
Stmt *func = stmt_func(p->a, NULL, params, pcount, body, line);
return expr_lambda(p->a, func, line);
}
static Stmt *parse_func(Parser *p) {
int line = adv(p)->line;
if (!check(p, TK_IDENT)) { perr(p, "行 %d: func 后期望函数名", line); return stmt_nil(p->a, line); }
char *name = adv(p)->text;
expect(p, TK_LPAREN, "'('");
char **params = NULL; int pcount = 0, pcap = 0;
if (!check(p, TK_RPAREN)) {
if (!check(p, TK_IDENT)) { perr(p, "行 %d: 参数应为标识符", line); }
else {
param_push(p->a, ¶ms, &pcount, &pcap, adv(p)->text);
while (match(p, TK_COMMA)) param_push(p->a, ¶ms, &pcount, &pcap, adv(p)->text);
}
}
expect(p, TK_RPAREN, "')'");
Stmt *body = parse_block(p);
return stmt_func(p->a, name, params, pcount, body, line);
}
static Stmt *parse_block(Parser *p) {
int line = adv(p)->line;
Stmt **stmts = NULL; int count = 0, cap = 0;
while (!check(p, TK_RBRACE) && !check(p, TK_EOF)) {
stmt_push(p->a, &stmts, &count, &cap, parse_statement(p));
if (p->prog.has_error) break;
}
expect(p, TK_RBRACE, "'}'");
return stmt_block(p->a, stmts, count, line);
}
static Stmt *parse_try(Parser *p) {
int line = adv(p)->line;
if (!check(p, TK_LBRACE)) { perr(p, "行 %d: try 后期望 '{'", line); return stmt_nil(p->a, line); }
Stmt *body = parse_block(p);
char *catchvar = NULL;
Stmt *catchbody = NULL;
Stmt *finallybody = NULL;
if (check(p, TK_CATCH)) {
adv(p);
if (match(p, TK_LPAREN)) {
if (!check(p, TK_IDENT)) { perr(p, "行 %d: catch 后期望变量名", peek(p)->line); }
else catchvar = adv(p)->text;
expect(p, TK_RPAREN, "')'");
}
if (!check(p, TK_LBRACE)) { perr(p, "行 %d: catch 后期望 '{'", peek(p)->line); return stmt_nil(p->a, line); }
catchbody = parse_block(p);
}
if (check(p, TK_FINALLY)) {
adv(p);
if (!check(p, TK_LBRACE)) { perr(p, "行 %d: finally 后期望 '{'", peek(p)->line); return stmt_nil(p->a, line); }
finallybody = parse_block(p);
}
if (!catchbody && !finallybody) {
perr(p, "行 %d: try 需要 catch 或 finally", line);
return stmt_nil(p->a, line);
}
return stmt_try(p->a, body, catchvar, catchbody, finallybody, line);
}
static Stmt *parse_throw(Parser *p) {
int line = adv(p)->line;
Expr *v = NULL;
if (!check(p, TK_SEMI)) { v = parse_expression(p); expect(p, TK_SEMI, "';' after throw 表达式"); }
return stmt_throw(p->a, v, line);
}
static Stmt *parse_statement(Parser *p) {
if (p->prog.has_error) return stmt_nil(p->a, peek(p)->line);
if (check(p, TK_LET)) return parse_let(p);
if (check(p, TK_IF)) return parse_if(p);
if (check(p, TK_WHILE)) return parse_while(p);
if (check(p, TK_FOR)) return parse_for(p);
if (check(p, TK_RETURN))return parse_return(p);
if (check(p, TK_BREAK)) return parse_break(p);
if (check(p, TK_CONTINUE)) return parse_continue(p);
if (check(p, TK_FUNC)) return parse_func(p);
if (check(p, TK_TRY)) return parse_try(p);
if (check(p, TK_THROW)) return parse_throw(p);
if (check(p, TK_LBRACE))return parse_block(p);
if (check(p, TK_IDENT) && p->pos + 1 < p->tl->count &&
p->tl->tokens[p->pos + 1].type == TK_ASSIGN) return parse_assign(p);
Expr *e = parse_expression(p);
expect(p, TK_SEMI, "';'");
return stmt_expr(p->a, e, peek(p)->line);
}
Program parse(Arena *a, TokenList *tl) {
Parser p; p.tl = tl; p.pos = 0; p.a = a;
p.prog.stmts = NULL; p.prog.count = 0; p.prog.cap = 0; p.prog.has_error = 0;
while (!check(&p, TK_EOF)) {
stmt_push(a, &p.prog.stmts, &p.prog.count, &p.prog.cap, parse_statement(&p));
if (p.prog.has_error) break;
}
return p.prog;
}