Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions src/arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,9 @@ impl Arguments {

let filename = filename.to_string_lossy().to_string();

let mut evaluator =
Evaluator::from(Environment::new(Into::<Config>::into(self)));
let mut evaluator = Evaluator::from(Environment::new_with_process_control(
Into::<Config>::into(self),
));

match parse(&content) {
Ok(ast) => match evaluator.evaluate(&ast) {
Expand All @@ -98,8 +99,9 @@ impl Arguments {
}

fn evaluate_expression(&self, value: String) -> Result {
let mut evaluator =
Evaluator::from(Environment::new(Into::<Config>::into(self)));
let mut evaluator = Evaluator::from(Environment::new_with_process_control(
Into::<Config>::into(self),
));

match parse(&value) {
Ok(ast) => match evaluator.evaluate(&ast) {
Expand Down Expand Up @@ -150,8 +152,9 @@ impl Arguments {
editor.set_helper(Some(Prompt::new()));
editor.load_history(&history).ok();

let mut evaluator =
Evaluator::from(Environment::new(Into::<Config>::into(self)));
let mut evaluator = Evaluator::from(Environment::new_with_process_control(
Into::<Config>::into(self),
));

if let Some(filenames) = &self.load {
for filename in filenames {
Expand Down
4 changes: 4 additions & 0 deletions src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ pub enum Builtin {
}

impl Builtin {
pub(crate) fn controls_process(&self) -> bool {
matches!(self.name(), "exit" | "quit")
}

#[must_use]
pub fn kind(&self) -> &'static str {
match self {
Expand Down
82 changes: 58 additions & 24 deletions src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,38 @@ impl<'src> Environment<'src> {
}
}

fn from_builtins(
config: Config,
builtins: impl IntoIterator<Item = &'static Builtin>,
) -> Self {
let environment = Self {
config,
frame: Rc::new(RefCell::new(Frame::default())),
};

for builtin in builtins {
match builtin {
Builtin::Constant { value, .. } => {
environment.add_symbol(builtin.name(), Value::Number(value(config)));
}
Builtin::Function {
arity, function, ..
} => {
environment.add_function(
builtin.name(),
Function::Builtin {
arity: *arity,
function: *function,
name: builtin.name(),
},
);
}
}
}

environment
}

pub(crate) fn function(
&self,
name: &str,
Expand Down Expand Up @@ -94,32 +126,17 @@ impl<'src> Environment<'src> {

#[must_use]
pub fn new(config: Config) -> Self {
let environment = Self {
Self::from_builtins(
config,
frame: Rc::new(RefCell::new(Frame::default())),
};

for builtin in BUILTINS {
match builtin {
Builtin::Constant { value, .. } => {
environment.add_symbol(builtin.name(), Value::Number(value(config)));
}
Builtin::Function {
arity, function, ..
} => {
environment.add_function(
builtin.name(),
Function::Builtin {
arity: *arity,
function: *function,
name: builtin.name(),
},
);
}
}
}
BUILTINS
.iter()
.filter(|builtin| !builtin.controls_process()),
)
}

environment
#[must_use]
pub fn new_with_process_control(config: Config) -> Self {
Self::from_builtins(config, BUILTINS)
}

fn resolve_function(&self, name: &str) -> Option<Function<'src>> {
Expand Down Expand Up @@ -152,3 +169,20 @@ impl fmt::Debug for Environment<'_> {
.finish_non_exhaustive()
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn process_control_is_opt_in() {
let safe = Environment::new(Config::default());
let process_control =
Environment::new_with_process_control(Config::default());

for name in ["exit", "quit"] {
assert!(safe.resolve_function(name).is_none());
assert!(process_control.resolve_function(name).is_some());
}
}
}
Loading