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