unset
This commit is contained in:
parent
ff5855af76
commit
04af1e291c
|
@ -162,12 +162,27 @@ fn print(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>
|
|||
Ok(Empty::new(""))
|
||||
}
|
||||
|
||||
fn unset(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
for arg in args {
|
||||
if let NodeEnum::StringNode(string) = arg.as_ref() {
|
||||
if let Some(id) = env.str_to_id(string.get_value()) {
|
||||
env.undefine(*id);
|
||||
}
|
||||
} else {
|
||||
return Err(format!("Cannot undefine the expression {arg}"));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Empty::new(format!("Undefined {} symbols", args.len())))
|
||||
}
|
||||
|
||||
fn main() -> Result<(), io::Error> {
|
||||
let mut input = Input::new();
|
||||
|
||||
let mut env = Environment::new();
|
||||
|
||||
env.define_native_function("print", print);
|
||||
env.define_native_function("unset", unset);
|
||||
env.define(
|
||||
"pi",
|
||||
Rc::new(Constant::new(f64::consts::PI.try_into().unwrap()).into()),
|
||||
|
|
|
@ -22,6 +22,9 @@ pub struct Environment {
|
|||
stack: Vec<EnvironmentInternalSymbolKey>,
|
||||
stack_shadows: Vec<(EnvironmentInternalSymbolKey, Rc<NodeEnum>)>,
|
||||
|
||||
hidden: Vec<EnvironmentInternalSymbolKey>,
|
||||
disable_calls: bool,
|
||||
|
||||
// stack: Vec<Vec<EnvironmentInternalSymbolKey>>,
|
||||
symbol_to_id: HashMap<String, EnvironmentInternalSymbolKey>,
|
||||
id_to_symbol: HashMap<EnvironmentInternalSymbolKey, String>,
|
||||
|
@ -38,6 +41,8 @@ impl Environment {
|
|||
stack_sizes: vec![],
|
||||
stack: vec![],
|
||||
stack_shadows: vec![],
|
||||
hidden: vec![],
|
||||
disable_calls: false,
|
||||
|
||||
symbol_to_id: HashMap::new(),
|
||||
id_to_symbol: HashMap::new(),
|
||||
|
@ -45,6 +50,34 @@ impl Environment {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn hide(&mut self, key: EnvironmentInternalSymbolKey) {
|
||||
match self.hidden.binary_search(&key) {
|
||||
Ok(_) => {}
|
||||
Err(pos) => self.hidden.insert(pos, key),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unhide(&mut self, key: EnvironmentInternalSymbolKey) {
|
||||
match self.hidden.binary_search(&key) {
|
||||
Ok(pos) => {
|
||||
self.hidden.remove(pos);
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disable_calls(&mut self) {
|
||||
self.disable_calls = true;
|
||||
}
|
||||
|
||||
pub fn enable_calls(&mut self) {
|
||||
self.disable_calls = false;
|
||||
}
|
||||
|
||||
pub fn calls_disabled(&self) -> bool {
|
||||
self.disable_calls
|
||||
}
|
||||
|
||||
pub fn push_stack(&mut self) -> Result<(), String> {
|
||||
if self.stack_depth == self.max_stack_depth {
|
||||
self.unwind_stack();
|
||||
|
@ -104,6 +137,10 @@ impl Environment {
|
|||
self.insert_id_to_str(id, name);
|
||||
}
|
||||
|
||||
pub fn undefine(&mut self, key: EnvironmentInternalSymbolKey) {
|
||||
self.map.remove(&key);
|
||||
}
|
||||
|
||||
pub fn define_native_function(&mut self, name: &'static str, func: NativeFunctionType) {
|
||||
let f = Function::new(FunctionType::Native(name, func));
|
||||
|
||||
|
@ -111,7 +148,10 @@ impl Environment {
|
|||
}
|
||||
|
||||
pub fn get(&self, key: &EnvironmentInternalSymbolKey) -> Option<&Rc<NodeEnum>> {
|
||||
eprintln!("Get {key}");
|
||||
if self.hidden.binary_search(key).is_ok() {
|
||||
// This value is hidden, so we pretend its not defined
|
||||
return None;
|
||||
}
|
||||
self.map.get(key)
|
||||
}
|
||||
|
||||
|
|
|
@ -12,15 +12,20 @@ pub struct Call {
|
|||
|
||||
impl Node for Call {
|
||||
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
if env.calls_disabled() {
|
||||
return Ok(Rc::new(self.clone().into()));
|
||||
}
|
||||
|
||||
// Evaluate callee and error if its not a function
|
||||
let evaluated = self.function.evaluate(env)?;
|
||||
let func = if let NodeEnum::Function(func) = evaluated.as_ref() {
|
||||
func
|
||||
} else {
|
||||
return Err(format!(
|
||||
"Cannot call {} as a function",
|
||||
evaluated.as_string(Some(env))
|
||||
));
|
||||
// return Err(format!(
|
||||
// "Cannot call {} as a function",
|
||||
// evaluated.as_string(Some(env))
|
||||
// ));
|
||||
return Ok(Rc::new(self.clone().into()));
|
||||
};
|
||||
|
||||
let arguments = if let NodeEnum::Set(set) = self.arguments.as_ref() {
|
||||
|
|
|
@ -4,7 +4,8 @@ use crate::environment::Environment;
|
|||
|
||||
use super::{Node, NodeEnum, Precedence, symbol::Symbol};
|
||||
|
||||
pub type NativeFunctionType = fn(&Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String>;
|
||||
pub type NativeFunctionType =
|
||||
fn(&Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub enum FunctionType {
|
||||
|
@ -18,8 +19,23 @@ pub struct Function {
|
|||
}
|
||||
|
||||
impl Node for Function {
|
||||
fn evaluate(&self, _: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
Ok(Rc::new(self.clone().into()))
|
||||
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
// Ok(Rc::new(self.clone().into()))
|
||||
|
||||
Ok(Rc::new(
|
||||
Self {
|
||||
function: match &self.function {
|
||||
FunctionType::Native(_, _) => self.function.clone(),
|
||||
FunctionType::UserFunction(node_enum, symbols) => {
|
||||
env.disable_calls();
|
||||
let evaluated = node_enum.evaluate(env)?;
|
||||
env.enable_calls();
|
||||
FunctionType::UserFunction(evaluated, symbols.clone())
|
||||
}
|
||||
},
|
||||
}
|
||||
.into(),
|
||||
))
|
||||
}
|
||||
|
||||
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||
|
|
|
@ -16,6 +16,7 @@ use multiply::Multiply;
|
|||
use set::Set;
|
||||
use subtract::Subtract;
|
||||
use symbol::Symbol;
|
||||
use string_node::StringNode;
|
||||
|
||||
use crate::environment::Environment;
|
||||
|
||||
|
@ -35,12 +36,14 @@ pub mod node_ref;
|
|||
pub mod set;
|
||||
pub mod subtract;
|
||||
pub mod symbol;
|
||||
pub mod string_node;
|
||||
|
||||
#[enum_dispatch]
|
||||
#[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum NodeEnum {
|
||||
Constant,
|
||||
StringNode,
|
||||
|
||||
// Operators
|
||||
Add,
|
||||
|
@ -50,10 +53,10 @@ pub enum NodeEnum {
|
|||
Exponent,
|
||||
|
||||
Symbol,
|
||||
// NodeRef, // DEPRECATED, use Symbol
|
||||
Assign,
|
||||
Empty,
|
||||
Function,
|
||||
// Closure // IMPLEMENT THIS SO CURRYING WORKS
|
||||
Call,
|
||||
|
||||
Bool,
|
||||
|
@ -65,12 +68,13 @@ pub enum NodeEnum {
|
|||
Greater,
|
||||
GreaterEquals,
|
||||
Less,
|
||||
LessEquals, // Logical operators
|
||||
// In,
|
||||
// Where,
|
||||
// Not,
|
||||
// Or,
|
||||
// And
|
||||
LessEquals,
|
||||
// Logical operators
|
||||
// In,
|
||||
// Where,
|
||||
// Not,
|
||||
// Or,
|
||||
// And
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
|
38
src/lib/node/string_node.rs
Normal file
38
src/lib/node/string_node.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use super::{Environment, Node, NodeEnum, Precedence};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct StringNode {
|
||||
value: String,
|
||||
}
|
||||
|
||||
impl From<String> for StringNode {
|
||||
fn from(value: String) -> Self {
|
||||
Self { value }
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for StringNode {
|
||||
fn evaluate(&self, _: &mut super::Environment) -> Result<Rc<super::NodeEnum>, String> {
|
||||
Ok(Rc::new(self.clone().into()))
|
||||
}
|
||||
|
||||
fn as_string(&self, _env: Option<&Environment>) -> String {
|
||||
format!("\"{}\"", self.value.clone())
|
||||
}
|
||||
|
||||
fn precedence(&self) -> Precedence {
|
||||
Precedence::Primary
|
||||
}
|
||||
}
|
||||
|
||||
impl StringNode {
|
||||
pub fn new(value: String) -> Rc<NodeEnum> {
|
||||
Rc::new(Self { value }.into())
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> &String {
|
||||
&self.value
|
||||
}
|
||||
}
|
|
@ -3,21 +3,7 @@ use std::{iter::Peekable, rc::Rc, slice::Iter, str::Chars, vec::IntoIter};
|
|||
use crate::{
|
||||
environment::Environment,
|
||||
node::{
|
||||
NodeEnum,
|
||||
add::Add,
|
||||
assign::Assign,
|
||||
call::Call,
|
||||
comparison::{Greater, GreaterEquals, Less, LessEquals},
|
||||
constant::{Constant, ConstantValue},
|
||||
divide::Divide,
|
||||
equals::Equals,
|
||||
exponent::Exponent,
|
||||
function::{Function, FunctionType},
|
||||
if_else::{Bool, ElseBranchEnum, IfElse},
|
||||
multiply::Multiply,
|
||||
set::Set,
|
||||
subtract::Subtract,
|
||||
symbol::Symbol,
|
||||
add::Add, assign::Assign, call::Call, comparison::{Greater, GreaterEquals, Less, LessEquals}, constant::{Constant, ConstantValue}, divide::Divide, equals::Equals, exponent::Exponent, function::{Function, FunctionType}, if_else::{Bool, ElseBranchEnum, IfElse}, multiply::Multiply, set::Set, string_node::StringNode, subtract::Subtract, symbol::Symbol, NodeEnum
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -29,6 +15,7 @@ pub enum TokenType {
|
|||
// Space,
|
||||
Number(ConstantValue),
|
||||
Identifier(String),
|
||||
String(String),
|
||||
|
||||
Plus,
|
||||
Minus,
|
||||
|
@ -62,7 +49,7 @@ impl TokenType {
|
|||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
TokenType::Number(n) => n.to_string().len(),
|
||||
TokenType::Identifier(s) => s.len(),
|
||||
TokenType::Identifier(s) | TokenType::String(s) => s.len(),
|
||||
|
||||
TokenType::Plus => 1,
|
||||
TokenType::Minus => 1,
|
||||
|
@ -174,6 +161,29 @@ impl<'a> Lexer<'a> {
|
|||
tokens.push(Token(i, TokenType::Number(number)));
|
||||
}
|
||||
|
||||
'"' => {
|
||||
let mut buffer = "".to_owned();
|
||||
loop {
|
||||
let next = self.source.peek();
|
||||
|
||||
match next {
|
||||
Some('"') => {
|
||||
tokens.push(Token(i, TokenType::String(buffer.clone())));
|
||||
self.source.next();
|
||||
break;
|
||||
}
|
||||
Some(_) => {
|
||||
buffer.push(self.source.next().unwrap());
|
||||
}
|
||||
None => {
|
||||
return Err(LexerError::UnexpectedChar(
|
||||
i,
|
||||
"Unexpected End of file".to_owned(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}},
|
||||
|
||||
// LeftArrow (->)
|
||||
'-' if self.source.peek() == Some(&'>') => {
|
||||
self.source.next();
|
||||
|
@ -350,14 +360,13 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
fn assignment(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||
let expr = self.equality();
|
||||
let expr = self.equality()?;
|
||||
|
||||
if let Some(Token(_, TokenType::ColonEquals)) = self.tokens.peek() {
|
||||
self.consume();
|
||||
return Ok(Rc::new(Assign::new(expr?, self.equality()?).into()));
|
||||
if self.matchType(TokenType::ColonEquals) {
|
||||
return Ok(Rc::new(Assign::new(expr, self.equality()?).into()));
|
||||
}
|
||||
|
||||
expr
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn equality(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||
|
@ -599,6 +608,8 @@ impl<'a> Parser<'a> {
|
|||
TokenType::True => Ok(Rc::new(Bool::True.into())),
|
||||
TokenType::False => Ok(Rc::new(Bool::False.into())),
|
||||
|
||||
TokenType::String(s) => Ok(StringNode::new(s)),
|
||||
|
||||
TokenType::LParen => {
|
||||
// Empty set
|
||||
if self.matchType(TokenType::RParen) {
|
||||
|
|
Loading…
Reference in a new issue