Page MenuHomePhorge

ast.c
No OneTemporary

Size
31 KB
Referenced Files
None
Subscribers
None
#include "ast.h"
#include "internal.h"
#include "runtime.h"
#include <oxc.h>
#include <yyjson.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
static inline bool is_err(jsval_t v) { return vtype(v) == T_ERR; }
ast_ctx_t *ast_parse(struct js *js, const char *code, size_t len, const char *filename) {
(void)len;
OxcParseResult *result = OXC_parse(code, filename);
if (!result) return NULL;
if (!result->success) {
if (result->error_msg) {
js_mkerr_typed(js, JS_ERR_SYNTAX, "%s", result->error_msg);
} else {
js_mkerr_typed(js, JS_ERR_SYNTAX, "parse error");
}
OXC_free_result(result);
return NULL;
}
yyjson_doc *doc = yyjson_read(result->json, result->json_len, 0);
OXC_free_result(result);
if (!doc) {
js_mkerr_typed(js, JS_ERR_SYNTAX, "failed to parse AST JSON");
return NULL;
}
ast_ctx_t *ctx = malloc(sizeof(ast_ctx_t));
if (!ctx) {
yyjson_doc_free(doc);
return NULL;
}
ctx->js = js;
ctx->doc = doc;
ctx->root = yyjson_doc_get_root(doc);
return ctx;
}
void ast_free(ast_ctx_t *ctx) {
if (!ctx) return;
if (ctx->doc) yyjson_doc_free(ctx->doc);
free(ctx);
}
jsval_t js_eval_ast(struct js *js, const char *code, size_t len, const char *filename) {
ast_ctx_t *ctx = ast_parse(js, code, len, filename);
if (!ctx) {
return js_mkerr_typed(js, JS_ERR_SYNTAX, "failed to parse code");
}
jsval_t result = ast_eval_program(js, ctx);
ast_free(ctx);
return result;
}
typedef jsval_t (*stmt_eval_fn)(struct js *js, yyjson_val *node);
typedef jsval_t (*expr_eval_fn)(struct js *js, yyjson_val *node);
static jsval_t eval_identifier(struct js *js, yyjson_val *node);
static jsval_t eval_literal(struct js *js, yyjson_val *node);
static jsval_t eval_binary_expr(struct js *js, yyjson_val *node);
static jsval_t eval_unary_expr(struct js *js, yyjson_val *node);
static jsval_t eval_update_expr(struct js *js, yyjson_val *node);
static jsval_t eval_logical_expr(struct js *js, yyjson_val *node);
static jsval_t eval_conditional_expr(struct js *js, yyjson_val *node);
static jsval_t eval_assignment_expr(struct js *js, yyjson_val *node);
static jsval_t eval_member_expr(struct js *js, yyjson_val *node);
static jsval_t eval_call_expr(struct js *js, yyjson_val *node);
static jsval_t eval_new_expr(struct js *js, yyjson_val *node);
static jsval_t eval_array_expr(struct js *js, yyjson_val *node);
static jsval_t eval_object_expr(struct js *js, yyjson_val *node);
static jsval_t eval_function_expr(struct js *js, yyjson_val *node);
static jsval_t eval_arrow_function(struct js *js, yyjson_val *node);
static jsval_t eval_sequence_expr(struct js *js, yyjson_val *node);
static jsval_t eval_this_expr(struct js *js, yyjson_val *node);
static jsval_t eval_template_literal(struct js *js, yyjson_val *node);
static jsval_t eval_tagged_template(struct js *js, yyjson_val *node);
static jsval_t eval_spread_element(struct js *js, yyjson_val *node);
static jsval_t eval_await_expr(struct js *js, yyjson_val *node);
static jsval_t eval_yield_expr(struct js *js, yyjson_val *node);
static jsval_t eval_class_expr(struct js *js, yyjson_val *node);
static jsval_t eval_super_expr(struct js *js, yyjson_val *node);
static jsval_t eval_import_expr(struct js *js, yyjson_val *node);
static jsval_t eval_meta_property(struct js *js, yyjson_val *node);
static jsval_t eval_chain_expr(struct js *js, yyjson_val *node);
static jsval_t eval_block_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_expr_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_if_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_while_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_do_while_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_for_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_for_in_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_for_of_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_switch_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_return_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_break_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_continue_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_throw_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_try_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_var_decl(struct js *js, yyjson_val *node);
static jsval_t eval_function_decl(struct js *js, yyjson_val *node);
static jsval_t eval_class_decl(struct js *js, yyjson_val *node);
static jsval_t eval_import_decl(struct js *js, yyjson_val *node);
static jsval_t eval_export_decl(struct js *js, yyjson_val *node);
static jsval_t eval_labeled_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_with_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_empty_stmt(struct js *js, yyjson_val *node);
static jsval_t eval_debugger_stmt(struct js *js, yyjson_val *node);
typedef struct {
const char *type;
expr_eval_fn fn;
} expr_dispatch_t;
typedef struct {
const char *type;
stmt_eval_fn fn;
} stmt_dispatch_t;
static const expr_dispatch_t expr_dispatch[] = {
{"Identifier", eval_identifier},
{"Literal", eval_literal},
{"NumericLiteral", eval_literal},
{"StringLiteral", eval_literal},
{"BooleanLiteral", eval_literal},
{"NullLiteral", eval_literal},
{"BigIntLiteral", eval_literal},
{"RegExpLiteral", eval_literal},
{"BinaryExpression", eval_binary_expr},
{"UnaryExpression", eval_unary_expr},
{"UpdateExpression", eval_update_expr},
{"LogicalExpression", eval_logical_expr},
{"ConditionalExpression", eval_conditional_expr},
{"AssignmentExpression", eval_assignment_expr},
{"MemberExpression", eval_member_expr},
{"CallExpression", eval_call_expr},
{"NewExpression", eval_new_expr},
{"ArrayExpression", eval_array_expr},
{"ObjectExpression", eval_object_expr},
{"FunctionExpression", eval_function_expr},
{"ArrowFunctionExpression", eval_arrow_function},
{"SequenceExpression", eval_sequence_expr},
{"ThisExpression", eval_this_expr},
{"TemplateLiteral", eval_template_literal},
{"TaggedTemplateExpression", eval_tagged_template},
{"SpreadElement", eval_spread_element},
{"AwaitExpression", eval_await_expr},
{"YieldExpression", eval_yield_expr},
{"ClassExpression", eval_class_expr},
{"Super", eval_super_expr},
{"ImportExpression", eval_import_expr},
{"MetaProperty", eval_meta_property},
{"ChainExpression", eval_chain_expr},
{NULL, NULL}
};
static const stmt_dispatch_t stmt_dispatch[] = {
{"BlockStatement", eval_block_stmt},
{"ExpressionStatement", eval_expr_stmt},
{"IfStatement", eval_if_stmt},
{"WhileStatement", eval_while_stmt},
{"DoWhileStatement", eval_do_while_stmt},
{"ForStatement", eval_for_stmt},
{"ForInStatement", eval_for_in_stmt},
{"ForOfStatement", eval_for_of_stmt},
{"SwitchStatement", eval_switch_stmt},
{"ReturnStatement", eval_return_stmt},
{"BreakStatement", eval_break_stmt},
{"ContinueStatement", eval_continue_stmt},
{"ThrowStatement", eval_throw_stmt},
{"TryStatement", eval_try_stmt},
{"VariableDeclaration", eval_var_decl},
{"FunctionDeclaration", eval_function_decl},
{"ClassDeclaration", eval_class_decl},
{"ImportDeclaration", eval_import_decl},
{"ExportNamedDeclaration", eval_export_decl},
{"ExportDefaultDeclaration", eval_export_decl},
{"ExportAllDeclaration", eval_export_decl},
{"LabeledStatement", eval_labeled_stmt},
{"WithStatement", eval_with_stmt},
{"EmptyStatement", eval_empty_stmt},
{"DebuggerStatement", eval_debugger_stmt},
{NULL, NULL}
};
static jsval_t lookup_var(struct js *js, const char *name, size_t len);
static jsval_t set_var(struct js *js, const char *name, size_t len, jsval_t val);
static jsval_t declare_var(struct js *js, const char *name, size_t len, jsval_t val, const char *kind);
jsval_t ast_eval_expr(struct js *js, yyjson_val *node) {
if (!node) return js_mkundef();
const char *type = ast_node_type(node);
if (!type) return js_mkerr_typed(js, JS_ERR_SYNTAX, "invalid AST node");
for (const expr_dispatch_t *d = expr_dispatch; d->type; d++) {
if (strcmp(type, d->type) == 0) {
return d->fn(js, node);
}
}
for (const stmt_dispatch_t *d = stmt_dispatch; d->type; d++) {
if (strcmp(type, d->type) == 0) {
return d->fn(js, node);
}
}
return js_mkerr(js, "unsupported AST node: %s", type);
}
jsval_t ast_eval_stmt(struct js *js, yyjson_val *node) {
if (!node) return js_mkundef();
const char *type = ast_node_type(node);
if (!type) return js_mkerr_typed(js, JS_ERR_SYNTAX, "invalid AST node");
for (const stmt_dispatch_t *d = stmt_dispatch; d->type; d++) {
if (strcmp(type, d->type) == 0) {
return d->fn(js, node);
}
}
return ast_eval_expr(js, node);
}
jsval_t ast_eval_node(struct js *js, yyjson_val *node) {
return ast_eval_stmt(js, node);
}
jsval_t ast_eval_program(struct js *js, ast_ctx_t *ctx) {
if (!ctx || !ctx->root) return js_mkundef();
const char *type = ast_node_type(ctx->root);
if (!type || strcmp(type, "Program") != 0) {
return js_mkerr_typed(js, JS_ERR_SYNTAX, "expected Program node");
}
yyjson_val *body = ast_get(ctx->root, "body");
if (!body || !yyjson_is_arr(body)) return js_mkundef();
jsval_t result = js_mkundef();
size_t idx, max;
yyjson_val *stmt;
yyjson_arr_foreach(body, idx, max, stmt) {
result = ast_eval_stmt(js, stmt);
if (is_err(result)) break;
if (js->flags & (F_RETURN | F_THROW | F_BREAK)) break;
}
return result;
}
static jsval_t lookup_var(struct js *js, const char *name, size_t len) {
jsval_t key = js_mkstr(js, name, len);
return js_get(js, js->scope, js_getstr(js, key, NULL));
}
static jsval_t set_var(struct js *js, const char *name, size_t len, jsval_t val) {
jsval_t key = js_mkstr(js, name, len);
js_set(js, js->scope, js_getstr(js, key, NULL), val);
return val;
}
static jsval_t declare_var(struct js *js, const char *name, size_t len, jsval_t val, const char *kind) {
(void)kind;
return set_var(js, name, len, val);
}
static jsval_t eval_identifier(struct js *js, yyjson_val *node) {
const char *name = ast_get_str(node, "name");
if (!name) return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier missing name");
size_t len = strlen(name);
if (strcmp(name, "undefined") == 0) return js_mkundef();
if (strcmp(name, "NaN") == 0) return js_mknum(NAN);
if (strcmp(name, "Infinity") == 0) return js_mknum(INFINITY);
jsval_t val = lookup_var(js, name, len);
if (js_type(val) == JS_UNDEF) {
return js_mkerr_typed(js, JS_ERR_REFERENCE, "%s is not defined", name);
}
return val;
}
static jsval_t eval_literal(struct js *js, yyjson_val *node) {
const char *type = ast_node_type(node);
if (strcmp(type, "NullLiteral") == 0) {
return js_mknull();
}
if (strcmp(type, "BooleanLiteral") == 0) {
yyjson_val *val = ast_get(node, "value");
return yyjson_get_bool(val) ? js_mktrue() : js_mkfalse();
}
if (strcmp(type, "NumericLiteral") == 0) {
yyjson_val *val = ast_get(node, "value");
return js_mknum(yyjson_get_real(val));
}
if (strcmp(type, "StringLiteral") == 0) {
yyjson_val *val = ast_get(node, "value");
const char *str = yyjson_get_str(val);
size_t len = yyjson_get_len(val);
return js_mkstr(js, str, len);
}
if (strcmp(type, "BigIntLiteral") == 0) {
return js_mkerr(js, "BigInt literals not yet supported in AST evaluator");
}
if (strcmp(type, "RegExpLiteral") == 0) {
return js_mkerr(js, "RegExp literals not yet supported in AST evaluator");
}
if (strcmp(type, "Literal") == 0) {
yyjson_val *val = ast_get(node, "value");
if (yyjson_is_null(val)) return js_mknull();
if (yyjson_is_bool(val)) return yyjson_get_bool(val) ? js_mktrue() : js_mkfalse();
if (yyjson_is_num(val)) return js_mknum(yyjson_get_real(val));
if (yyjson_is_str(val)) {
const char *str = yyjson_get_str(val);
size_t len = yyjson_get_len(val);
return js_mkstr(js, str, len);
}
yyjson_val *regex = ast_get(node, "regex");
if (regex) {
return js_mkerr(js, "RegExp literals not yet supported in AST evaluator");
}
yyjson_val *bigint = ast_get(node, "bigint");
if (bigint) {
return js_mkerr(js, "BigInt literals not yet supported in AST evaluator");
}
return js_mkundef();
}
return js_mkerr(js, "unknown literal type: %s", type);
}
static inline int32_t to_int32(double d) {
if (!isfinite(d) || d == 0.0) return 0;
d = trunc(d);
d = fmod(d, 4294967296.0);
if (d >= 2147483648.0) d -= 4294967296.0;
else if (d < -2147483648.0) d += 4294967296.0;
return (int32_t)d;
}
static inline uint32_t to_uint32(double d) {
if (!isfinite(d) || d == 0.0) return 0;
d = trunc(d);
d = fmod(d, 4294967296.0);
if (d < 0) d += 4294967296.0;
return (uint32_t)d;
}
static double js_to_number_simple(struct js *js, jsval_t v) {
switch (vtype(v)) {
case T_NUM: return js_getnum(v);
case T_BOOL: return js_getbool(v) ? 1.0 : 0.0;
case T_NULL: return 0.0;
case T_UNDEF: return NAN;
case T_STR: {
size_t len;
char *s = js_getstr(js, v, &len);
if (len == 0) return 0.0;
char *end;
double d = strtod(s, &end);
while (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r') end++;
return (*end == '\0') ? d : NAN;
}
default: return NAN;
}
}
static bool strict_eq(struct js *js, jsval_t l, jsval_t r) {
uint8_t lt = vtype(l), rt = vtype(r);
if (lt != rt) return false;
switch (lt) {
case T_UNDEF: case T_NULL: return true;
case T_BOOL: return js_getbool(l) == js_getbool(r);
case T_NUM: {
double ld = js_getnum(l), rd = js_getnum(r);
if (isnan(ld) || isnan(rd)) return false;
return ld == rd;
}
case T_STR: {
size_t ll, rl;
char *ls = js_getstr(js, l, &ll);
char *rs = js_getstr(js, r, &rl);
return ll == rl && memcmp(ls, rs, ll) == 0;
}
default: return vdata(l) == vdata(r);
}
}
static int compare_vals(struct js *js, jsval_t l, jsval_t r) {
double ld = js_to_number_simple(js, l);
double rd = js_to_number_simple(js, r);
if (isnan(ld) || isnan(rd)) return 2;
if (ld < rd) return -1;
if (ld > rd) return 1;
return 0;
}
static jsval_t eval_binary_expr(struct js *js, yyjson_val *node) {
const char *op = ast_get_str(node, "operator");
yyjson_val *left = ast_get(node, "left");
yyjson_val *right = ast_get(node, "right");
jsval_t lval = ast_eval_expr(js, left);
if (is_err(lval)) return lval;
jsval_t rval = ast_eval_expr(js, right);
if (is_err(rval)) return rval;
if (strcmp(op, "+") == 0) {
if (vtype(lval) == T_STR || vtype(rval) == T_STR) {
const char *ls = js_str(js, lval);
const char *rs = js_str(js, rval);
size_t ll = strlen(ls), rl = strlen(rs);
char *buf = malloc(ll + rl + 1);
memcpy(buf, ls, ll);
memcpy(buf + ll, rs, rl + 1);
jsval_t result = js_mkstr(js, buf, ll + rl);
free(buf);
return result;
}
return js_mknum(js_to_number_simple(js, lval) + js_to_number_simple(js, rval));
}
if (strcmp(op, "-") == 0) return js_mknum(js_to_number_simple(js, lval) - js_to_number_simple(js, rval));
if (strcmp(op, "*") == 0) return js_mknum(js_to_number_simple(js, lval) * js_to_number_simple(js, rval));
if (strcmp(op, "/") == 0) return js_mknum(js_to_number_simple(js, lval) / js_to_number_simple(js, rval));
if (strcmp(op, "%") == 0) return js_mknum(fmod(js_to_number_simple(js, lval), js_to_number_simple(js, rval)));
if (strcmp(op, "**") == 0) return js_mknum(pow(js_to_number_simple(js, lval), js_to_number_simple(js, rval)));
if (strcmp(op, "&") == 0) return js_mknum((double)(to_int32(js_to_number_simple(js, lval)) & to_int32(js_to_number_simple(js, rval))));
if (strcmp(op, "|") == 0) return js_mknum((double)(to_int32(js_to_number_simple(js, lval)) | to_int32(js_to_number_simple(js, rval))));
if (strcmp(op, "^") == 0) return js_mknum((double)(to_int32(js_to_number_simple(js, lval)) ^ to_int32(js_to_number_simple(js, rval))));
if (strcmp(op, "<<") == 0) return js_mknum((double)(to_int32(js_to_number_simple(js, lval)) << (to_uint32(js_to_number_simple(js, rval)) & 0x1f)));
if (strcmp(op, ">>") == 0) return js_mknum((double)(to_int32(js_to_number_simple(js, lval)) >> (to_uint32(js_to_number_simple(js, rval)) & 0x1f)));
if (strcmp(op, ">>>") == 0) return js_mknum((double)(to_uint32(js_to_number_simple(js, lval)) >> (to_uint32(js_to_number_simple(js, rval)) & 0x1f)));
if (strcmp(op, "===") == 0) return strict_eq(js, lval, rval) ? js_mktrue() : js_mkfalse();
if (strcmp(op, "!==") == 0) return strict_eq(js, lval, rval) ? js_mkfalse() : js_mktrue();
if (strcmp(op, "==") == 0) return strict_eq(js, lval, rval) ? js_mktrue() : js_mkfalse();
if (strcmp(op, "!=") == 0) return strict_eq(js, lval, rval) ? js_mkfalse() : js_mktrue();
if (strcmp(op, "<") == 0) { int c = compare_vals(js, lval, rval); return c == 2 ? js_mkfalse() : (c < 0 ? js_mktrue() : js_mkfalse()); }
if (strcmp(op, ">") == 0) { int c = compare_vals(js, lval, rval); return c == 2 ? js_mkfalse() : (c > 0 ? js_mktrue() : js_mkfalse()); }
if (strcmp(op, "<=") == 0) { int c = compare_vals(js, lval, rval); return c == 2 ? js_mkfalse() : (c <= 0 ? js_mktrue() : js_mkfalse()); }
if (strcmp(op, ">=") == 0) { int c = compare_vals(js, lval, rval); return c == 2 ? js_mkfalse() : (c >= 0 ? js_mktrue() : js_mkfalse()); }
if (strcmp(op, "in") == 0) {
if (vtype(rval) != T_OBJ && vtype(rval) != T_ARR && vtype(rval) != T_FUNC) {
return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot use 'in' operator to search for '%s' in non-object", js_str(js, lval));
}
const char *key = js_str(js, lval);
jsval_t found = js_get(js, rval, key);
return js_type(found) != JS_UNDEF ? js_mktrue() : js_mkfalse();
}
if (strcmp(op, "instanceof") == 0) {
return js_mkfalse();
}
return js_mkerr(js, "unknown binary operator: %s", op);
}
static const char *typeof_str(uint8_t t) {
switch (t) {
case T_UNDEF: return "undefined";
case T_NULL: return "object";
case T_BOOL: return "boolean";
case T_NUM: return "number";
case T_STR: return "string";
case T_SYMBOL: return "symbol";
case T_BIGINT: return "bigint";
case T_FUNC: case T_CFUNC: return "function";
default: return "object";
}
}
static jsval_t eval_unary_expr(struct js *js, yyjson_val *node) {
const char *op = ast_get_str(node, "operator");
yyjson_val *arg = ast_get(node, "argument");
if (strcmp(op, "typeof") == 0) {
const char *arg_type = ast_node_type(arg);
if (arg_type && strcmp(arg_type, "Identifier") == 0) {
const char *name = ast_get_str(arg, "name");
if (name) {
jsval_t val = lookup_var(js, name, strlen(name));
if (js_type(val) == JS_UNDEF || is_err(val)) {
return js_mkstr(js, "undefined", 9);
}
const char *ts = typeof_str(vtype(val));
return js_mkstr(js, ts, strlen(ts));
}
}
jsval_t val = ast_eval_expr(js, arg);
if (is_err(val)) return val;
const char *ts = typeof_str(vtype(val));
return js_mkstr(js, ts, strlen(ts));
}
if (strcmp(op, "delete") == 0) {
return js_mktrue();
}
if (strcmp(op, "void") == 0) {
jsval_t val = ast_eval_expr(js, arg);
if (is_err(val)) return val;
return js_mkundef();
}
jsval_t val = ast_eval_expr(js, arg);
if (is_err(val)) return val;
if (strcmp(op, "-") == 0) return js_mknum(-js_to_number_simple(js, val));
if (strcmp(op, "+") == 0) return js_mknum(js_to_number_simple(js, val));
if (strcmp(op, "!") == 0) return js_truthy(js, val) ? js_mkfalse() : js_mktrue();
if (strcmp(op, "~") == 0) return js_mknum((double)(~to_int32(js_to_number_simple(js, val))));
return js_mkerr(js, "unknown unary operator: %s", op);
}
static jsval_t eval_update_expr(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "UpdateExpression not yet implemented");
}
static jsval_t eval_logical_expr(struct js *js, yyjson_val *node) {
const char *op = ast_get_str(node, "operator");
yyjson_val *left = ast_get(node, "left");
yyjson_val *right = ast_get(node, "right");
jsval_t lval = ast_eval_expr(js, left);
if (is_err(lval)) return lval;
if (strcmp(op, "&&") == 0) {
if (!js_truthy(js, lval)) return lval;
return ast_eval_expr(js, right);
}
if (strcmp(op, "||") == 0) {
if (js_truthy(js, lval)) return lval;
return ast_eval_expr(js, right);
}
if (strcmp(op, "??") == 0) {
if (js_type(lval) != JS_NULL && js_type(lval) != JS_UNDEF) return lval;
return ast_eval_expr(js, right);
}
return js_mkerr(js, "unknown logical operator: %s", op);
}
static jsval_t eval_conditional_expr(struct js *js, yyjson_val *node) {
yyjson_val *test = ast_get(node, "test");
yyjson_val *consequent = ast_get(node, "consequent");
yyjson_val *alternate = ast_get(node, "alternate");
jsval_t cond = ast_eval_expr(js, test);
if (is_err(cond)) return cond;
if (js_truthy(js, cond)) {
return ast_eval_expr(js, consequent);
} else {
return ast_eval_expr(js, alternate);
}
}
static jsval_t eval_assignment_expr(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "AssignmentExpression not yet implemented");
}
static jsval_t eval_member_expr(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "MemberExpression not yet implemented");
}
static jsval_t eval_call_expr(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "CallExpression not yet implemented");
}
static jsval_t eval_new_expr(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "NewExpression not yet implemented");
}
static jsval_t eval_array_expr(struct js *js, yyjson_val *node) {
yyjson_val *elements = ast_get(node, "elements");
if (!elements || !yyjson_is_arr(elements)) {
return js_mkarr(js);
}
jsval_t arr = js_mkarr(js);
size_t idx, max;
yyjson_val *elem;
yyjson_arr_foreach(elements, idx, max, elem) {
jsval_t val;
if (yyjson_is_null(elem)) {
val = js_mkundef();
} else {
val = ast_eval_expr(js, elem);
if (is_err(val)) return val;
}
js_arr_push(js, arr, val);
}
return arr;
}
static jsval_t eval_object_expr(struct js *js, yyjson_val *node) {
yyjson_val *properties = ast_get(node, "properties");
jsval_t obj = js_mkobj(js);
if (!properties || !yyjson_is_arr(properties)) return obj;
size_t idx, max;
yyjson_val *prop;
yyjson_arr_foreach(properties, idx, max, prop) {
const char *prop_type = ast_node_type(prop);
if (!prop_type) continue;
if (strcmp(prop_type, "SpreadElement") == 0) {
yyjson_val *arg = ast_get(prop, "argument");
jsval_t spread_val = ast_eval_expr(js, arg);
if (is_err(spread_val)) return spread_val;
continue;
}
yyjson_val *key_node = ast_get(prop, "key");
yyjson_val *value_node = ast_get(prop, "value");
const char *key = NULL;
const char *key_type = ast_node_type(key_node);
if (key_type && strcmp(key_type, "Identifier") == 0) {
key = ast_get_str(key_node, "name");
} else if (key_type && (strcmp(key_type, "StringLiteral") == 0 || strcmp(key_type, "Literal") == 0)) {
yyjson_val *kval = ast_get(key_node, "value");
key = yyjson_get_str(kval);
}
if (!key) continue;
jsval_t val = ast_eval_expr(js, value_node);
if (is_err(val)) return val;
js_set(js, obj, key, val);
}
return obj;
}
static jsval_t eval_function_expr(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "FunctionExpression not yet implemented");
}
static jsval_t eval_arrow_function(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "ArrowFunctionExpression not yet implemented");
}
static jsval_t eval_sequence_expr(struct js *js, yyjson_val *node) {
yyjson_val *expressions = ast_get(node, "expressions");
if (!expressions || !yyjson_is_arr(expressions)) return js_mkundef();
jsval_t result = js_mkundef();
size_t idx, max;
yyjson_val *expr;
yyjson_arr_foreach(expressions, idx, max, expr) {
result = ast_eval_expr(js, expr);
if (is_err(result)) return result;
}
return result;
}
static jsval_t eval_this_expr(struct js *js, yyjson_val *node) {
(void)node;
return js->this_val;
}
static jsval_t eval_template_literal(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "TemplateLiteral not yet implemented");
}
static jsval_t eval_tagged_template(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "TaggedTemplateExpression not yet implemented");
}
static jsval_t eval_spread_element(struct js *js, yyjson_val *node) {
yyjson_val *arg = ast_get(node, "argument");
return ast_eval_expr(js, arg);
}
static jsval_t eval_await_expr(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "AwaitExpression not yet implemented");
}
static jsval_t eval_yield_expr(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "YieldExpression not yet implemented");
}
static jsval_t eval_class_expr(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "ClassExpression not yet implemented");
}
static jsval_t eval_super_expr(struct js *js, yyjson_val *node) {
(void)node;
return js->super_val;
}
static jsval_t eval_import_expr(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "ImportExpression not yet implemented");
}
static jsval_t eval_meta_property(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "MetaProperty not yet implemented");
}
static jsval_t eval_chain_expr(struct js *js, yyjson_val *node) {
yyjson_val *expr = ast_get(node, "expression");
return ast_eval_expr(js, expr);
}
static jsval_t eval_block_stmt(struct js *js, yyjson_val *node) {
yyjson_val *body = ast_get(node, "body");
if (!body || !yyjson_is_arr(body)) return js_mkundef();
jsval_t result = js_mkundef();
size_t idx, max;
yyjson_val *stmt;
yyjson_arr_foreach(body, idx, max, stmt) {
result = ast_eval_stmt(js, stmt);
if (is_err(result)) return result;
if (js->flags & (F_RETURN | F_THROW | F_BREAK)) break;
}
return result;
}
static jsval_t eval_expr_stmt(struct js *js, yyjson_val *node) {
yyjson_val *expr = ast_get(node, "expression");
return ast_eval_expr(js, expr);
}
static jsval_t eval_if_stmt(struct js *js, yyjson_val *node) {
yyjson_val *test = ast_get(node, "test");
yyjson_val *consequent = ast_get(node, "consequent");
yyjson_val *alternate = ast_get(node, "alternate");
jsval_t cond = ast_eval_expr(js, test);
if (is_err(cond)) return cond;
if (js_truthy(js, cond)) {
return ast_eval_stmt(js, consequent);
} else if (alternate && !yyjson_is_null(alternate)) {
return ast_eval_stmt(js, alternate);
}
return js_mkundef();
}
static jsval_t eval_while_stmt(struct js *js, yyjson_val *node) {
yyjson_val *test = ast_get(node, "test");
yyjson_val *body = ast_get(node, "body");
jsval_t result = js_mkundef();
uint8_t saved_flags = js->flags;
js->flags |= F_LOOP;
while (true) {
jsval_t cond = ast_eval_expr(js, test);
if (is_err(cond)) { result = cond; break; }
if (!js_truthy(js, cond)) break;
result = ast_eval_stmt(js, body);
if (is_err(result)) break;
if (js->flags & F_BREAK) { js->flags &= ~F_BREAK; break; }
if (js->flags & F_RETURN) break;
if (js->flags & F_THROW) break;
}
js->flags = (js->flags & ~F_LOOP) | (saved_flags & F_LOOP);
return result;
}
static jsval_t eval_do_while_stmt(struct js *js, yyjson_val *node) {
yyjson_val *test = ast_get(node, "test");
yyjson_val *body = ast_get(node, "body");
jsval_t result = js_mkundef();
uint8_t saved_flags = js->flags;
js->flags |= F_LOOP;
do {
result = ast_eval_stmt(js, body);
if (is_err(result)) break;
if (js->flags & F_BREAK) { js->flags &= ~F_BREAK; break; }
if (js->flags & F_RETURN) break;
if (js->flags & F_THROW) break;
jsval_t cond = ast_eval_expr(js, test);
if (is_err(cond)) { result = cond; break; }
if (!js_truthy(js, cond)) break;
} while (true);
js->flags = (js->flags & ~F_LOOP) | (saved_flags & F_LOOP);
return result;
}
static jsval_t eval_for_stmt(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "ForStatement not yet implemented");
}
static jsval_t eval_for_in_stmt(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "ForInStatement not yet implemented");
}
static jsval_t eval_for_of_stmt(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "ForOfStatement not yet implemented");
}
static jsval_t eval_switch_stmt(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "SwitchStatement not yet implemented");
}
static jsval_t eval_return_stmt(struct js *js, yyjson_val *node) {
yyjson_val *arg = ast_get(node, "argument");
if (arg && !yyjson_is_null(arg)) {
jsval_t val = ast_eval_expr(js, arg);
if (is_err(val)) return val;
js->flags |= F_RETURN;
return val;
}
js->flags |= F_RETURN;
return js_mkundef();
}
static jsval_t eval_break_stmt(struct js *js, yyjson_val *node) {
(void)node;
js->flags |= F_BREAK;
return js_mkundef();
}
static jsval_t eval_continue_stmt(struct js *js, yyjson_val *node) {
(void)node;
return js_mkundef();
}
static jsval_t eval_throw_stmt(struct js *js, yyjson_val *node) {
yyjson_val *arg = ast_get(node, "argument");
jsval_t val = ast_eval_expr(js, arg);
js->flags |= F_THROW;
js->thrown_value = val;
return js_mkerr(js, "Uncaught %s", js_str(js, val));
}
static jsval_t eval_try_stmt(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "TryStatement not yet implemented");
}
static jsval_t eval_var_decl(struct js *js, yyjson_val *node) {
const char *kind = ast_get_str(node, "kind");
yyjson_val *declarations = ast_get(node, "declarations");
if (!declarations || !yyjson_is_arr(declarations)) return js_mkundef();
size_t idx, max;
yyjson_val *decl;
yyjson_arr_foreach(declarations, idx, max, decl) {
yyjson_val *id = ast_get(decl, "id");
yyjson_val *init = ast_get(decl, "init");
const char *id_type = ast_node_type(id);
if (!id_type) continue;
if (strcmp(id_type, "Identifier") == 0) {
const char *name = ast_get_str(id, "name");
if (!name) continue;
jsval_t val = js_mkundef();
if (init && !yyjson_is_null(init)) {
val = ast_eval_expr(js, init);
if (is_err(val)) return val;
}
declare_var(js, name, strlen(name), val, kind);
}
}
return js_mkundef();
}
static jsval_t eval_function_decl(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "FunctionDeclaration not yet implemented");
}
static jsval_t eval_class_decl(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "ClassDeclaration not yet implemented");
}
static jsval_t eval_import_decl(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "ImportDeclaration not yet implemented");
}
static jsval_t eval_export_decl(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "ExportDeclaration not yet implemented");
}
static jsval_t eval_labeled_stmt(struct js *js, yyjson_val *node) {
yyjson_val *body = ast_get(node, "body");
return ast_eval_stmt(js, body);
}
static jsval_t eval_with_stmt(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkerr(js, "WithStatement not yet implemented");
}
static jsval_t eval_empty_stmt(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkundef();
}
static jsval_t eval_debugger_stmt(struct js *js, yyjson_val *node) {
(void)js; (void)node;
return js_mkundef();
}

File Metadata

Mime Type
text/x-c
Expires
Fri, Mar 27, 9:54 AM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
512304
Default Alt Text
ast.c (31 KB)

Event Timeline