This commit is contained in:
Snorre Ettrup Altschul 2025-02-22 21:38:41 +01:00
parent ff5855af76
commit 04af1e291c
7 changed files with 165 additions and 36 deletions

View file

@ -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()),

View file

@ -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)
} }

View file

@ -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() {

View file

@ -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 {

View file

@ -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)]

View 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
}
}

View file

@ -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) {