1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use crate::{
	error::EggResult,
	expression::{Expression, Value},
	scope::{self, Scope},
};
use alloc::{boxed::Box, collections::BTreeMap};

// egg-std definitions
mod arithmetic;
mod boolean;
mod comparison;
mod control_flow;
mod convert;

#[cfg(feature = "std")]
mod console;

mod stringtools;
mod variables;

/// Trait for functions defined Rust, callable in Egg.
/// Operators then need to be registered into the operators map, during script [evaluation](crate::evaluator::evaluate).
pub trait Operator {
	/// Invokes this Operator.
	///
	/// `[args]` are the arguments to the Operator, as [`Expressions`](Expression). To get a [`Value`] from an argument, use the [`evaluate`](crate::evaluator::evaluate) function.
	///
	/// `[scope]` is the current scope, where variables are stored. A local scope if the function is called from a user-defined function, or the global scope if called from the main script.
	///
	/// `[operators]` is a map of all other operators; Can be used directly, but it's main use is to invoke [`evaluate`](crate::evaluator::evaluate) on arguments.
	///
	fn evaluate(&self, args: &[Expression], scope: &mut Scope, operators: &BTreeMap<&str, Box<dyn Operator>>) -> EggResult<Value>;
}

/// Create an empty map of operations
pub fn empty() -> BTreeMap<&'static str, Box<dyn Operator>> {
	BTreeMap::new()
}

/// Only the basic operations available in Egg
pub fn minimal<'a>(map: &'a mut BTreeMap<&'static str, Box<dyn Operator>>) -> &'a mut BTreeMap<&'static str, Box<dyn Operator>> {
	// Insert language statements
	map.insert("define", Box::new(variables::Define));
	map.insert("set", Box::new(variables::Set));
	map.insert("delete", Box::new(variables::Delete));
	map.insert("exists", Box::new(variables::Exists));
	map.insert("typeof", Box::new(variables::TypeOf));

	// Control flow
	map.insert("if", Box::new(control_flow::If));
	map.insert("do", Box::new(control_flow::Do));
	map.insert("while", Box::new(control_flow::While));
	map.insert("repeat", Box::new(control_flow::Repeat));
	map.insert("panic", Box::new(control_flow::Panic));
	map.insert("assert", Box::new(control_flow::Assert));

	// Comparison
	map.insert("equals", Box::new(comparison::Equals));
	map.insert("not_equals", Box::new(comparison::NotEquals));
	map.insert("greater_than", Box::new(comparison::GreaterThan));
	map.insert("less_than", Box::new(comparison::LessThan));
	map.insert("is_nil", Box::new(comparison::IsNil));

	// Arithmetic
	map.insert("sum", Box::new(arithmetic::Sum));
	map.insert("subtract", Box::new(arithmetic::Subtract));
	map.insert("divide", Box::new(arithmetic::Divide));
	map.insert("multiply", Box::new(arithmetic::Multiply));
	map.insert("modulus", Box::new(arithmetic::Modulus));

	// Boolean
	map.insert("and", Box::new(boolean::AND));
	map.insert("or", Box::new(boolean::OR));
	map.insert("not", Box::new(boolean::NOT));

	// Type conversion functions
	map.insert("str", Box::new(convert::ToString));
	map.insert("num", Box::new(convert::ToNumber));

	// Function creation
	map.insert("fn", Box::new(scope::functions::CreateFunction));

	map
}

/// Create, interact with and delete objects
pub fn objects(map: &mut BTreeMap<&'static str, Box<dyn Operator>>) {
	map.insert("object.new", Box::new(scope::object::CreateObject));
	map.insert("object.get", Box::new(scope::object::Get));
	map.insert("object.insert", Box::new(scope::object::Insert));
	map.insert("object.has", Box::new(scope::object::Has));
	map.insert("object.remove", Box::new(scope::object::Remove));
	map.insert("object.size", Box::new(scope::object::Size));
	map.insert("object.clear", Box::new(scope::object::Clear));
}

/// Strings tools
pub fn strings<'a>(map: &'a mut BTreeMap<&'static str, Box<dyn Operator>>) {
	map.insert("string.length", Box::new(stringtools::Length));
	map.insert("string.slice", Box::new(stringtools::Slice));
	map.insert("string.concat", Box::new(stringtools::Concat));
	map.insert("string.to_upper", Box::new(stringtools::ToUpper));
	map.insert("string.to_lower", Box::new(stringtools::ToLower));
	map.insert("string.trim", Box::new(stringtools::Trim));
}

/// Console Functions
#[cfg(feature = "std")]
pub fn console<'a>(map: &'a mut BTreeMap<&'static str, Box<dyn Operator>>) {
	map.insert("print", Box::new(console::Print));
	map.insert("println", Box::new(console::PrintLine));
	map.insert("readline", Box::new(console::ReadLine));
}

/// All Internal functions defined in `Egg`
pub fn full<'a>(map: &'a mut BTreeMap<&'static str, Box<dyn Operator>>) {
	minimal(map);
	objects(map);
	strings(map);

	#[cfg(feature = "std")]
	{
		map.insert("sleep", Box::new(control_flow::Sleep));
		console(map);
	}
}