#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![allow(clippy::similar_names)]
#![allow(clippy::needless_pass_by_value)]
#![allow(clippy::float_cmp)]
#![allow(clippy::cast_precision_loss)]
#![allow(clippy::cast_possible_truncation)]
#![allow(clippy::cast_sign_loss)]
#![allow(clippy::cast_possible_wrap)]
#![allow(unpredictable_function_pointer_comparisons)]
pub mod coercion;
pub mod completion;
pub mod env;
pub mod error;
pub mod expression;
pub mod fuel;
pub mod heap;
pub mod operator;
pub mod outcome;
pub mod statement;
pub mod value;
use comp_cat_rs::effect::io::Io;
use ecma_lex_cat::lex;
use ecma_parse_cat::parse_script;
use ecma_syntax_cat::program::{Program, ProgramKind};
pub use env::Binding;
pub use error::Error;
pub use value::{Cell, NativeFn, Value};
use crate::completion::Completion;
use crate::env::Env;
use crate::fuel::Fuel;
use crate::heap::Heap;
use crate::statement::eval_block;
pub const DEFAULT_FUEL: u64 = 100_000;
#[must_use]
pub fn run(source: &str) -> Io<Error, Value> {
run_with_fuel(source, Fuel::new(DEFAULT_FUEL))
}
#[must_use]
pub fn run_with_fuel(source: &str, fuel: Fuel) -> Io<Error, Value> {
let owned = source.to_owned();
Io::suspend(move || pipeline(&owned, fuel).map(|(value, _heap)| value))
}
#[must_use]
pub fn run_inspecting(source: &str, fuel: Fuel) -> Io<Error, (Value, Heap)> {
let owned = source.to_owned();
Io::suspend(move || pipeline(&owned, fuel))
}
fn pipeline(source: &str, fuel: Fuel) -> Result<(Value, Heap), Error> {
let tokens = lex(source)?;
let program = parse_script(&tokens)?;
evaluate_program(&program, fuel)
}
pub fn evaluate_program(program: &Program, fuel: Fuel) -> Result<(Value, Heap), Error> {
evaluate_program_with(program, initial_env(), Heap::new(), fuel)
}
pub fn evaluate_program_with(
program: &Program,
env: Env,
heap: Heap,
fuel: Fuel,
) -> Result<(Value, Heap), Error> {
match program.value() {
ProgramKind::Script { body } => {
eval_block(body, &env, heap, fuel).and_then(|(completion, heap, _env, _fuel)| {
let value = match completion {
Completion::Normal(v) | Completion::Return(v) => Ok(v),
Completion::Throw(v) => Err(Error::UncaughtException {
rendered: format!("{v}"),
}),
Completion::Break | Completion::Continue => Ok(Value::Undefined),
};
value.map(|v| (v, heap))
})
}
ProgramKind::Module { .. } => Err(Error::Unsupported {
feature: "module evaluation (v0 supports Script only)",
}),
}
}
fn initial_env() -> Env {
Env::empty()
.extend_direct("undefined", Value::Undefined)
.extend_direct("NaN", Value::Number(f64::NAN))
.extend_direct("Infinity", Value::Number(f64::INFINITY))
}