Skip to main content

pipa/compiler/
mod.rs

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}