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(""))
|
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> {
|
fn main() -> Result<(), io::Error> {
|
||||||
let mut input = Input::new();
|
let mut input = Input::new();
|
||||||
|
|
||||||
let mut env = Environment::new();
|
let mut env = Environment::new();
|
||||||
|
|
||||||
env.define_native_function("print", print);
|
env.define_native_function("print", print);
|
||||||
|
env.define_native_function("unset", unset);
|
||||||
env.define(
|
env.define(
|
||||||
"pi",
|
"pi",
|
||||||
Rc::new(Constant::new(f64::consts::PI.try_into().unwrap()).into()),
|
Rc::new(Constant::new(f64::consts::PI.try_into().unwrap()).into()),
|
||||||
|
|
|
@ -22,6 +22,9 @@ pub struct Environment {
|
||||||
stack: Vec<EnvironmentInternalSymbolKey>,
|
stack: Vec<EnvironmentInternalSymbolKey>,
|
||||||
stack_shadows: Vec<(EnvironmentInternalSymbolKey, Rc<NodeEnum>)>,
|
stack_shadows: Vec<(EnvironmentInternalSymbolKey, Rc<NodeEnum>)>,
|
||||||
|
|
||||||
|
hidden: Vec<EnvironmentInternalSymbolKey>,
|
||||||
|
disable_calls: bool,
|
||||||
|
|
||||||
// stack: Vec<Vec<EnvironmentInternalSymbolKey>>,
|
// stack: Vec<Vec<EnvironmentInternalSymbolKey>>,
|
||||||
symbol_to_id: HashMap<String, EnvironmentInternalSymbolKey>,
|
symbol_to_id: HashMap<String, EnvironmentInternalSymbolKey>,
|
||||||
id_to_symbol: HashMap<EnvironmentInternalSymbolKey, String>,
|
id_to_symbol: HashMap<EnvironmentInternalSymbolKey, String>,
|
||||||
|
@ -38,6 +41,8 @@ impl Environment {
|
||||||
stack_sizes: vec![],
|
stack_sizes: vec![],
|
||||||
stack: vec![],
|
stack: vec![],
|
||||||
stack_shadows: vec![],
|
stack_shadows: vec![],
|
||||||
|
hidden: vec![],
|
||||||
|
disable_calls: false,
|
||||||
|
|
||||||
symbol_to_id: HashMap::new(),
|
symbol_to_id: HashMap::new(),
|
||||||
id_to_symbol: 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> {
|
pub fn push_stack(&mut self) -> Result<(), String> {
|
||||||
if self.stack_depth == self.max_stack_depth {
|
if self.stack_depth == self.max_stack_depth {
|
||||||
self.unwind_stack();
|
self.unwind_stack();
|
||||||
|
@ -104,6 +137,10 @@ impl Environment {
|
||||||
self.insert_id_to_str(id, name);
|
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) {
|
pub fn define_native_function(&mut self, name: &'static str, func: NativeFunctionType) {
|
||||||
let f = Function::new(FunctionType::Native(name, func));
|
let f = Function::new(FunctionType::Native(name, func));
|
||||||
|
|
||||||
|
@ -111,7 +148,10 @@ impl Environment {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, key: &EnvironmentInternalSymbolKey) -> Option<&Rc<NodeEnum>> {
|
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)
|
self.map.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,15 +12,20 @@ pub struct Call {
|
||||||
|
|
||||||
impl Node for Call {
|
impl Node for Call {
|
||||||
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
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
|
// Evaluate callee and error if its not a function
|
||||||
let evaluated = self.function.evaluate(env)?;
|
let evaluated = self.function.evaluate(env)?;
|
||||||
let func = if let NodeEnum::Function(func) = evaluated.as_ref() {
|
let func = if let NodeEnum::Function(func) = evaluated.as_ref() {
|
||||||
func
|
func
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
// return Err(format!(
|
||||||
"Cannot call {} as a function",
|
// "Cannot call {} as a function",
|
||||||
evaluated.as_string(Some(env))
|
// evaluated.as_string(Some(env))
|
||||||
));
|
// ));
|
||||||
|
return Ok(Rc::new(self.clone().into()));
|
||||||
};
|
};
|
||||||
|
|
||||||
let arguments = if let NodeEnum::Set(set) = self.arguments.as_ref() {
|
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};
|
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)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||||
pub enum FunctionType {
|
pub enum FunctionType {
|
||||||
|
@ -18,8 +19,23 @@ pub struct Function {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node for Function {
|
impl Node for Function {
|
||||||
fn evaluate(&self, _: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||||
Ok(Rc::new(self.clone().into()))
|
// 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 {
|
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||||
|
|
|
@ -16,6 +16,7 @@ use multiply::Multiply;
|
||||||
use set::Set;
|
use set::Set;
|
||||||
use subtract::Subtract;
|
use subtract::Subtract;
|
||||||
use symbol::Symbol;
|
use symbol::Symbol;
|
||||||
|
use string_node::StringNode;
|
||||||
|
|
||||||
use crate::environment::Environment;
|
use crate::environment::Environment;
|
||||||
|
|
||||||
|
@ -35,12 +36,14 @@ pub mod node_ref;
|
||||||
pub mod set;
|
pub mod set;
|
||||||
pub mod subtract;
|
pub mod subtract;
|
||||||
pub mod symbol;
|
pub mod symbol;
|
||||||
|
pub mod string_node;
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
#[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)]
|
#[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)]
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum NodeEnum {
|
pub enum NodeEnum {
|
||||||
Constant,
|
Constant,
|
||||||
|
StringNode,
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
Add,
|
Add,
|
||||||
|
@ -50,10 +53,10 @@ pub enum NodeEnum {
|
||||||
Exponent,
|
Exponent,
|
||||||
|
|
||||||
Symbol,
|
Symbol,
|
||||||
// NodeRef, // DEPRECATED, use Symbol
|
|
||||||
Assign,
|
Assign,
|
||||||
Empty,
|
Empty,
|
||||||
Function,
|
Function,
|
||||||
|
// Closure // IMPLEMENT THIS SO CURRYING WORKS
|
||||||
Call,
|
Call,
|
||||||
|
|
||||||
Bool,
|
Bool,
|
||||||
|
@ -65,12 +68,13 @@ pub enum NodeEnum {
|
||||||
Greater,
|
Greater,
|
||||||
GreaterEquals,
|
GreaterEquals,
|
||||||
Less,
|
Less,
|
||||||
LessEquals, // Logical operators
|
LessEquals,
|
||||||
// In,
|
// Logical operators
|
||||||
// Where,
|
// In,
|
||||||
// Not,
|
// Where,
|
||||||
// Or,
|
// Not,
|
||||||
// And
|
// Or,
|
||||||
|
// And
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
#[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::{
|
use crate::{
|
||||||
environment::Environment,
|
environment::Environment,
|
||||||
node::{
|
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, string_node::StringNode, subtract::Subtract, symbol::Symbol, 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,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -29,6 +15,7 @@ pub enum TokenType {
|
||||||
// Space,
|
// Space,
|
||||||
Number(ConstantValue),
|
Number(ConstantValue),
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
|
String(String),
|
||||||
|
|
||||||
Plus,
|
Plus,
|
||||||
Minus,
|
Minus,
|
||||||
|
@ -62,7 +49,7 @@ impl TokenType {
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
TokenType::Number(n) => n.to_string().len(),
|
TokenType::Number(n) => n.to_string().len(),
|
||||||
TokenType::Identifier(s) => s.len(),
|
TokenType::Identifier(s) | TokenType::String(s) => s.len(),
|
||||||
|
|
||||||
TokenType::Plus => 1,
|
TokenType::Plus => 1,
|
||||||
TokenType::Minus => 1,
|
TokenType::Minus => 1,
|
||||||
|
@ -174,6 +161,29 @@ impl<'a> Lexer<'a> {
|
||||||
tokens.push(Token(i, TokenType::Number(number)));
|
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 (->)
|
// LeftArrow (->)
|
||||||
'-' if self.source.peek() == Some(&'>') => {
|
'-' if self.source.peek() == Some(&'>') => {
|
||||||
self.source.next();
|
self.source.next();
|
||||||
|
@ -350,14 +360,13 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assignment(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
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() {
|
if self.matchType(TokenType::ColonEquals) {
|
||||||
self.consume();
|
return Ok(Rc::new(Assign::new(expr, self.equality()?).into()));
|
||||||
return Ok(Rc::new(Assign::new(expr?, self.equality()?).into()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expr
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equality(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
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::True => Ok(Rc::new(Bool::True.into())),
|
||||||
TokenType::False => Ok(Rc::new(Bool::False.into())),
|
TokenType::False => Ok(Rc::new(Bool::False.into())),
|
||||||
|
|
||||||
|
TokenType::String(s) => Ok(StringNode::new(s)),
|
||||||
|
|
||||||
TokenType::LParen => {
|
TokenType::LParen => {
|
||||||
// Empty set
|
// Empty set
|
||||||
if self.matchType(TokenType::RParen) {
|
if self.matchType(TokenType::RParen) {
|
||||||
|
|
Loading…
Reference in a new issue