1pub mod ast;
2pub mod codegen;
3pub mod ic;
4pub mod lexer;
5pub mod location;
6pub mod mir;
7pub mod opcode;
8pub mod parser;
9pub mod peephole;
10
11pub use codegen::{CodeGenerator, OptLevel};
12pub use ic::{InlineCache, InlineCacheTable};
13pub use lexer::{Lexer, Token, TokenType};
14pub use location::{FrameInfo, LineNumberTable, SourceLocation, TracebackFormatter};
15pub use opcode::{Bytecode, Opcode};
16
17use crate::builtins::promise::run_microtasks_with_vm;
18use crate::runtime::JSContext;
19use crate::runtime::event_loop::EventLoopResult;
20use crate::value::JSValue;
21
22pub fn eval_code(ctx: &mut JSContext, source: &str) -> Result<JSValue, String> {
23 eval_code_via_ast_with_opt_level(ctx, source, ctx.get_compiler_opt_level())
24}
25
26pub fn eval_code_via_ast(ctx: &mut JSContext, source: &str) -> Result<JSValue, String> {
27 eval_code_via_ast_with_opt_level(ctx, source, ctx.get_compiler_opt_level())
28}
29
30pub fn compile_script_to_bytecode_with_opt_level(
31 ctx: &mut JSContext,
32 source: &str,
33 opt_level: OptLevel,
34 is_strict: bool,
35 is_eval: bool,
36) -> Result<Bytecode, String> {
37 let ast = parser::Parser::new(source).parse()?;
38
39 let mut func_codegen = CodeGenerator::with_opt_level(opt_level);
40 func_codegen.is_strict = is_strict;
41 func_codegen.is_eval = is_eval;
42 let block = ast::BlockStatement {
43 body: ast.body,
44 lines: ast.lines,
45 };
46 let (mut rb, _) = func_codegen.compile_script(&block, ctx)?;
47
48 peephole::optimize_with_level(&mut rb, opt_level);
49
50 Ok(rb)
51}
52
53fn eval_bytecode_with_caller(
54 ctx: &mut JSContext,
55 rb: &Bytecode,
56 caller_vm: Option<*mut crate::runtime::vm::VM>,
57) -> Result<JSValue, String> {
58 use crate::runtime::vm::{ExecutionOutcome, VM};
59
60 let saved_register_vm_ptr = ctx.get_register_vm_ptr();
61
62 let mut vm = VM::new();
63 let vm_ptr = &mut vm as *mut _ as usize;
64 ctx.set_register_vm_ptr(Some(vm_ptr));
65
66 let caller_ptr = caller_vm.map(|p| p as usize);
67
68 let caller_this = if let Some(ptr) = caller_vm {
69 let caller = unsafe { &*ptr };
70 let caller_frame = &caller.frames[caller.frame_index];
71 let mut this_val = caller_frame.this_value;
72 if !caller_frame.is_strict_frame && (this_val.is_undefined() || this_val.is_null()) {
73 this_val = ctx.global();
74 }
75 this_val
76 } else {
77 ctx.global()
78 };
79
80 let result = match vm.execute_eval(ctx, rb, caller_this, caller_ptr) {
81 Ok(ExecutionOutcome::Complete(v)) => Ok(v),
82 Ok(ExecutionOutcome::Yield(v)) => Ok(v),
83 Err(e) => Err(e),
84 };
85
86 run_microtasks_with_vm(ctx, &mut vm);
87
88 ctx.set_register_vm_ptr(saved_register_vm_ptr);
89
90 result
91}
92
93pub fn eval_code_via_ast_with_opt_level_as_eval_with_caller(
94 ctx: &mut JSContext,
95 source: &str,
96 opt_level: OptLevel,
97 is_strict: bool,
98 caller_vm: *mut crate::runtime::vm::VM,
99) -> Result<JSValue, String> {
100 let rb = compile_script_to_bytecode_with_opt_level(ctx, source, opt_level, is_strict, true)?;
101 eval_bytecode_with_caller(ctx, &rb, Some(caller_vm))
102}
103
104pub fn eval_code_via_ast_with_opt_level(
105 ctx: &mut JSContext,
106 source: &str,
107 opt_level: OptLevel,
108) -> Result<JSValue, String> {
109 let rb = compile_script_to_bytecode_with_opt_level(ctx, source, opt_level, false, false)?;
110
111 let saved_register_vm_ptr = ctx.get_register_vm_ptr();
112
113 let mut vm = crate::runtime::vm::VM::new();
114 let vm_ptr = &mut vm as *mut _ as usize;
115 ctx.set_register_vm_ptr(Some(vm_ptr));
116
117 let result = match vm.execute_preserving_registers(ctx, &rb) {
118 Ok(crate::runtime::vm::ExecutionOutcome::Complete(v)) => Ok(v),
119 Ok(crate::runtime::vm::ExecutionOutcome::Yield(v)) => Ok(v),
120 Err(e) => Err(e),
121 };
122
123 run_microtasks_with_vm(ctx, &mut vm);
124
125 ctx.set_register_vm_ptr(saved_register_vm_ptr);
126
127 result
128}
129
130pub fn run_event_loop(ctx: &mut JSContext) -> Result<EventLoopResult, String> {
131 ctx.run_event_loop()
132}
133
134pub fn run_event_loop_with_timeout(
135 ctx: &mut JSContext,
136 timeout_ms: u64,
137) -> Result<EventLoopResult, String> {
138 ctx.run_event_loop_with_timeout(timeout_ms)
139}