we (web engine): Experimental web browser project to understand the limits of Claude
1//! JavaScript engine — lexer, parser, bytecode, register VM, GC, JIT (AArch64).
2
3pub mod ast;
4pub mod builtins;
5pub mod bytecode;
6pub mod compiler;
7pub mod gc;
8pub mod lexer;
9pub mod parser;
10pub mod regex;
11pub mod vm;
12
13use std::fmt;
14
15/// An error produced by the JavaScript engine.
16#[derive(Debug)]
17pub enum JsError {
18 /// The engine does not yet support this feature or syntax.
19 NotImplemented,
20 /// A parse/syntax error in the source.
21 SyntaxError(String),
22 /// A runtime error during execution.
23 RuntimeError(String),
24}
25
26impl fmt::Display for JsError {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 match self {
29 JsError::NotImplemented => write!(f, "not implemented"),
30 JsError::SyntaxError(msg) => write!(f, "SyntaxError: {}", msg),
31 JsError::RuntimeError(msg) => write!(f, "RuntimeError: {}", msg),
32 }
33 }
34}
35
36/// Evaluate a JavaScript source string and return the completion value as a string.
37///
38/// Parses the source, compiles to bytecode, and executes in the VM.
39pub fn evaluate(source: &str) -> Result<String, JsError> {
40 let program = parser::Parser::parse(source).map_err(|e| JsError::SyntaxError(e.to_string()))?;
41 let func = compiler::compile(&program)?;
42 let mut engine = vm::Vm::new();
43 let result = engine
44 .execute(&func)
45 .map_err(|e| JsError::RuntimeError(e.to_string()))?;
46 Ok(result.to_js_string(&engine.gc))
47}
48
49/// Evaluate a JavaScript source string with a preamble executed first in the
50/// same VM instance. Used by the Test262 harness to inject helpers like
51/// `assert`, `assert.sameValue`, and `Test262Error` before running tests.
52///
53/// Returns `Ok(())` on success, or a `JsError` on parse/runtime failure.
54pub fn evaluate_with_preamble(preamble: &str, source: &str) -> Result<(), JsError> {
55 evaluate_with_preamble_limited(preamble, source, None)
56}
57
58/// Like [`evaluate_with_preamble`] but with an optional instruction limit to
59/// prevent infinite loops. Used by the Test262 harness.
60pub fn evaluate_with_preamble_limited(
61 preamble: &str,
62 source: &str,
63 instruction_limit: Option<u64>,
64) -> Result<(), JsError> {
65 let mut engine = vm::Vm::new();
66
67 // Execute preamble to define harness functions.
68 let preamble_ast =
69 parser::Parser::parse(preamble).map_err(|e| JsError::SyntaxError(e.to_string()))?;
70 let preamble_func = compiler::compile(&preamble_ast)?;
71 engine
72 .execute(&preamble_func)
73 .map_err(|e| JsError::RuntimeError(e.to_string()))?;
74
75 // Set instruction limit for the test source (not the preamble).
76 if let Some(limit) = instruction_limit {
77 engine.set_instruction_limit(limit);
78 }
79
80 // Execute the test source.
81 let test_ast =
82 parser::Parser::parse(source).map_err(|e| JsError::SyntaxError(e.to_string()))?;
83 let test_func = compiler::compile(&test_ast)?;
84 engine
85 .execute(&test_func)
86 .map_err(|e| JsError::RuntimeError(e.to_string()))?;
87
88 Ok(())
89}