Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2921564
ast.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
31 KB
Referenced Files
None
Subscribers
None
ast.c
View Options
#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
Details
Attached
Mime Type
text/x-c
Expires
Fri, Mar 27, 9:54 AM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
512304
Default Alt Text
ast.c (31 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment