From 160ebd649d4641138c1ffd2bdded43ddb7807a3d Mon Sep 17 00:00:00 2001 From: Erin Date: Sat, 28 Aug 2021 23:27:35 +0200 Subject: [PATCH 01/37] Most coercions implemented --- ablescript/src/ast.rs | 2 +- ablescript/src/interpret.rs | 96 ++++------- ablescript/src/parser.rs | 5 +- ablescript/src/variables.rs | 322 +++++++++++++++++++++++++++++------- 4 files changed, 298 insertions(+), 127 deletions(-) diff --git a/ablescript/src/ast.rs b/ablescript/src/ast.rs index 9043283..0d68f11 100644 --- a/ablescript/src/ast.rs +++ b/ablescript/src/ast.rs @@ -142,7 +142,7 @@ pub enum ExprKind { Literal(Value), Cart(Vec<(Expr, Expr)>), Index { - cart: Box, + expr: Box, index: Box, }, Variable(String), diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 1f0f0f6..73e9ed8 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -141,59 +141,19 @@ impl ExecEnv { let lhs = self.eval_expr(lhs)?; let rhs = self.eval_expr(rhs)?; match kind { - // Arithmetic operators. - Add | Subtract | Multiply | Divide => { - let lhs = lhs.to_i32(); - let rhs = rhs.to_i32(); - - let res = match kind { - Add => lhs.checked_add(rhs), - Subtract => lhs.checked_sub(rhs), - Multiply => lhs.checked_mul(rhs), - Divide => lhs.checked_div(rhs), - _ => unreachable!(), - } - .unwrap_or(consts::ANSWER); - Int(res) - } - - // Numeric comparisons. - Less | Greater => { - let lhs = lhs.to_i32(); - let rhs = rhs.to_i32(); - - let res = match kind { - Less => lhs < rhs, - Greater => lhs > rhs, - _ => unreachable!(), - }; - Bool(res) - } - - // General comparisons. - Equal | NotEqual => { - let res = match kind { - Equal => lhs == rhs, - NotEqual => lhs != rhs, - _ => unreachable!(), - }; - Bool(res) - } - - // Logical connectives. - And | Or => { - let lhs = lhs.to_bool(); - let rhs = rhs.to_bool(); - let res = match kind { - And => lhs && rhs, - Or => lhs || rhs, - _ => unreachable!(), - }; - Bool(res) - } + Add => lhs + rhs, + Subtract => todo!(), + Multiply => todo!(), + Divide => todo!(), + Greater => Value::Bool(lhs > rhs), + Less => Value::Bool(lhs < rhs), + Equal => Value::Bool(lhs == rhs), + NotEqual => Value::Bool(lhs != rhs), + And => todo!(), + Or => todo!(), } } - Not(expr) => Bool(!self.eval_expr(expr)?.to_bool()), + Not(expr) => Bool(!self.eval_expr(expr)?.into_bool()), Literal(value) => value.clone(), ExprKind::Cart(members) => Value::Cart( members @@ -206,12 +166,15 @@ impl ExecEnv { }) .collect::, _>>()?, ), - Index { cart, index } => { - let cart = self.eval_expr(cart)?; + Index { expr, index } => { + let value = self.eval_expr(expr)?; let index = self.eval_expr(index)?; - // TODO: this probably shouldn't be cloned - cart.index(&index).borrow().clone() + value + .into_cart() + .get(&index) + .map(|x| x.borrow().clone()) + .unwrap_or(Value::Nul) } // TODO: not too happy with constructing an artificial @@ -257,24 +220,20 @@ impl ExecEnv { instructions: code.to_owned(), tape_len: tape_len .as_ref() - .map(|tape_len| self.eval_expr(tape_len).map(|v| v.to_i32() as usize)) + .map(|tape_len| self.eval_expr(tape_len).map(|v| v.into_i32() as usize)) .unwrap_or(Ok(crate::brian::DEFAULT_TAPE_SIZE_LIMIT))?, }), ); } StmtKind::If { cond, body } => { - if self.eval_expr(cond)?.to_bool() { + if self.eval_expr(cond)?.into_bool() { return self.eval_stmts_hs(&body.block, true); } } StmtKind::Call { expr, args } => { - let func = self.eval_expr(expr)?; + let func = self.eval_expr(expr)?.into_functio(); - if let Value::Functio(func) = func { - self.fn_call(func, args, &stmt.span)?; - } else { - // Fail silently for now. - } + self.fn_call(func, args, &stmt.span)?; } StmtKind::Loop { body } => loop { let res = self.eval_stmts_hs(&body.block, true)?; @@ -387,6 +346,17 @@ impl ExecEnv { self.stack.pop(); res?; } + Functio::Eval(code) => { + if args.len() != 0 { + return Err(Error { + kind: ErrorKind::MismatchedArgumentError, + span: span.to_owned(), + }); + } + + let stmts = crate::parser::Parser::new(&code).init()?; + self.eval_stmts(&stmts)?; + } } Ok(()) } diff --git a/ablescript/src/parser.rs b/ablescript/src/parser.rs index f42873e..16c6733 100644 --- a/ablescript/src/parser.rs +++ b/ablescript/src/parser.rs @@ -98,6 +98,7 @@ impl<'source> Parser<'source> { | Token::Integer(_) | Token::Abool(_) | Token::Bool(_) + | Token::Nul | Token::LeftBracket | Token::LeftParen => Ok(Stmt::new( self.value_flow(token)?, @@ -192,7 +193,7 @@ impl<'source> Parser<'source> { Token::LeftBracket => match buf.take() { Some(buf) => Ok(Expr::new( ExprKind::Index { - cart: Box::new(buf), + expr: Box::new(buf), index: Box::new(self.expr_flow(Token::RightBracket)?), }, start..self.lexer.span().end, @@ -728,7 +729,7 @@ mod tests { let expected = &[Stmt { kind: StmtKind::Print(Expr { kind: ExprKind::Index { - cart: Box::new(Expr { + expr: Box::new(Expr { kind: ExprKind::Cart(vec![( Expr { kind: ExprKind::Literal(Value::Str("able".to_string())), diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index f088b16..57a9c7c 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -1,6 +1,6 @@ use std::{ cell::RefCell, collections::HashMap, convert::TryFrom, fmt::Display, hash::Hash, io::Write, - mem::discriminant, rc::Rc, + mem::discriminant, ops, rc::Rc, vec, }; use rand::Rng; @@ -44,8 +44,11 @@ pub enum Functio { params: Vec, body: Vec, }, + Eval(String), } +pub type Cart = HashMap>>; + #[derive(Debug, Clone)] pub enum Value { Nul, @@ -54,7 +57,7 @@ pub enum Value { Bool(bool), Abool(Abool), Functio(Functio), - Cart(HashMap>>), + Cart(Cart), } impl Hash for Value { @@ -72,24 +75,6 @@ impl Hash for Value { } } -impl PartialEq for Value { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Value::Nul, Value::Nul) => true, - (Value::Str(left), Value::Str(right)) => left == right, - (Value::Int(left), Value::Int(right)) => left == right, - (Value::Bool(left), Value::Bool(right)) => left == right, - (Value::Abool(left), Value::Abool(right)) => left == right, - (Value::Functio(left), Value::Functio(right)) => left == right, - (Value::Cart(_), Value::Cart(_)) => self.to_string() == other.to_string(), - (_, _) => false, - // TODO: do more coercions! - } - } -} - -impl Eq for Value {} - impl Value { /// Write an AbleScript value to a Brainfuck input stream by /// coercing the value to an integer, then truncating that integer @@ -98,23 +83,24 @@ impl Value { /// any IO errors will cause a panic. pub fn bf_write(&self, stream: &mut impl Write) { stream - .write_all(&[self.clone().to_i32() as u8]) + .write_all(&[self.clone().into_i32() as u8]) .expect("Failed to write to Brainfuck input"); } /// Coerce a value to an integer. - pub fn to_i32(&self) -> i32 { + pub fn into_i32(self) -> i32 { match self { - Value::Abool(a) => *a as _, - Value::Bool(b) => *b as _, + Value::Abool(a) => a as _, + Value::Bool(b) => b as _, Value::Functio(func) => match func { Functio::BfFunctio { instructions, tape_len, } => (instructions.len() + tape_len) as _, Functio::AbleFunctio { params, body } => (params.len() + body.len()) as _, + Functio::Eval(s) => s.parse().unwrap_or(consts::ANSWER), }, - Value::Int(i) => *i, + Value::Int(i) => i, Value::Nul => consts::ANSWER, Value::Str(text) => text.parse().unwrap_or(consts::ANSWER), Value::Cart(c) => c.len() as _, @@ -122,49 +108,262 @@ impl Value { } /// Coerce a Value to a boolean. The conversion cannot fail. - pub fn to_bool(&self) -> bool { + pub fn into_bool(self) -> bool { match self { - Value::Abool(b) => (*b).into(), - Value::Bool(b) => *b, + Value::Abool(b) => b.into(), + Value::Bool(b) => b, Value::Functio(_) => true, - Value::Int(x) => *x != 0, - Value::Nul => true, - Value::Str(s) => !s.is_empty(), + Value::Int(x) => x != 0, + Value::Nul => false, + Value::Str(s) => match s.to_lowercase().as_str() { + "false" | "no" | "🇳🇴" => false, + "true" | "yes" => true, + s => !s.is_empty(), + }, Value::Cart(c) => !c.is_empty(), } } - /// Index a value with another value, as in the "a[b]" syntax. - pub fn index(&self, index: &Value) -> Rc> { - Rc::new(RefCell::new(match self { - Value::Nul => Value::Nul, - Value::Str(s) => Value::Int( - usize::try_from(index.to_i32() - 1) - .ok() - .and_then(|idx| s.as_bytes().get(idx).cloned()) - .map(|value| value as i32) - .unwrap_or(0), - ), - Value::Int(i) => Value::Int( - usize::try_from(index.to_i32() - 1) - .ok() - .and_then(|idx| format!("{}", i).as_bytes().get(idx).cloned()) - .map(|value| value as i32) - .unwrap_or(0), - ), - Value::Bool(b) => Value::Int( - usize::try_from(index.to_i32() - 1) - .ok() - .and_then(|idx| format!("{}", b).as_bytes().get(idx).cloned()) - .map(|value| value as i32) - .unwrap_or(0), - ), - Value::Abool(b) => Value::Int(*b as i32), - Value::Functio(_) => Value::Int(42), - Value::Cart(c) => { - return (c.get(index).cloned()).unwrap_or_else(|| Rc::new(RefCell::new(Value::Nul))) + /// Coerce a Value to an aboolean + pub fn into_abool(self) -> Abool { + match self { + Value::Nul => Abool::Never, + Value::Str(s) => match s.to_lowercase().as_str() { + "never" => Abool::Never, + "sometimes" => Abool::Sometimes, + "always" => Abool::Always, + s => { + if s.is_empty() { + Abool::Never + } else { + Abool::Always + } + } + }, + Value::Int(x) => match x.cmp(&0) { + std::cmp::Ordering::Less => Abool::Never, + std::cmp::Ordering::Equal => Abool::Sometimes, + std::cmp::Ordering::Greater => Abool::Always, + }, + Value::Bool(b) => { + if b { + Abool::Always + } else { + Abool::Never + } } - })) + Value::Abool(a) => a, + Value::Functio(_) => todo!(), + Value::Cart(c) => { + if c.is_empty() { + Abool::Never + } else { + Abool::Always + } + } + } + } + + /// Coerce a Value to a functio + pub fn into_functio(self) -> Functio { + match self { + Value::Nul => Functio::AbleFunctio { + body: vec![], + params: vec![], + }, + Value::Str(s) => Functio::Eval(s), + Value::Int(i) => todo!(), + Value::Bool(_) => todo!(), + Value::Abool(_) => todo!(), + Value::Functio(f) => f, + Value::Cart(_) => todo!(), + } + } + + pub fn into_cart(self) -> Cart { + match self { + Value::Nul => HashMap::new(), + Value::Str(s) => s + .chars() + .enumerate() + .map(|(i, x)| { + ( + Value::Int(i as i32 + 1), + Rc::new(RefCell::new(Value::Str(x.to_string()))), + ) + }) + .collect(), + Value::Int(i) => Value::Str(i.to_string()).into_cart(), + Value::Bool(b) => Value::Str(b.to_string()).into_cart(), + Value::Abool(a) => Value::Str(a.to_string()).into_cart(), + Value::Functio(f) => match f { + Functio::BfFunctio { + instructions, + tape_len, + } => { + let mut cart: Cart = instructions + .into_iter() + .enumerate() + .map(|(i, x)| { + ( + Value::Int(i as i32 + 1), + Rc::new(RefCell::new( + char::from_u32(x as u32) + .map(|x| Value::Str(x.to_string())) + .unwrap_or(Value::Nul), + )), + ) + }) + .collect(); + + cart.insert( + Value::Str("tapelen".to_owned()), + Rc::new(RefCell::new(Value::Int(tape_len as _))), + ); + cart + } + Functio::AbleFunctio { params, body } => { + let params: Cart = params + .into_iter() + .enumerate() + .map(|(i, x)| { + ( + Value::Int(i as i32 + 1), + Rc::new(RefCell::new(Value::Str(x))), + ) + }) + .collect(); + + let body: Cart = body + .into_iter() + .enumerate() + .map(|(i, x)| { + ( + Value::Int(i as i32 + 1), + Rc::new(RefCell::new(Value::Str(format!("{:?}", x)))), + ) + }) + .collect(); + + let mut cart = HashMap::new(); + cart.insert( + Value::Str("params".to_owned()), + Rc::new(RefCell::new(Value::Cart(params))), + ); + + cart.insert( + Value::Str("body".to_owned()), + Rc::new(RefCell::new(Value::Cart(body))), + ); + + cart + } + Functio::Eval(s) => Value::Str(s).into_cart(), + }, + Value::Cart(c) => c, + } + } +} + +impl ops::Add for Value { + type Output = Value; + + fn add(self, rhs: Self) -> Self::Output { + match self { + Value::Nul => todo!(), + Value::Str(s) => Value::Str(format!("{}{}", s, rhs.to_string())), + Value::Int(i) => Value::Int(i + rhs.into_i32()), + Value::Bool(b) => Value::Bool(b ^ rhs.into_bool()), + Value::Abool(a) => Value::Abool({ + let rhs = rhs.into_abool(); + if a == rhs { + a + } else if a == Abool::Sometimes { + if rand::thread_rng().gen() { + Abool::Sometimes + } else { + rhs + } + } else if rhs == Abool::Sometimes { + if rand::thread_rng().gen() { + Abool::Sometimes + } else { + a + } + } else { + Abool::Sometimes + } + }), + Value::Functio(f) => Value::Functio(todo!()), + Value::Cart(c) => { + Value::Cart(c.into_iter().chain(rhs.into_cart().into_iter()).collect()) + } + } + } +} + +impl ops::Sub for Value { + type Output = Value; + + fn sub(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl ops::Mul for Value { + type Output = Value; + + fn mul(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl ops::Div for Value { + type Output = Value; + + fn div(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl PartialEq for Value { + fn eq(&self, other: &Self) -> bool { + let other = other.clone(); + + match self { + Value::Nul => other == Value::Nul, + Value::Str(s) => *s == other.to_string(), + Value::Int(i) => *i == other.into_i32(), + Value::Bool(b) => *b == other.into_bool(), + Value::Abool(a) => *a == other.into_abool(), + Value::Functio(f) => *f == other.into_functio(), + Value::Cart(c) => *c == other.into_cart(), + } + } +} + +impl Eq for Value {} + +impl PartialOrd for Value { + fn partial_cmp(&self, other: &Self) -> Option { + use std::cmp::Ordering::*; + let other = other.clone(); + + match self { + Value::Nul => { + if other == Value::Nul { + Some(Equal) + } else { + None + } + } + Value::Str(_) => todo!(), + Value::Int(_) => todo!(), + Value::Bool(_) => todo!(), + Value::Abool(_) => todo!(), + Value::Functio(_) => todo!(), + Value::Cart(_) => todo!(), + } } } @@ -199,6 +398,7 @@ impl Display for Value { body, ) } + Functio::Eval(s) => write!(f, "{}", s), }, Value::Cart(c) => { write!(f, "[")?; From 2010b131682155b536b7ec25199531399af9c2ec Mon Sep 17 00:00:00 2001 From: Erin Date: Sat, 28 Aug 2021 23:43:59 +0200 Subject: [PATCH 02/37] Implement custom `PartialEq` for `Value` --- ablescript/src/variables.rs | 39 ++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 57a9c7c..3fa3fa0 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -7,7 +7,7 @@ use rand::Rng; use crate::{ast::Stmt, consts}; -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] pub enum Abool { Never = -1, Sometimes = 0, @@ -357,12 +357,37 @@ impl PartialOrd for Value { None } } - Value::Str(_) => todo!(), - Value::Int(_) => todo!(), - Value::Bool(_) => todo!(), - Value::Abool(_) => todo!(), - Value::Functio(_) => todo!(), - Value::Cart(_) => todo!(), + Value::Str(s) => Some(s.cmp(&other.to_string())), + Value::Int(i) => Some(i.cmp(&other.into_i32())), + Value::Bool(b) => Some(b.cmp(&other.into_bool())), + Value::Abool(a) => a.partial_cmp(&other.into_abool()), + Value::Functio(f) => { + // Compares lengths of functions: + // BfFunctio - Sum of lengths of instructions and length of tape + // AbleFunctio - Sum of argument count and body length + // Eval - Length of input code + + let selfl = match f { + Functio::BfFunctio { + instructions, + tape_len, + } => instructions.len() + tape_len, + Functio::AbleFunctio { params, body } => params.len() + body.len(), + Functio::Eval(s) => s.len(), + }; + + let otherl = match other.into_functio() { + Functio::BfFunctio { + instructions, + tape_len, + } => instructions.len() + tape_len, + Functio::AbleFunctio { params, body } => params.len() + body.len(), + Functio::Eval(s) => s.len(), + }; + + Some(selfl.cmp(&otherl)) + } + Value::Cart(c) => Some(c.len().cmp(&other.into_cart().len())), } } } From 1b243d142c9047b845414580adf83fde45604b55 Mon Sep 17 00:00:00 2001 From: Erin Date: Sat, 28 Aug 2021 23:52:58 +0200 Subject: [PATCH 03/37] Display carts sorted --- ablescript/src/variables.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 3fa3fa0..544f29f 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -427,9 +427,11 @@ impl Display for Value { }, Value::Cart(c) => { write!(f, "[")?; + let mut cart_vec = c.into_iter().collect::>(); + cart_vec.sort_by(|x, y| x.0.partial_cmp(&y.0).unwrap_or(std::cmp::Ordering::Less)); - for (key, value) in c { - write!(f, "{} <= {},", value.borrow(), key)?; + for (key, value) in cart_vec { + write!(f, "{} <= {}, ", value.borrow(), key)?; } write!(f, "]") From e95e0744c6f9504aa735b9c93857b3a8171bf711 Mon Sep 17 00:00:00 2001 From: Erin Date: Sat, 28 Aug 2021 23:55:36 +0200 Subject: [PATCH 04/37] Fixed add overflows --- ablescript/src/variables.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 544f29f..20f0031 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -272,7 +272,7 @@ impl ops::Add for Value { match self { Value::Nul => todo!(), Value::Str(s) => Value::Str(format!("{}{}", s, rhs.to_string())), - Value::Int(i) => Value::Int(i + rhs.into_i32()), + Value::Int(i) => Value::Int(i.checked_add(rhs.into_i32()).unwrap_or(consts::ANSWER)), Value::Bool(b) => Value::Bool(b ^ rhs.into_bool()), Value::Abool(a) => Value::Abool({ let rhs = rhs.into_abool(); From 24b6683b2100b71d352fc6be9006c138f1d12944 Mon Sep 17 00:00:00 2001 From: Erin Date: Sat, 28 Aug 2021 23:59:04 +0200 Subject: [PATCH 05/37] Added placeholders for And + Or and used placeholders for -, * and / in interpret --- ablescript/src/interpret.rs | 10 +++++----- ablescript/src/variables.rs | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 73e9ed8..656583a 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -142,15 +142,15 @@ impl ExecEnv { let rhs = self.eval_expr(rhs)?; match kind { Add => lhs + rhs, - Subtract => todo!(), - Multiply => todo!(), - Divide => todo!(), + Subtract => lhs - rhs, + Multiply => lhs * rhs, + Divide => lhs / rhs, Greater => Value::Bool(lhs > rhs), Less => Value::Bool(lhs < rhs), Equal => Value::Bool(lhs == rhs), NotEqual => Value::Bool(lhs != rhs), - And => todo!(), - Or => todo!(), + And => lhs & rhs, + Or => lhs | rhs, } } Not(expr) => Bool(!self.eval_expr(expr)?.into_bool()), diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 20f0031..7a5492a 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -392,6 +392,22 @@ impl PartialOrd for Value { } } +impl ops::BitAnd for Value { + type Output = Value; + + fn bitand(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl ops::BitOr for Value { + type Output = Value; + + fn bitor(self, rhs: Self) -> Self::Output { + todo!() + } +} + impl Display for Value { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { From f08778ca3e8a8d3752d19e66bfc74b261475a73a Mon Sep 17 00:00:00 2001 From: Erin Date: Sun, 29 Aug 2021 00:07:26 +0200 Subject: [PATCH 06/37] Eval's integer representation is now its length - consistency with other types --- ablescript/src/variables.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 7a5492a..3a5b186 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -98,7 +98,7 @@ impl Value { tape_len, } => (instructions.len() + tape_len) as _, Functio::AbleFunctio { params, body } => (params.len() + body.len()) as _, - Functio::Eval(s) => s.parse().unwrap_or(consts::ANSWER), + Functio::Eval(s) => s.len() as _, }, Value::Int(i) => i, Value::Nul => consts::ANSWER, From c764cda7c7085f39423c343f330fbefb7147ddf0 Mon Sep 17 00:00:00 2001 From: Erin Date: Sun, 29 Aug 2021 00:10:44 +0200 Subject: [PATCH 07/37] AbleFunctio's body length is now by it's string representation --- ablescript/src/variables.rs | 34 +++++++--------------------------- 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 3a5b186..5d3eada 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -93,11 +93,16 @@ impl Value { Value::Abool(a) => a as _, Value::Bool(b) => b as _, Value::Functio(func) => match func { + // Compares lengths of functions: + // BfFunctio - Sum of lengths of instructions and length of tape + // AbleFunctio - Sum of argument count and body length + // Eval - Length of input code + Functio::BfFunctio { instructions, tape_len, } => (instructions.len() + tape_len) as _, - Functio::AbleFunctio { params, body } => (params.len() + body.len()) as _, + Functio::AbleFunctio { params, body } => (params.len() + format!("{:?}", body).len()) as _, Functio::Eval(s) => s.len() as _, }, Value::Int(i) => i, @@ -361,32 +366,7 @@ impl PartialOrd for Value { Value::Int(i) => Some(i.cmp(&other.into_i32())), Value::Bool(b) => Some(b.cmp(&other.into_bool())), Value::Abool(a) => a.partial_cmp(&other.into_abool()), - Value::Functio(f) => { - // Compares lengths of functions: - // BfFunctio - Sum of lengths of instructions and length of tape - // AbleFunctio - Sum of argument count and body length - // Eval - Length of input code - - let selfl = match f { - Functio::BfFunctio { - instructions, - tape_len, - } => instructions.len() + tape_len, - Functio::AbleFunctio { params, body } => params.len() + body.len(), - Functio::Eval(s) => s.len(), - }; - - let otherl = match other.into_functio() { - Functio::BfFunctio { - instructions, - tape_len, - } => instructions.len() + tape_len, - Functio::AbleFunctio { params, body } => params.len() + body.len(), - Functio::Eval(s) => s.len(), - }; - - Some(selfl.cmp(&otherl)) - } + Value::Functio(_) => self.clone().into_i32().partial_cmp(&other.into_i32()), Value::Cart(c) => Some(c.len().cmp(&other.into_cart().len())), } } From 0cf8576a774d2774b5b87c2c26f3c83ff85bc240 Mon Sep 17 00:00:00 2001 From: Erin Date: Sun, 29 Aug 2021 00:16:15 +0200 Subject: [PATCH 08/37] Eval errors are now correctly spanned --- ablescript/src/interpret.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 656583a..cf85a10 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -355,7 +355,10 @@ impl ExecEnv { } let stmts = crate::parser::Parser::new(&code).init()?; - self.eval_stmts(&stmts)?; + self.eval_stmts(&stmts).map_err(|x| Error { + span: span.clone(), + ..x + })?; } } Ok(()) From 9b81ccf57ce84b0b2768fc017dd03163a9885a9c Mon Sep 17 00:00:00 2001 From: Erin Date: Sun, 29 Aug 2021 00:16:15 +0200 Subject: [PATCH 09/37] Eval errors are now correctly spanned --- ablescript/src/interpret.rs | 5 ++++- ablescript/src/variables.rs | 34 +++++++--------------------------- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 656583a..cf85a10 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -355,7 +355,10 @@ impl ExecEnv { } let stmts = crate::parser::Parser::new(&code).init()?; - self.eval_stmts(&stmts)?; + self.eval_stmts(&stmts).map_err(|x| Error { + span: span.clone(), + ..x + })?; } } Ok(()) diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 3a5b186..5d3eada 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -93,11 +93,16 @@ impl Value { Value::Abool(a) => a as _, Value::Bool(b) => b as _, Value::Functio(func) => match func { + // Compares lengths of functions: + // BfFunctio - Sum of lengths of instructions and length of tape + // AbleFunctio - Sum of argument count and body length + // Eval - Length of input code + Functio::BfFunctio { instructions, tape_len, } => (instructions.len() + tape_len) as _, - Functio::AbleFunctio { params, body } => (params.len() + body.len()) as _, + Functio::AbleFunctio { params, body } => (params.len() + format!("{:?}", body).len()) as _, Functio::Eval(s) => s.len() as _, }, Value::Int(i) => i, @@ -361,32 +366,7 @@ impl PartialOrd for Value { Value::Int(i) => Some(i.cmp(&other.into_i32())), Value::Bool(b) => Some(b.cmp(&other.into_bool())), Value::Abool(a) => a.partial_cmp(&other.into_abool()), - Value::Functio(f) => { - // Compares lengths of functions: - // BfFunctio - Sum of lengths of instructions and length of tape - // AbleFunctio - Sum of argument count and body length - // Eval - Length of input code - - let selfl = match f { - Functio::BfFunctio { - instructions, - tape_len, - } => instructions.len() + tape_len, - Functio::AbleFunctio { params, body } => params.len() + body.len(), - Functio::Eval(s) => s.len(), - }; - - let otherl = match other.into_functio() { - Functio::BfFunctio { - instructions, - tape_len, - } => instructions.len() + tape_len, - Functio::AbleFunctio { params, body } => params.len() + body.len(), - Functio::Eval(s) => s.len(), - }; - - Some(selfl.cmp(&otherl)) - } + Value::Functio(_) => self.clone().into_i32().partial_cmp(&other.into_i32()), Value::Cart(c) => Some(c.len().cmp(&other.into_cart().len())), } } From d6e99acdc9a295f514768dab1e4de18f353c6169 Mon Sep 17 00:00:00 2001 From: Erin Date: Sun, 29 Aug 2021 00:26:40 +0200 Subject: [PATCH 10/37] Revert "Eval errors are now correctly spanned" This reverts commit 9b81ccf57ce84b0b2768fc017dd03163a9885a9c. --- ablescript/src/interpret.rs | 5 +---- ablescript/src/variables.rs | 34 +++++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index cf85a10..656583a 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -355,10 +355,7 @@ impl ExecEnv { } let stmts = crate::parser::Parser::new(&code).init()?; - self.eval_stmts(&stmts).map_err(|x| Error { - span: span.clone(), - ..x - })?; + self.eval_stmts(&stmts)?; } } Ok(()) diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 5d3eada..3a5b186 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -93,16 +93,11 @@ impl Value { Value::Abool(a) => a as _, Value::Bool(b) => b as _, Value::Functio(func) => match func { - // Compares lengths of functions: - // BfFunctio - Sum of lengths of instructions and length of tape - // AbleFunctio - Sum of argument count and body length - // Eval - Length of input code - Functio::BfFunctio { instructions, tape_len, } => (instructions.len() + tape_len) as _, - Functio::AbleFunctio { params, body } => (params.len() + format!("{:?}", body).len()) as _, + Functio::AbleFunctio { params, body } => (params.len() + body.len()) as _, Functio::Eval(s) => s.len() as _, }, Value::Int(i) => i, @@ -366,7 +361,32 @@ impl PartialOrd for Value { Value::Int(i) => Some(i.cmp(&other.into_i32())), Value::Bool(b) => Some(b.cmp(&other.into_bool())), Value::Abool(a) => a.partial_cmp(&other.into_abool()), - Value::Functio(_) => self.clone().into_i32().partial_cmp(&other.into_i32()), + Value::Functio(f) => { + // Compares lengths of functions: + // BfFunctio - Sum of lengths of instructions and length of tape + // AbleFunctio - Sum of argument count and body length + // Eval - Length of input code + + let selfl = match f { + Functio::BfFunctio { + instructions, + tape_len, + } => instructions.len() + tape_len, + Functio::AbleFunctio { params, body } => params.len() + body.len(), + Functio::Eval(s) => s.len(), + }; + + let otherl = match other.into_functio() { + Functio::BfFunctio { + instructions, + tape_len, + } => instructions.len() + tape_len, + Functio::AbleFunctio { params, body } => params.len() + body.len(), + Functio::Eval(s) => s.len(), + }; + + Some(selfl.cmp(&otherl)) + } Value::Cart(c) => Some(c.len().cmp(&other.into_cart().len())), } } From e84c4b2a397824b508dccffb5380e67981f0e6d0 Mon Sep 17 00:00:00 2001 From: Erin Date: Sun, 29 Aug 2021 00:28:45 +0200 Subject: [PATCH 11/37] Used body length for AbleFunctio to i32 instead of AST length --- ablescript/src/variables.rs | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 3a5b186..a558ce3 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -97,7 +97,7 @@ impl Value { instructions, tape_len, } => (instructions.len() + tape_len) as _, - Functio::AbleFunctio { params, body } => (params.len() + body.len()) as _, + Functio::AbleFunctio { params, body } => (params.len() + format!("{:?}", body).len()) as _, Functio::Eval(s) => s.len() as _, }, Value::Int(i) => i, @@ -361,32 +361,7 @@ impl PartialOrd for Value { Value::Int(i) => Some(i.cmp(&other.into_i32())), Value::Bool(b) => Some(b.cmp(&other.into_bool())), Value::Abool(a) => a.partial_cmp(&other.into_abool()), - Value::Functio(f) => { - // Compares lengths of functions: - // BfFunctio - Sum of lengths of instructions and length of tape - // AbleFunctio - Sum of argument count and body length - // Eval - Length of input code - - let selfl = match f { - Functio::BfFunctio { - instructions, - tape_len, - } => instructions.len() + tape_len, - Functio::AbleFunctio { params, body } => params.len() + body.len(), - Functio::Eval(s) => s.len(), - }; - - let otherl = match other.into_functio() { - Functio::BfFunctio { - instructions, - tape_len, - } => instructions.len() + tape_len, - Functio::AbleFunctio { params, body } => params.len() + body.len(), - Functio::Eval(s) => s.len(), - }; - - Some(selfl.cmp(&otherl)) - } + Value::Functio(_) => self.clone().into_i32().partial_cmp(&other.into_i32()), Value::Cart(c) => Some(c.len().cmp(&other.into_cart().len())), } } From e2c7a33a59d15f0951b31d358359e6abf557c9b4 Mon Sep 17 00:00:00 2001 From: Erin Date: Sun, 29 Aug 2021 00:34:08 +0200 Subject: [PATCH 12/37] fmt + docs --- ablescript/src/variables.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index a558ce3..dca8371 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -93,11 +93,17 @@ impl Value { Value::Abool(a) => a as _, Value::Bool(b) => b as _, Value::Functio(func) => match func { + // Compares lengths of functions: + // BfFunctio - Sum of lengths of instructions and length of tape + // AbleFunctio - Sum of argument count and body length + // Eval - Length of input code Functio::BfFunctio { instructions, tape_len, } => (instructions.len() + tape_len) as _, - Functio::AbleFunctio { params, body } => (params.len() + format!("{:?}", body).len()) as _, + Functio::AbleFunctio { params, body } => { + (params.len() + format!("{:?}", body).len()) as _ + } Functio::Eval(s) => s.len() as _, }, Value::Int(i) => i, From 539989e2d02504fdd5957636b83bd13ca9c250bd Mon Sep 17 00:00:00 2001 From: Erin Date: Mon, 30 Aug 2021 22:14:13 +0200 Subject: [PATCH 13/37] Most of operations are implemented --- ablescript/src/variables.rs | 152 ++++++++++++++++++++++++++++-------- 1 file changed, 119 insertions(+), 33 deletions(-) diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index dca8371..4e636a3 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -1,6 +1,14 @@ use std::{ - cell::RefCell, collections::HashMap, convert::TryFrom, fmt::Display, hash::Hash, io::Write, - mem::discriminant, ops, rc::Rc, vec, + cell::RefCell, + collections::HashMap, + convert::{TryFrom, TryInto}, + fmt::Display, + hash::Hash, + io::Write, + mem::discriminant, + ops, + rc::Rc, + vec, }; use rand::Rng; @@ -203,31 +211,6 @@ impl Value { Value::Bool(b) => Value::Str(b.to_string()).into_cart(), Value::Abool(a) => Value::Str(a.to_string()).into_cart(), Value::Functio(f) => match f { - Functio::BfFunctio { - instructions, - tape_len, - } => { - let mut cart: Cart = instructions - .into_iter() - .enumerate() - .map(|(i, x)| { - ( - Value::Int(i as i32 + 1), - Rc::new(RefCell::new( - char::from_u32(x as u32) - .map(|x| Value::Str(x.to_string())) - .unwrap_or(Value::Nul), - )), - ) - }) - .collect(); - - cart.insert( - Value::Str("tapelen".to_owned()), - Rc::new(RefCell::new(Value::Int(tape_len as _))), - ); - cart - } Functio::AbleFunctio { params, body } => { let params: Cart = params .into_iter() @@ -264,6 +247,31 @@ impl Value { cart } + Functio::BfFunctio { + instructions, + tape_len, + } => { + let mut cart: Cart = instructions + .into_iter() + .enumerate() + .map(|(i, x)| { + ( + Value::Int(i as i32 + 1), + Rc::new(RefCell::new( + char::from_u32(x as u32) + .map(|x| Value::Str(x.to_string())) + .unwrap_or(Value::Nul), + )), + ) + }) + .collect(); + + cart.insert( + Value::Str("tapelen".to_owned()), + Rc::new(RefCell::new(Value::Int(tape_len as _))), + ); + cart + } Functio::Eval(s) => Value::Str(s).into_cart(), }, Value::Cart(c) => c, @@ -276,10 +284,18 @@ impl ops::Add for Value { fn add(self, rhs: Self) -> Self::Output { match self { - Value::Nul => todo!(), + Value::Nul => match rhs { + Value::Nul => Value::Nul, + Value::Str(_) => Value::Str(self.to_string()) + rhs, + Value::Int(_) => Value::Int(self.into_i32()) + rhs, + Value::Bool(_) => Value::Bool(self.into_bool()) + rhs, + Value::Abool(_) => Value::Abool(self.into_abool()) + rhs, + Value::Functio(_) => Value::Functio(self.into_functio()) + rhs, + Value::Cart(_) => Value::Cart(self.into_cart()) + rhs, + }, Value::Str(s) => Value::Str(format!("{}{}", s, rhs.to_string())), - Value::Int(i) => Value::Int(i.checked_add(rhs.into_i32()).unwrap_or(consts::ANSWER)), - Value::Bool(b) => Value::Bool(b ^ rhs.into_bool()), + Value::Int(i) => Value::Int(i.wrapping_add(rhs.into_i32())), + Value::Bool(b) => Value::Bool(b || rhs.into_bool()), Value::Abool(a) => Value::Abool({ let rhs = rhs.into_abool(); if a == rhs { @@ -312,7 +328,28 @@ impl ops::Sub for Value { type Output = Value; fn sub(self, rhs: Self) -> Self::Output { - todo!() + match self { + Value::Nul => match rhs { + Value::Nul => Value::Nul, + Value::Str(_) => Value::Str(self.to_string()) - rhs, + Value::Int(_) => Value::Int(self.into_i32()) - rhs, + Value::Bool(_) => Value::Bool(self.into_bool()) - rhs, + Value::Abool(_) => Value::Abool(self.into_abool()) - rhs, + Value::Functio(_) => Value::Functio(self.into_functio()) - rhs, + Value::Cart(_) => Value::Cart(self.into_cart()) - rhs, + }, + Value::Str(s) => Value::Str(s.replace(&rhs.to_string(), "")), + Value::Int(i) => Value::Int(i.wrapping_sub(rhs.into_i32())), + Value::Bool(b) => Value::Bool(b ^ rhs.into_bool()), + Value::Abool(_) => todo!(), + Value::Functio(_) => todo!(), + Value::Cart(c) => Value::Cart({ + let rhs_cart = rhs.into_cart(); + c.into_iter() + .filter(|(k, v)| rhs_cart.get(k) != Some(v)) + .collect() + }), + } } } @@ -320,7 +357,23 @@ impl ops::Mul for Value { type Output = Value; fn mul(self, rhs: Self) -> Self::Output { - todo!() + match self { + Value::Nul => match rhs { + Value::Nul => Value::Nul, + Value::Str(_) => Value::Str(self.to_string()) * rhs, + Value::Int(_) => Value::Int(self.into_i32()) * rhs, + Value::Bool(_) => Value::Bool(self.into_bool()) * rhs, + Value::Abool(_) => Value::Abool(self.into_abool()) * rhs, + Value::Functio(_) => Value::Functio(self.into_functio()) * rhs, + Value::Cart(_) => Value::Cart(self.into_cart()) * rhs, + }, + Value::Str(s) => Value::Str(s.repeat(rhs.into_i32() as usize)), + Value::Int(i) => Value::Int(i.wrapping_mul(rhs.into_i32())), + Value::Bool(b) => Value::Bool(b && rhs.into_bool()), + Value::Abool(_) => todo!(), + Value::Functio(_) => todo!(), + Value::Cart(_) => todo!(), + } } } @@ -328,7 +381,40 @@ impl ops::Div for Value { type Output = Value; fn div(self, rhs: Self) -> Self::Output { - todo!() + match self { + Value::Nul => match rhs { + Value::Nul => Value::Nul, + Value::Str(_) => Value::Str(self.to_string()) / rhs, + Value::Int(_) => Value::Int(self.into_i32()) / rhs, + Value::Bool(_) => Value::Bool(self.into_bool()) / rhs, + Value::Abool(_) => Value::Abool(self.into_abool()) / rhs, + Value::Functio(_) => Value::Functio(self.into_functio()) / rhs, + Value::Cart(_) => Value::Cart(self.into_cart()) / rhs, + }, + Value::Str(s) => Value::Cart( + s.split(&rhs.to_string()) + .enumerate() + .map(|(i, x)| { + ( + Value::Int(i as i32 + 1), + Rc::new(RefCell::new(Value::Str(x.to_owned()))), + ) + }) + .collect(), + ), + Value::Int(i) => Value::Int({ + let rhsi = rhs.into_i32(); + if rhsi == 0 { + consts::ANSWER + } else { + i.wrapping_div(rhsi) + } + }), + Value::Bool(b) => Value::Bool(!(b && rhs.into_bool())), + Value::Abool(_) => todo!(), + Value::Functio(_) => todo!(), + Value::Cart(_) => todo!(), + } } } From bd7209c004b5614814390b0c6d966035ab0430ba Mon Sep 17 00:00:00 2001 From: Erin Date: Mon, 30 Aug 2021 22:18:09 +0200 Subject: [PATCH 14/37] Removed And and Or ops because they aren't cursed enough --- ablescript/src/ast.rs | 4 ---- ablescript/src/interpret.rs | 2 -- ablescript/src/lexer.rs | 6 ------ ablescript/src/parser.rs | 4 +--- ablescript/src/variables.rs | 16 ---------------- 5 files changed, 1 insertion(+), 31 deletions(-) diff --git a/ablescript/src/ast.rs b/ablescript/src/ast.rs index 0d68f11..61fe523 100644 --- a/ablescript/src/ast.rs +++ b/ablescript/src/ast.rs @@ -164,8 +164,6 @@ pub enum BinOpKind { Less, Equal, NotEqual, - And, - Or, } impl BinOpKind { @@ -181,8 +179,6 @@ impl BinOpKind { Token::LessThan => Ok(Self::Less), Token::EqualEqual => Ok(Self::Equal), Token::NotEqual => Ok(Self::NotEqual), - Token::And => Ok(Self::And), - Token::Or => Ok(Self::Or), t => Err(crate::error::ErrorKind::UnexpectedToken(t)), } } diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 656583a..21e023a 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -149,8 +149,6 @@ impl ExecEnv { Less => Value::Bool(lhs < rhs), Equal => Value::Bool(lhs == rhs), NotEqual => Value::Bool(lhs != rhs), - And => lhs & rhs, - Or => lhs | rhs, } } Not(expr) => Bool(!self.eval_expr(expr)?.into_bool()), diff --git a/ablescript/src/lexer.rs b/ablescript/src/lexer.rs index 1ac49d6..c32d936 100644 --- a/ablescript/src/lexer.rs +++ b/ablescript/src/lexer.rs @@ -64,12 +64,6 @@ pub enum Token { #[token("!=")] NotEqual, - #[token("&")] - And, - - #[token("|")] - Or, - #[token("!|aint")] // also add aint as a not keyword Not, diff --git a/ablescript/src/parser.rs b/ablescript/src/parser.rs index 16c6733..e2873b0 100644 --- a/ablescript/src/parser.rs +++ b/ablescript/src/parser.rs @@ -209,9 +209,7 @@ impl<'source> Parser<'source> { | Token::EqualEqual | Token::NotEqual | Token::LessThan - | Token::GreaterThan - | Token::And - | Token::Or => Ok(Expr::new( + | Token::GreaterThan => Ok(Expr::new( self.binop_flow( BinOpKind::from_token(token).map_err(|e| Error::new(e, self.lexer.span()))?, buf, diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 4e636a3..25b9217 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -459,22 +459,6 @@ impl PartialOrd for Value { } } -impl ops::BitAnd for Value { - type Output = Value; - - fn bitand(self, rhs: Self) -> Self::Output { - todo!() - } -} - -impl ops::BitOr for Value { - type Output = Value; - - fn bitor(self, rhs: Self) -> Self::Output { - todo!() - } -} - impl Display for Value { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { From af2fe717fb3b26a9309630f64528d427cbc72cd7 Mon Sep 17 00:00:00 2001 From: Erin Date: Mon, 30 Aug 2021 22:55:31 +0200 Subject: [PATCH 15/37] Not is now lexing and parsing correctly --- ablescript/src/interpret.rs | 8 ++++---- ablescript/src/lexer.rs | 2 +- ablescript/src/parser.rs | 1 + ablescript/src/variables.rs | 8 ++++++++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 21e023a..b22eedc 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -151,7 +151,7 @@ impl ExecEnv { NotEqual => Value::Bool(lhs != rhs), } } - Not(expr) => Bool(!self.eval_expr(expr)?.into_bool()), + Not(expr) => !self.eval_expr(expr)?, Literal(value) => value.clone(), ExprKind::Cart(members) => Value::Cart( members @@ -539,7 +539,7 @@ mod tests { span: 1..1 }) .unwrap(), - Value::Int(42) + Value::Int(-2147483648) ); // And the same for divide by zero. @@ -547,7 +547,7 @@ mod tests { env.eval_expr(&Expr { kind: ExprKind::BinOp { lhs: Box::new(Expr { - kind: ExprKind::Literal(Value::Int(1)), + kind: ExprKind::Literal(Value::Int(84)), span: 1..1, }), rhs: Box::new(Expr { @@ -559,7 +559,7 @@ mod tests { span: 1..1 }) .unwrap(), - Value::Int(42) + Value::Int(2) ); } diff --git a/ablescript/src/lexer.rs b/ablescript/src/lexer.rs index c32d936..612d0e9 100644 --- a/ablescript/src/lexer.rs +++ b/ablescript/src/lexer.rs @@ -64,7 +64,7 @@ pub enum Token { #[token("!=")] NotEqual, - #[token("!|aint")] // also add aint as a not keyword + #[regex("!|aint")] // also add aint as a not keyword Not, // Keywords diff --git a/ablescript/src/parser.rs b/ablescript/src/parser.rs index e2873b0..49ade13 100644 --- a/ablescript/src/parser.rs +++ b/ablescript/src/parser.rs @@ -99,6 +99,7 @@ impl<'source> Parser<'source> { | Token::Abool(_) | Token::Bool(_) | Token::Nul + | Token::Not | Token::LeftBracket | Token::LeftParen => Ok(Stmt::new( self.value_flow(token)?, diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 25b9217..8b2c788 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -418,6 +418,14 @@ impl ops::Div for Value { } } +impl ops::Not for Value { + type Output = Value; + + fn not(self) -> Self::Output { + todo!() + } +} + impl PartialEq for Value { fn eq(&self, other: &Self) -> bool { let other = other.clone(); From 70288ae4090154afdbe21c9222fb320d5bf2870b Mon Sep 17 00:00:00 2001 From: Erin Date: Mon, 30 Aug 2021 23:19:25 +0200 Subject: [PATCH 16/37] Implemented negation for most types --- ablescript/src/lexer.rs | 2 +- ablescript/src/variables.rs | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/ablescript/src/lexer.rs b/ablescript/src/lexer.rs index 612d0e9..e75414d 100644 --- a/ablescript/src/lexer.rs +++ b/ablescript/src/lexer.rs @@ -133,7 +133,7 @@ pub enum Token { String(String), /// Integer - #[regex(r"[0-9]+", get_int)] + #[regex(r"-?[0-9]+", get_int)] Integer(i32), /// A C-complaint identifier diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 8b2c788..8ff96ca 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -422,7 +422,23 @@ impl ops::Not for Value { type Output = Value; fn not(self) -> Self::Output { - todo!() + match self { + Value::Nul => Value::Nul, + Value::Str(s) => Value::Str(s.chars().rev().collect()), + Value::Int(i) => Value::Int(i.swap_bytes()), + Value::Bool(b) => Value::Bool(!b), + Value::Abool(a) => Value::Abool(match a { + Abool::Never => Abool::Always, + Abool::Sometimes => Abool::Sometimes, + Abool::Always => Abool::Never, + }), + Value::Functio(_) => todo!(), + Value::Cart(c) => Value::Cart( + c.into_iter() + .map(|(k, v)| (v.borrow().clone(), Rc::new(RefCell::new(k)))) + .collect(), + ), + } } } @@ -431,7 +447,13 @@ impl PartialEq for Value { let other = other.clone(); match self { - Value::Nul => other == Value::Nul, + Value::Nul => { + if let Value::Nul = other { + true + } else { + false + } + } Value::Str(s) => *s == other.to_string(), Value::Int(i) => *i == other.into_i32(), Value::Bool(b) => *b == other.into_bool(), From a33a3ddd7f0c98536e980b4c6591c7fd2c545a02 Mon Sep 17 00:00:00 2001 From: Erin Date: Tue, 31 Aug 2021 00:41:05 +0200 Subject: [PATCH 17/37] All operations except functio ones are implemented - Aboolean logic - Cart division/multiplication --- ablescript/src/variables.rs | 74 +++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 8ff96ca..ee0bc87 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -186,7 +186,7 @@ impl Value { params: vec![], }, Value::Str(s) => Functio::Eval(s), - Value::Int(i) => todo!(), + Value::Int(_) => todo!(), Value::Bool(_) => todo!(), Value::Abool(_) => todo!(), Value::Functio(f) => f, @@ -296,27 +296,10 @@ impl ops::Add for Value { Value::Str(s) => Value::Str(format!("{}{}", s, rhs.to_string())), Value::Int(i) => Value::Int(i.wrapping_add(rhs.into_i32())), Value::Bool(b) => Value::Bool(b || rhs.into_bool()), - Value::Abool(a) => Value::Abool({ - let rhs = rhs.into_abool(); - if a == rhs { - a - } else if a == Abool::Sometimes { - if rand::thread_rng().gen() { - Abool::Sometimes - } else { - rhs - } - } else if rhs == Abool::Sometimes { - if rand::thread_rng().gen() { - Abool::Sometimes - } else { - a - } - } else { - Abool::Sometimes - } - }), - Value::Functio(f) => Value::Functio(todo!()), + Value::Abool(_) => { + Value::Abool(Value::Int(self.into_i32().max(rhs.into_i32())).into_abool()) + } + Value::Functio(_) => todo!(), Value::Cart(c) => { Value::Cart(c.into_iter().chain(rhs.into_cart().into_iter()).collect()) } @@ -341,7 +324,7 @@ impl ops::Sub for Value { Value::Str(s) => Value::Str(s.replace(&rhs.to_string(), "")), Value::Int(i) => Value::Int(i.wrapping_sub(rhs.into_i32())), Value::Bool(b) => Value::Bool(b ^ rhs.into_bool()), - Value::Abool(_) => todo!(), + Value::Abool(_) => (self.clone() + rhs.clone()) * !(self * rhs), Value::Functio(_) => todo!(), Value::Cart(c) => Value::Cart({ let rhs_cart = rhs.into_cart(); @@ -370,9 +353,25 @@ impl ops::Mul for Value { Value::Str(s) => Value::Str(s.repeat(rhs.into_i32() as usize)), Value::Int(i) => Value::Int(i.wrapping_mul(rhs.into_i32())), Value::Bool(b) => Value::Bool(b && rhs.into_bool()), - Value::Abool(_) => todo!(), + Value::Abool(_) => { + Value::Abool(Value::Int(self.into_i32().min(rhs.into_i32())).into_abool()) + } Value::Functio(_) => todo!(), - Value::Cart(_) => todo!(), + Value::Cart(c) => { + let rhsc = rhs.into_cart(); + + Value::Cart( + c.into_iter() + .map(|(k, v)| { + if let Some(k) = rhsc.get(&k) { + (k.borrow().clone(), v) + } else { + (k, v) + } + }) + .collect(), + ) + } } } } @@ -410,10 +409,29 @@ impl ops::Div for Value { i.wrapping_div(rhsi) } }), - Value::Bool(b) => Value::Bool(!(b && rhs.into_bool())), - Value::Abool(_) => todo!(), + Value::Bool(b) => Value::Bool(!b || rhs.into_bool()), + Value::Abool(_) => !self + rhs, Value::Functio(_) => todo!(), - Value::Cart(_) => todo!(), + Value::Cart(c) => { + let cart_len = c.len(); + let chunk_len = rhs.into_i32() as usize; + + Value::Cart( + c.into_iter() + .collect::>() + .chunks(cart_len / chunk_len + (cart_len % chunk_len != 0) as usize) + .enumerate() + .map(|(k, v)| { + ( + Value::Int(k as i32 + 1), + Rc::new(RefCell::new(Value::Cart( + v.into_iter().cloned().collect(), + ))), + ) + }) + .collect(), + ) + } } } } From 23f03e7f67656e667d92233104594298e685e561 Mon Sep 17 00:00:00 2001 From: Erin Date: Wed, 1 Sep 2021 17:46:17 +0200 Subject: [PATCH 18/37] Clippy --- ablescript/src/interpret.rs | 5 ++--- ablescript/src/variables.rs | 28 ++++++---------------------- 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index b22eedc..61a5065 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -21,7 +21,7 @@ use rand::random; use crate::{ ast::{Expr, ExprKind, Iden, Stmt, StmtKind}, base_55, - consts::{self, ablescript_consts}, + consts::ablescript_consts, error::{Error, ErrorKind}, variables::{Functio, Value, Variable}, }; @@ -134,7 +134,6 @@ impl ExecEnv { fn eval_expr(&self, expr: &Expr) -> Result { use crate::ast::BinOpKind::*; use crate::ast::ExprKind::*; - use Value::*; Ok(match &expr.kind { BinOp { lhs, rhs, kind } => { @@ -345,7 +344,7 @@ impl ExecEnv { res?; } Functio::Eval(code) => { - if args.len() != 0 { + if !args.is_empty() { return Err(Error { kind: ErrorKind::MismatchedArgumentError, span: span.to_owned(), diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index ee0bc87..23fb17a 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -1,14 +1,6 @@ use std::{ - cell::RefCell, - collections::HashMap, - convert::{TryFrom, TryInto}, - fmt::Display, - hash::Hash, - io::Write, - mem::discriminant, - ops, - rc::Rc, - vec, + cell::RefCell, collections::HashMap, fmt::Display, hash::Hash, io::Write, mem::discriminant, + ops, rc::Rc, vec, }; use rand::Rng; @@ -424,9 +416,7 @@ impl ops::Div for Value { .map(|(k, v)| { ( Value::Int(k as i32 + 1), - Rc::new(RefCell::new(Value::Cart( - v.into_iter().cloned().collect(), - ))), + Rc::new(RefCell::new(Value::Cart(v.iter().cloned().collect()))), ) }) .collect(), @@ -465,13 +455,7 @@ impl PartialEq for Value { let other = other.clone(); match self { - Value::Nul => { - if let Value::Nul = other { - true - } else { - false - } - } + Value::Nul => matches!(other, Value::Nul), Value::Str(s) => *s == other.to_string(), Value::Int(i) => *i == other.into_i32(), Value::Bool(b) => *b == other.into_bool(), @@ -542,8 +526,8 @@ impl Display for Value { }, Value::Cart(c) => { write!(f, "[")?; - let mut cart_vec = c.into_iter().collect::>(); - cart_vec.sort_by(|x, y| x.0.partial_cmp(&y.0).unwrap_or(std::cmp::Ordering::Less)); + let mut cart_vec = c.iter().collect::>(); + cart_vec.sort_by(|x, y| x.0.partial_cmp(y.0).unwrap_or(std::cmp::Ordering::Less)); for (key, value) in cart_vec { write!(f, "{} <= {}, ", value.borrow(), key)?; From fb16cb2ebbed019562237fd907f2a9f4ea7fa465 Mon Sep 17 00:00:00 2001 From: Erin Date: Thu, 2 Sep 2021 18:35:33 +0200 Subject: [PATCH 19/37] Fixed division x/0 is now x/42 instead of 42 which makes it more confusing --- ablescript/src/variables.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 23fb17a..ca609a8 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -393,14 +393,10 @@ impl ops::Div for Value { }) .collect(), ), - Value::Int(i) => Value::Int({ - let rhsi = rhs.into_i32(); - if rhsi == 0 { - consts::ANSWER - } else { - i.wrapping_div(rhsi) - } - }), + Value::Int(i) => Value::Int(i.wrapping_div(match rhs.into_i32() { + 0 => consts::ANSWER, + rhsi => rhsi, + })), Value::Bool(b) => Value::Bool(!b || rhs.into_bool()), Value::Abool(_) => !self + rhs, Value::Functio(_) => todo!(), From 1b9f8a61793825e6fb89e51d0ffd54176182d71a Mon Sep 17 00:00:00 2001 From: Erin Date: Thu, 2 Sep 2021 18:36:25 +0200 Subject: [PATCH 20/37] Variable name shortened --- ablescript/src/variables.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index ca609a8..8aeb816 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -395,7 +395,7 @@ impl ops::Div for Value { ), Value::Int(i) => Value::Int(i.wrapping_div(match rhs.into_i32() { 0 => consts::ANSWER, - rhsi => rhsi, + x => x, })), Value::Bool(b) => Value::Bool(!b || rhs.into_bool()), Value::Abool(_) => !self + rhs, From 7673b64a7149e422cb42b591a2561e1d58ecfe4b Mon Sep 17 00:00:00 2001 From: Alex Bethel Date: Sat, 4 Sep 2021 10:54:53 -0600 Subject: [PATCH 21/37] Improve consistency of code & comments Changed all `&str.to_string()` into `&str.to_owned()`, and made the grammar of the `Value::into_*` comments uniform. --- ablescript/src/interpret.rs | 2 +- ablescript/src/parser.rs | 20 ++++++++++---------- ablescript/src/variables.rs | 7 ++++--- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 61a5065..516b681 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -201,7 +201,7 @@ impl ExecEnv { self.decl_var( &iden.iden, Value::Functio(Functio::AbleFunctio { - params: params.iter().map(|iden| iden.iden.to_string()).collect(), + params: params.iter().map(|iden| iden.iden.to_owned()).collect(), body: body.block.to_owned(), }), ); diff --git a/ablescript/src/parser.rs b/ablescript/src/parser.rs index 49ade13..e0debe2 100644 --- a/ablescript/src/parser.rs +++ b/ablescript/src/parser.rs @@ -558,7 +558,7 @@ mod tests { rhs: Box::new(Expr { kind: ExprKind::BinOp { lhs: Box::new(Expr { - kind: ExprKind::Variable("a".to_string()), + kind: ExprKind::Variable("a".to_owned()), span: 5..6, }), rhs: Box::new(Expr { @@ -594,7 +594,7 @@ mod tests { let expected = &[Stmt { kind: StmtKind::Var { iden: Iden { - iden: "a".to_string(), + iden: "a".to_owned(), span: 4..5, }, init: Some(Expr { @@ -631,7 +631,7 @@ mod tests { body: Block { block: vec![Stmt { kind: StmtKind::Print(Expr { - kind: ExprKind::Literal(Value::Str("Buy Able products!".to_string())), + kind: ExprKind::Literal(Value::Str("Buy Able products!".to_owned())), span: 19..39, }), span: 19..46, @@ -651,17 +651,17 @@ mod tests { let expected = &[Stmt { kind: StmtKind::Var { iden: Iden { - iden: "script".to_string(), + iden: "script".to_owned(), span: 13..17, }, init: Some(Expr { kind: ExprKind::BinOp { lhs: Box::new(Expr { - kind: ExprKind::Literal(Value::Str("script".to_string())), + kind: ExprKind::Literal(Value::Str("script".to_owned())), span: 20..26, }), rhs: Box::new(Expr { - kind: ExprKind::Variable("script".to_string()), + kind: ExprKind::Variable("script".to_owned()), span: 29..33, }), kind: BinOpKind::Add, @@ -684,7 +684,7 @@ mod tests { kind: ExprKind::Cart(vec![ ( Expr { - kind: ExprKind::Literal(Value::Str("able".to_string())), + kind: ExprKind::Literal(Value::Str("able".to_owned())), span: 1..7, }, Expr { @@ -694,7 +694,7 @@ mod tests { ), ( Expr { - kind: ExprKind::Literal(Value::Str("script".to_string())), + kind: ExprKind::Literal(Value::Str("script".to_owned())), span: 14..22, }, Expr { @@ -731,11 +731,11 @@ mod tests { expr: Box::new(Expr { kind: ExprKind::Cart(vec![( Expr { - kind: ExprKind::Literal(Value::Str("able".to_string())), + kind: ExprKind::Literal(Value::Str("able".to_owned())), span: 1..7, }, Expr { - kind: ExprKind::Literal(Value::Str("ablecorp".to_string())), + kind: ExprKind::Literal(Value::Str("ablecorp".to_owned())), span: 11..21, }, )]), diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 8aeb816..fb663a5 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -113,7 +113,7 @@ impl Value { } } - /// Coerce a Value to a boolean. The conversion cannot fail. + /// Coerce a value to a boolean. pub fn into_bool(self) -> bool { match self { Value::Abool(b) => b.into(), @@ -130,7 +130,7 @@ impl Value { } } - /// Coerce a Value to an aboolean + /// Coerce a value to an aboolean. pub fn into_abool(self) -> Abool { match self { Value::Nul => Abool::Never, @@ -170,7 +170,7 @@ impl Value { } } - /// Coerce a Value to a functio + /// Coerce a value to a functio. pub fn into_functio(self) -> Functio { match self { Value::Nul => Functio::AbleFunctio { @@ -186,6 +186,7 @@ impl Value { } } + /// Coerce a value into a cart. pub fn into_cart(self) -> Cart { match self { Value::Nul => HashMap::new(), From d229c3d3c35713b037724d7d2c8e3ab777f172f3 Mon Sep 17 00:00:00 2001 From: Erin Date: Mon, 4 Oct 2021 23:00:18 +0200 Subject: [PATCH 22/37] Renamed `Iden` to `Ident` --- ablescript/src/ast.rs | 32 ++++++++--------- ablescript/src/interpret.rs | 70 ++++++++++++++++++------------------- ablescript/src/lexer.rs | 4 +-- ablescript/src/parser.rs | 48 ++++++++++++------------- 4 files changed, 77 insertions(+), 77 deletions(-) diff --git a/ablescript/src/ast.rs b/ablescript/src/ast.rs index 61fe523..8e654ed 100644 --- a/ablescript/src/ast.rs +++ b/ablescript/src/ast.rs @@ -15,26 +15,26 @@ use crate::variables::Value; type Span = std::ops::Range; #[derive(Debug, Clone)] -pub struct Iden { - pub iden: String, +pub struct Ident { + pub ident: String, pub span: Span, } -impl Iden { - pub fn new(iden: String, span: Span) -> Self { - Self { iden, span } +impl Ident { + pub fn new(ident: String, span: Span) -> Self { + Self { ident, span } } } -impl PartialEq for Iden { +impl PartialEq for Ident { fn eq(&self, other: &Self) -> bool { - self.iden == other.iden + self.ident == other.ident } } -impl Hash for Iden { +impl Hash for Ident { fn hash(&self, state: &mut H) { - self.iden.hash(state) + self.ident.hash(state) } } @@ -76,21 +76,21 @@ pub enum StmtKind { HopBack, Var { - iden: Iden, + ident: Ident, init: Option, }, Assign { - iden: Iden, + ident: Ident, value: Expr, }, Functio { - iden: Iden, - params: Vec, + ident: Ident, + params: Vec, body: Block, }, BfFunctio { - iden: Iden, + ident: Ident, tape_len: Option, code: Vec, }, @@ -99,8 +99,8 @@ pub enum StmtKind { args: Vec, }, Print(Expr), - Read(Iden), - Melo(Iden), + Read(Ident), + Melo(Ident), Rlyeh, Rickroll, } diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 516b681..ab58a7e 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -19,7 +19,7 @@ use std::{ use rand::random; use crate::{ - ast::{Expr, ExprKind, Iden, Stmt, StmtKind}, + ast::{Expr, ExprKind, Ident, Stmt, StmtKind}, base_55, consts::ablescript_consts, error::{Error, ErrorKind}, @@ -175,9 +175,9 @@ impl ExecEnv { } // TODO: not too happy with constructing an artificial - // Iden here. - Variable(name) => self.get_var(&Iden { - iden: name.to_owned(), + // Ident here. + Variable(name) => self.get_var(&Ident { + ident: name.to_owned(), span: expr.span.clone(), })?, }) @@ -189,30 +189,30 @@ impl ExecEnv { StmtKind::Print(expr) => { println!("{}", self.eval_expr(expr)?); } - StmtKind::Var { iden, init } => { + StmtKind::Var { ident, init } => { let init = match init { Some(e) => self.eval_expr(e)?, None => Value::Nul, }; - self.decl_var(&iden.iden, init); + self.decl_var(&ident.ident, init); } - StmtKind::Functio { iden, params, body } => { + StmtKind::Functio { ident, params, body } => { self.decl_var( - &iden.iden, + &ident.ident, Value::Functio(Functio::AbleFunctio { - params: params.iter().map(|iden| iden.iden.to_owned()).collect(), + params: params.iter().map(|ident| ident.ident.to_owned()).collect(), body: body.block.to_owned(), }), ); } StmtKind::BfFunctio { - iden, + ident, tape_len, code, } => { self.decl_var( - &iden.iden, + &ident.ident, Value::Functio(Functio::BfFunctio { instructions: code.to_owned(), tape_len: tape_len @@ -240,9 +240,9 @@ impl ExecEnv { HaltStatus::Hopback(_) => continue, } }, - StmtKind::Assign { iden, value } => { + StmtKind::Assign { ident, value } => { let value = self.eval_expr(value)?; - self.get_var_mut(iden)?.value.replace(value); + self.get_var_mut(ident)?.value.replace(value); } StmtKind::Break => { return Ok(HaltStatus::Break(stmt.span.clone())); @@ -250,8 +250,8 @@ impl ExecEnv { StmtKind::HopBack => { return Ok(HaltStatus::Hopback(stmt.span.clone())); } - StmtKind::Melo(iden) => { - self.get_var_mut(iden)?.melo = true; + StmtKind::Melo(ident) => { + self.get_var_mut(ident)?.melo = true; } StmtKind::Rlyeh => { // Maybe print a creepy error message or something @@ -263,14 +263,14 @@ impl ExecEnv { .write_all(include_str!("rickroll").as_bytes()) .expect("Failed to write to stdout"); } - StmtKind::Read(iden) => { + StmtKind::Read(ident) => { let mut value = 0; for _ in 0..READ_BITS { value <<= 1; value += self.get_bit()? as i32; } - self.get_var_mut(iden)?.value.replace(Value::Int(value)); + self.get_var_mut(ident)?.value.replace(Value::Int(value)); } } @@ -287,8 +287,8 @@ impl ExecEnv { .iter() .map(|arg| { if let ExprKind::Variable(name) = &arg.kind { - self.get_var_rc(&Iden { - iden: name.to_owned(), + self.get_var_rc(&Ident { + ident: name.to_owned(), span: arg.span.clone(), }) } else { @@ -380,9 +380,9 @@ impl ExecEnv { /// Get the value of a variable. Throw an error if the variable is /// inaccessible or banned. - fn get_var(&self, name: &Iden) -> Result { + fn get_var(&self, name: &Ident) -> Result { // One-letter names are reserved as base55 numbers. - let mut chars = name.iden.chars(); + let mut chars = name.ident.chars(); if let (Some(first), None) = (chars.next(), chars.next()) { return Ok(Value::Int(base_55::char2num(first))); } @@ -393,20 +393,20 @@ impl ExecEnv { .stack .iter() .rev() - .find_map(|scope| scope.variables.get(&name.iden)) + .find_map(|scope| scope.variables.get(&name.ident)) { Some(var) => { if !var.melo { Ok(var.value.borrow().clone()) } else { Err(Error { - kind: ErrorKind::MeloVariable(name.iden.to_owned()), + kind: ErrorKind::MeloVariable(name.ident.to_owned()), span: name.span.clone(), }) } } None => Err(Error { - kind: ErrorKind::UnknownVariable(name.iden.to_owned()), + kind: ErrorKind::UnknownVariable(name.ident.to_owned()), span: name.span.clone(), }), } @@ -414,27 +414,27 @@ impl ExecEnv { /// Get a mutable reference to a variable. Throw an error if the /// variable is inaccessible or banned. - fn get_var_mut(&mut self, name: &Iden) -> Result<&mut Variable, Error> { + fn get_var_mut(&mut self, name: &Ident) -> Result<&mut Variable, Error> { // This function has a lot of duplicated code with `get_var`, // which I feel like is a bad sign... match self .stack .iter_mut() .rev() - .find_map(|scope| scope.variables.get_mut(&name.iden)) + .find_map(|scope| scope.variables.get_mut(&name.ident)) { Some(var) => { if !var.melo { Ok(var) } else { Err(Error { - kind: ErrorKind::MeloVariable(name.iden.to_owned()), + kind: ErrorKind::MeloVariable(name.ident.to_owned()), span: name.span.clone(), }) } } None => Err(Error { - kind: ErrorKind::UnknownVariable(name.iden.to_owned()), + kind: ErrorKind::UnknownVariable(name.ident.to_owned()), span: name.span.clone(), }), } @@ -442,7 +442,7 @@ impl ExecEnv { /// Get an Rc'd pointer to the value of a variable. Throw an error /// if the variable is inaccessible or banned. - fn get_var_rc(&mut self, name: &Iden) -> Result>, Error> { + fn get_var_rc(&mut self, name: &Ident) -> Result>, Error> { Ok(self.get_var_mut(name)?.value.clone()) } @@ -584,8 +584,8 @@ mod tests { // Declaring and reading from a variable. eval(&mut env, "var foo = 32; var bar = foo + 1;").unwrap(); assert_eq!( - env.get_var(&Iden { - iden: "bar".to_owned(), + env.get_var(&Ident { + ident: "bar".to_owned(), span: 1..1, }) .unwrap(), @@ -595,8 +595,8 @@ mod tests { // Assigning an existing variable. eval(&mut env, "foo = \"hi\";").unwrap(); assert_eq!( - env.get_var(&Iden { - iden: "foo".to_owned(), + env.get_var(&Ident { + ident: "foo".to_owned(), span: 1..1, }) .unwrap(), @@ -621,8 +621,8 @@ mod tests { .unwrap(); assert_eq!( - env.get_var(&Iden { - iden: "foo".to_owned(), + env.get_var(&Ident { + ident: "foo".to_owned(), span: 1..1, }) .unwrap(), diff --git a/ablescript/src/lexer.rs b/ablescript/src/lexer.rs index e75414d..24ee265 100644 --- a/ablescript/src/lexer.rs +++ b/ablescript/src/lexer.rs @@ -137,7 +137,7 @@ pub enum Token { Integer(i32), /// A C-complaint identifier - #[regex(r"[a-zA-Z_][a-zA-Z_0-9]*", get_iden)] + #[regex(r"[a-zA-Z_][a-zA-Z_0-9]*", get_ident)] Identifier(String), #[regex(r"owo .*")] @@ -172,7 +172,7 @@ fn get_abool(lexer: &mut Lexer) -> Option { } } -fn get_iden(lexer: &mut Lexer) -> String { +fn get_ident(lexer: &mut Lexer) -> String { lexer.slice().to_owned() } diff --git a/ablescript/src/parser.rs b/ablescript/src/parser.rs index e0debe2..f07039d 100644 --- a/ablescript/src/parser.rs +++ b/ablescript/src/parser.rs @@ -131,13 +131,13 @@ impl<'source> Parser<'source> { } /// Get an Identifier - fn get_iden(&mut self) -> Result { + fn get_ident(&mut self) -> Result { match self.checked_next()? { - Token::Identifier(iden) => Ok(Iden { - iden: if self.tdark { - iden.replace("lang", "script") + Token::Identifier(ident) => Ok(Ident { + ident: if self.tdark { + ident.replace("lang", "script") } else { - iden + ident }, span: self.lexer.span(), }), @@ -356,12 +356,12 @@ impl<'source> Parser<'source> { // Variable Assignment Token::Equal => { if let Some(Expr { - kind: ExprKind::Variable(iden), + kind: ExprKind::Variable(ident), span, }) = buf { break StmtKind::Assign { - iden: Iden::new(iden, span), + ident: Ident::new(ident, span), value: self.expr_flow(Token::Semicolon)?, }; } @@ -370,11 +370,11 @@ impl<'source> Parser<'source> { // Read input Token::Read => { if let Some(Expr { - kind: ExprKind::Variable(iden), + kind: ExprKind::Variable(ident), span, }) = buf { - break self.semi_terminated(StmtKind::Read(Iden::new(iden, span)))?; + break self.semi_terminated(StmtKind::Read(Ident::new(ident, span)))?; } } @@ -400,9 +400,9 @@ impl<'source> Parser<'source> { /// Parse functio flow /// - /// functio $iden (a, b, c) { ... } + /// functio $ident (a, b, c) { ... } fn functio_flow(&mut self) -> Result { - let iden = self.get_iden()?; + let ident = self.get_ident()?; self.require(Token::LeftParen)?; @@ -411,7 +411,7 @@ impl<'source> Parser<'source> { match self.checked_next()? { Token::RightParen => break, Token::Identifier(i) => { - params.push(Iden::new(i, self.lexer.span())); + params.push(Ident::new(i, self.lexer.span())); // Require comma (next) or right paren (end) after identifier match self.checked_next()? { @@ -431,14 +431,14 @@ impl<'source> Parser<'source> { let body = self.get_block()?; - Ok(StmtKind::Functio { iden, params, body }) + Ok(StmtKind::Functio { ident, params, body }) } /// Parse BF function declaration /// - /// `bff $iden ([tapelen]) { ... }` + /// `bff $ident ([tapelen]) { ... }` fn bff_flow(&mut self) -> Result { - let iden = self.get_iden()?; + let ident = self.get_ident()?; let tape_len = match self.checked_next()? { Token::LeftParen => { @@ -472,7 +472,7 @@ impl<'source> Parser<'source> { } Ok(StmtKind::BfFunctio { - iden, + ident, tape_len, code, }) @@ -513,20 +513,20 @@ impl<'source> Parser<'source> { /// Parse variable declaration fn var_flow(&mut self) -> Result { - let iden = self.get_iden()?; + let ident = self.get_ident()?; let init = match self.checked_next()? { Token::Equal => Some(self.expr_flow(Token::Semicolon)?), Token::Semicolon => None, t => return Err(Error::new(ErrorKind::UnexpectedToken(t), self.lexer.span())), }; - Ok(StmtKind::Var { iden, init }) + Ok(StmtKind::Var { ident, init }) } /// Parse Melo flow fn melo_flow(&mut self) -> Result { - let iden = self.get_iden()?; - self.semi_terminated(StmtKind::Melo(iden)) + let ident = self.get_ident()?; + self.semi_terminated(StmtKind::Melo(ident)) } /// Parse loop flow @@ -593,8 +593,8 @@ mod tests { let code = r#"var a = 42;"#; let expected = &[Stmt { kind: StmtKind::Var { - iden: Iden { - iden: "a".to_owned(), + ident: Ident { + ident: "a".to_owned(), span: 4..5, }, init: Some(Expr { @@ -650,8 +650,8 @@ mod tests { let code = r#"T-Dark { var lang = "lang" + lang; }"#; let expected = &[Stmt { kind: StmtKind::Var { - iden: Iden { - iden: "script".to_owned(), + ident: Ident { + ident: "script".to_owned(), span: 13..17, }, init: Some(Expr { From 1a5d2edee1d2b1680cc58742e946105439fc4c9f Mon Sep 17 00:00:00 2001 From: Erin Date: Mon, 4 Oct 2021 23:03:23 +0200 Subject: [PATCH 23/37] Generalised some lexer functions --- ablescript/src/lexer.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/ablescript/src/lexer.rs b/ablescript/src/lexer.rs index 24ee265..a6c5940 100644 --- a/ablescript/src/lexer.rs +++ b/ablescript/src/lexer.rs @@ -117,7 +117,7 @@ pub enum Token { // Literals /// True, False - #[regex("true|false", get_bool)] + #[regex("true|false", get_value)] Bool(bool), /// Always, Sometimes, Never @@ -133,7 +133,7 @@ pub enum Token { String(String), /// Integer - #[regex(r"-?[0-9]+", get_int)] + #[regex(r"-?[0-9]+", get_value)] Integer(i32), /// A C-complaint identifier @@ -151,11 +151,7 @@ pub enum Token { Error, } -fn get_bool(lexer: &mut Lexer) -> Option { - lexer.slice().parse().ok() -} - -fn get_int(lexer: &mut Lexer) -> Option { +fn get_value(lexer: &mut Lexer) -> Option { lexer.slice().parse().ok() } From ea79e805f2a4856cfeeab0d8da23bc73c6e3c229 Mon Sep 17 00:00:00 2001 From: Erin Date: Tue, 12 Oct 2021 22:14:20 +0200 Subject: [PATCH 24/37] Added Assignable support in parser / AST --- ablescript/src/ast.rs | 14 ++++++++++- ablescript/src/interpret.rs | 11 ++++++--- ablescript/src/parser.rs | 49 +++++++++++++++++++++++++++++++------ 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/ablescript/src/ast.rs b/ablescript/src/ast.rs index 8e654ed..e11cb33 100644 --- a/ablescript/src/ast.rs +++ b/ablescript/src/ast.rs @@ -38,6 +38,18 @@ impl Hash for Ident { } } +#[derive(Debug, PartialEq, Clone, Hash)] +pub struct Assignable { + pub ident: Ident, + pub kind: AssignableKind, +} + +#[derive(Debug, PartialEq, Clone, Hash)] +pub enum AssignableKind { + Variable, + Cart { indices: Vec }, +} + #[derive(Debug, PartialEq, Clone, Hash)] pub struct Block { pub block: Vec, @@ -80,7 +92,7 @@ pub enum StmtKind { init: Option, }, Assign { - ident: Ident, + assignable: Assignable, value: Expr, }, diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index ab58a7e..f9b10e7 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -197,7 +197,11 @@ impl ExecEnv { self.decl_var(&ident.ident, init); } - StmtKind::Functio { ident, params, body } => { + StmtKind::Functio { + ident, + params, + body, + } => { self.decl_var( &ident.ident, Value::Functio(Functio::AbleFunctio { @@ -240,9 +244,10 @@ impl ExecEnv { HaltStatus::Hopback(_) => continue, } }, - StmtKind::Assign { ident, value } => { + StmtKind::Assign { assignable, value } => { + // TODO: Assigning to carts let value = self.eval_expr(value)?; - self.get_var_mut(ident)?.value.replace(value); + self.get_var_mut(&assignable.ident)?.value.replace(value); } StmtKind::Break => { return Ok(HaltStatus::Break(stmt.span.clone())); diff --git a/ablescript/src/parser.rs b/ablescript/src/parser.rs index f07039d..f01a9da 100644 --- a/ablescript/src/parser.rs +++ b/ablescript/src/parser.rs @@ -355,15 +355,25 @@ impl<'source> Parser<'source> { // Variable Assignment Token::Equal => { - if let Some(Expr { - kind: ExprKind::Variable(ident), - span, - }) = buf - { + let assignable = buf.take().and_then(|buf| match buf.kind { + ExprKind::Variable(ident) => Some(Assignable { + ident: Ident::new(ident, buf.span), + kind: AssignableKind::Variable, + }), + ExprKind::Index { expr, index } => self.cart_assignable_flow(*expr, *index), + _ => None, + }); + + if let Some(assignable) = assignable { break StmtKind::Assign { - ident: Ident::new(ident, span), + assignable, value: self.expr_flow(Token::Semicolon)?, }; + } else { + return Err(Error::new( + ErrorKind::UnexpectedToken(Token::Equal), + self.lexer.span(), + )); } } @@ -385,6 +395,27 @@ impl<'source> Parser<'source> { Ok(r) } + /// Parse Cart Assignable flow + fn cart_assignable_flow(&mut self, mut buf: Expr, index: Expr) -> Option { + let mut indices = vec![index]; + let ident = loop { + match buf.kind { + ExprKind::Variable(ident) => break ident, + ExprKind::Index { expr, index } => { + indices.push(*index); + buf = *expr; + } + _ => return None, + } + }; + + indices.reverse(); + Some(Assignable { + ident: Ident::new(ident, buf.span), + kind: AssignableKind::Cart { indices }, + }) + } + /// Parse If flow /// /// Consists of condition and block, there is no else @@ -431,7 +462,11 @@ impl<'source> Parser<'source> { let body = self.get_block()?; - Ok(StmtKind::Functio { ident, params, body }) + Ok(StmtKind::Functio { + ident, + params, + body, + }) } /// Parse BF function declaration From cce392aaaa458a6579c90d1895636fe679488989 Mon Sep 17 00:00:00 2001 From: Erin Date: Tue, 12 Oct 2021 22:22:33 +0200 Subject: [PATCH 25/37] improvement --- ablescript/src/interpret.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index f9b10e7..d778464 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -245,9 +245,14 @@ impl ExecEnv { } }, StmtKind::Assign { assignable, value } => { - // TODO: Assigning to carts let value = self.eval_expr(value)?; - self.get_var_mut(&assignable.ident)?.value.replace(value); + match &assignable.kind { + crate::ast::AssignableKind::Variable => { + &self.get_var_mut(&assignable.ident)?.value + } + crate::ast::AssignableKind::Cart { indices } => todo!("assigning to carts"), + } + .replace(value); } StmtKind::Break => { return Ok(HaltStatus::Break(stmt.span.clone())); From 990e2806f127d53d775d974b227307f10e1c9ec8 Mon Sep 17 00:00:00 2001 From: Alex Bethel Date: Tue, 12 Oct 2021 14:33:23 -0600 Subject: [PATCH 26/37] Sort of fix cart assignments --- ablescript/src/interpret.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index d778464..33bb740 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -19,7 +19,7 @@ use std::{ use rand::random; use crate::{ - ast::{Expr, ExprKind, Ident, Stmt, StmtKind}, + ast::{AssignableKind, Expr, ExprKind, Ident, Stmt, StmtKind}, base_55, consts::ablescript_consts, error::{Error, ErrorKind}, @@ -246,13 +246,20 @@ impl ExecEnv { }, StmtKind::Assign { assignable, value } => { let value = self.eval_expr(value)?; - match &assignable.kind { - crate::ast::AssignableKind::Variable => { - &self.get_var_mut(&assignable.ident)?.value + match assignable.kind { + AssignableKind::Variable => { + &self.get_var_mut(&assignable.ident)?.value.replace(value); + } + AssignableKind::Cart { ref indices } => { + let mut cell = self.get_var_rc(&assignable.ident)?; + for index in indices { + let index = self.eval_expr(index)?; + let value = cell.borrow().to_owned(); + cell = Rc::clone(value.into_cart().get(&index).unwrap()); + } + cell.replace(value); } - crate::ast::AssignableKind::Cart { indices } => todo!("assigning to carts"), } - .replace(value); } StmtKind::Break => { return Ok(HaltStatus::Break(stmt.span.clone())); From 3cff0da70aaa9d9a3b21e8d3a7a2055fa48a658b Mon Sep 17 00:00:00 2001 From: Erin Date: Wed, 13 Oct 2021 13:20:23 +0200 Subject: [PATCH 27/37] Change Cart AssignableKind to Index. --- ablescript/src/ast.rs | 2 +- ablescript/src/interpret.rs | 4 ++-- ablescript/src/parser.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ablescript/src/ast.rs b/ablescript/src/ast.rs index e11cb33..67cd235 100644 --- a/ablescript/src/ast.rs +++ b/ablescript/src/ast.rs @@ -47,7 +47,7 @@ pub struct Assignable { #[derive(Debug, PartialEq, Clone, Hash)] pub enum AssignableKind { Variable, - Cart { indices: Vec }, + Index { indices: Vec }, } #[derive(Debug, PartialEq, Clone, Hash)] diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 33bb740..1c7f096 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -248,9 +248,9 @@ impl ExecEnv { let value = self.eval_expr(value)?; match assignable.kind { AssignableKind::Variable => { - &self.get_var_mut(&assignable.ident)?.value.replace(value); + self.get_var_mut(&assignable.ident)?.value.replace(value); } - AssignableKind::Cart { ref indices } => { + AssignableKind::Index { ref indices } => { let mut cell = self.get_var_rc(&assignable.ident)?; for index in indices { let index = self.eval_expr(index)?; diff --git a/ablescript/src/parser.rs b/ablescript/src/parser.rs index f01a9da..d850f60 100644 --- a/ablescript/src/parser.rs +++ b/ablescript/src/parser.rs @@ -412,7 +412,7 @@ impl<'source> Parser<'source> { indices.reverse(); Some(Assignable { ident: Ident::new(ident, buf.span), - kind: AssignableKind::Cart { indices }, + kind: AssignableKind::Index { indices }, }) } From a82a9d7b79200c372bf2d317e6a2be05f6900a97 Mon Sep 17 00:00:00 2001 From: Erin Date: Thu, 21 Oct 2021 20:51:24 +0200 Subject: [PATCH 28/37] Moved Assignable creation functions --- ablescript/src/ast.rs | 33 +++++++++++++++++++++++++++++++++ ablescript/src/parser.rs | 32 +------------------------------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/ablescript/src/ast.rs b/ablescript/src/ast.rs index 67cd235..fa30420 100644 --- a/ablescript/src/ast.rs +++ b/ablescript/src/ast.rs @@ -50,6 +50,39 @@ pub enum AssignableKind { Index { indices: Vec }, } +impl Assignable { + pub fn from_expr(expr: Expr) -> Result { + match expr.kind { + ExprKind::Variable(ident) => Ok(Assignable { + ident: Ident::new(ident, expr.span), + kind: AssignableKind::Variable, + }), + ExprKind::Index { expr, index } => Self::from_index(*expr, *index), + _ => Err(()), + } + } + + fn from_index(mut buf: Expr, index: Expr) -> Result { + let mut indices = vec![index]; + let ident = loop { + match buf.kind { + ExprKind::Variable(ident) => break ident, + ExprKind::Index { expr, index } => { + indices.push(*index); + buf = *expr; + } + _ => return Err(()), + } + }; + + indices.reverse(); + Ok(Assignable { + ident: Ident::new(ident, buf.span), + kind: AssignableKind::Index { indices }, + }) + } +} + #[derive(Debug, PartialEq, Clone, Hash)] pub struct Block { pub block: Vec, diff --git a/ablescript/src/parser.rs b/ablescript/src/parser.rs index d850f60..1aa4876 100644 --- a/ablescript/src/parser.rs +++ b/ablescript/src/parser.rs @@ -355,16 +355,7 @@ impl<'source> Parser<'source> { // Variable Assignment Token::Equal => { - let assignable = buf.take().and_then(|buf| match buf.kind { - ExprKind::Variable(ident) => Some(Assignable { - ident: Ident::new(ident, buf.span), - kind: AssignableKind::Variable, - }), - ExprKind::Index { expr, index } => self.cart_assignable_flow(*expr, *index), - _ => None, - }); - - if let Some(assignable) = assignable { + if let Some(Ok(assignable)) = buf.take().map(Assignable::from_expr) { break StmtKind::Assign { assignable, value: self.expr_flow(Token::Semicolon)?, @@ -395,27 +386,6 @@ impl<'source> Parser<'source> { Ok(r) } - /// Parse Cart Assignable flow - fn cart_assignable_flow(&mut self, mut buf: Expr, index: Expr) -> Option { - let mut indices = vec![index]; - let ident = loop { - match buf.kind { - ExprKind::Variable(ident) => break ident, - ExprKind::Index { expr, index } => { - indices.push(*index); - buf = *expr; - } - _ => return None, - } - }; - - indices.reverse(); - Some(Assignable { - ident: Ident::new(ident, buf.span), - kind: AssignableKind::Index { indices }, - }) - } - /// Parse If flow /// /// Consists of condition and block, there is no else From 48d9d1e2e16da1a7c28584cf0b83f022dd196bb5 Mon Sep 17 00:00:00 2001 From: Erin Date: Sat, 23 Oct 2021 21:53:21 +0200 Subject: [PATCH 29/37] Read in AST takes Assignable instead of Ident --- ablescript/src/ast.rs | 2 +- ablescript/src/interpret.rs | 11 +++++++++-- ablescript/src/parser.rs | 14 ++++++++------ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/ablescript/src/ast.rs b/ablescript/src/ast.rs index fa30420..a5f1905 100644 --- a/ablescript/src/ast.rs +++ b/ablescript/src/ast.rs @@ -144,7 +144,7 @@ pub enum StmtKind { args: Vec, }, Print(Expr), - Read(Ident), + Read(Assignable), Melo(Ident), Rlyeh, Rickroll, diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 1c7f096..356e9f3 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -280,14 +280,21 @@ impl ExecEnv { .write_all(include_str!("rickroll").as_bytes()) .expect("Failed to write to stdout"); } - StmtKind::Read(ident) => { + StmtKind::Read(assignable) => { let mut value = 0; for _ in 0..READ_BITS { value <<= 1; value += self.get_bit()? as i32; } - self.get_var_mut(ident)?.value.replace(Value::Int(value)); + match assignable.kind { + AssignableKind::Variable => { + self.get_var_mut(&assignable.ident)? + .value + .replace(Value::Int(value)); + } + AssignableKind::Index { .. } => todo!(), + } } } diff --git a/ablescript/src/parser.rs b/ablescript/src/parser.rs index 1aa4876..a397287 100644 --- a/ablescript/src/parser.rs +++ b/ablescript/src/parser.rs @@ -370,12 +370,14 @@ impl<'source> Parser<'source> { // Read input Token::Read => { - if let Some(Expr { - kind: ExprKind::Variable(ident), - span, - }) = buf - { - break self.semi_terminated(StmtKind::Read(Ident::new(ident, span)))?; + if let Some(Ok(assignable)) = buf.take().map(Assignable::from_expr) { + self.require(Token::Semicolon)?; + break StmtKind::Read(assignable); + } else { + return Err(Error::new( + ErrorKind::UnexpectedToken(Token::Read), + self.lexer.span(), + )); } } From 7e0daeab29443234f96e398e8987ca1c5a8945cf Mon Sep 17 00:00:00 2001 From: Alex Bethel Date: Sat, 23 Oct 2021 14:17:17 -0600 Subject: [PATCH 30/37] Almost get cart assignments working --- ablescript/src/interpret.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 356e9f3..3bd8c78 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -254,8 +254,15 @@ impl ExecEnv { let mut cell = self.get_var_rc(&assignable.ident)?; for index in indices { let index = self.eval_expr(index)?; + let value = cell.borrow().to_owned(); - cell = Rc::clone(value.into_cart().get(&index).unwrap()); + let mut value = value.into_cart(); + if let Some(x) = value.get(&index) { + cell = Rc::clone(x); + } else { + cell = Rc::new(RefCell::new(Value::Cart(Default::default()))); + value.insert(index, Rc::clone(&cell)); + } } cell.replace(value); } From 2871e95e75c572741a4f93d891947774d391e117 Mon Sep 17 00:00:00 2001 From: Alex Bethel Date: Sat, 23 Oct 2021 15:08:10 -0600 Subject: [PATCH 31/37] Get cart assignments working --- ablescript/src/interpret.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 3bd8c78..d7db46b 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -255,14 +255,20 @@ impl ExecEnv { for index in indices { let index = self.eval_expr(index)?; - let value = cell.borrow().to_owned(); - let mut value = value.into_cart(); - if let Some(x) = value.get(&index) { - cell = Rc::clone(x); - } else { - cell = Rc::new(RefCell::new(Value::Cart(Default::default()))); - value.insert(index, Rc::clone(&cell)); + let next_cell; + match &mut *cell.borrow_mut() { + Value::Cart(c) => { + if let Some(x) = c.get(&index) { + next_cell = Rc::clone(x); + } else { + next_cell = + Rc::new(RefCell::new(Value::Cart(Default::default()))); + c.insert(index, Rc::clone(&next_cell)); + } + } + _ => todo!(), } + cell = next_cell; } cell.replace(value); } From 9712d58962e182773cc1ab14aae8cca426fed122 Mon Sep 17 00:00:00 2001 From: Erin Date: Sat, 23 Oct 2021 23:20:45 +0200 Subject: [PATCH 32/37] Renamed `semi_terminated` to `semicolon_terminated` --- ablescript/src/parser.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ablescript/src/parser.rs b/ablescript/src/parser.rs index a397287..4f8bf23 100644 --- a/ablescript/src/parser.rs +++ b/ablescript/src/parser.rs @@ -76,19 +76,19 @@ impl<'source> Parser<'source> { Token::Melo => Ok(Stmt::new(self.melo_flow()?, start..self.lexer.span().end)), Token::Loop => Ok(Stmt::new(self.loop_flow()?, start..self.lexer.span().end)), Token::Break => Ok(Stmt::new( - self.semi_terminated(StmtKind::Break)?, + self.semicolon_terminated(StmtKind::Break)?, start..self.lexer.span().end, )), Token::HopBack => Ok(Stmt::new( - self.semi_terminated(StmtKind::HopBack)?, + self.semicolon_terminated(StmtKind::HopBack)?, start..self.lexer.span().end, )), Token::Rlyeh => Ok(Stmt::new( - self.semi_terminated(StmtKind::Rlyeh)?, + self.semicolon_terminated(StmtKind::Rlyeh)?, start..self.lexer.span().end, )), Token::Rickroll => Ok(Stmt::new( - self.semi_terminated(StmtKind::Rickroll)?, + self.semicolon_terminated(StmtKind::Rickroll)?, start..self.lexer.span().end, )), @@ -116,7 +116,7 @@ impl<'source> Parser<'source> { /// Require statement to be semicolon terminated /// /// Utility function for short statements - fn semi_terminated(&mut self, stmt_kind: StmtKind) -> Result { + fn semicolon_terminated(&mut self, stmt_kind: StmtKind) -> Result { self.require(Token::Semicolon)?; Ok(stmt_kind) } @@ -340,7 +340,7 @@ impl<'source> Parser<'source> { let stmt = StmtKind::Print(buf.take().ok_or_else(|| { Error::new(ErrorKind::UnexpectedToken(Token::Print), self.lexer.span()) })?); - break self.semi_terminated(stmt)?; + break self.semicolon_terminated(stmt)?; } // Functio call @@ -533,7 +533,7 @@ impl<'source> Parser<'source> { /// Parse Melo flow fn melo_flow(&mut self) -> Result { let ident = self.get_ident()?; - self.semi_terminated(StmtKind::Melo(ident)) + self.semicolon_terminated(StmtKind::Melo(ident)) } /// Parse loop flow From 99f84dfd5bc22a494f3ae4b5b47dee700d9609e6 Mon Sep 17 00:00:00 2001 From: Alex Bethel Date: Fri, 5 Nov 2021 16:18:07 -0600 Subject: [PATCH 33/37] Coerce indexing assignments into non-carts --- ablescript/src/interpret.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index d7db46b..8ea0472 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -11,6 +11,7 @@ use std::{ cell::RefCell, collections::{HashMap, VecDeque}, io::{stdin, stdout, Read, Write}, + mem::swap, ops::Range, process::exit, rc::Rc, @@ -266,7 +267,18 @@ impl ExecEnv { c.insert(index, Rc::clone(&next_cell)); } } - _ => todo!(), + x => { + // Annoying borrow checker dance + // to move *x. + let mut tmp = Value::Nul; + swap(&mut tmp, x); + + let mut c = tmp.into_cart(); + next_cell = + Rc::new(RefCell::new(Value::Cart(Default::default()))); + c.insert(index, Rc::clone(&next_cell)); + *x = Value::Cart(c); + } } cell = next_cell; } From 8a04d9d1e06f28538c5334fa45c8344ec6607358 Mon Sep 17 00:00:00 2001 From: Alex Bethel Date: Fri, 5 Nov 2021 17:09:53 -0600 Subject: [PATCH 34/37] Assign read syntax --- ablescript/src/interpret.rs | 93 ++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 8ea0472..e1c3af5 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -20,7 +20,7 @@ use std::{ use rand::random; use crate::{ - ast::{AssignableKind, Expr, ExprKind, Ident, Stmt, StmtKind}, + ast::{Assignable, AssignableKind, Expr, ExprKind, Ident, Stmt, StmtKind}, base_55, consts::ablescript_consts, error::{Error, ErrorKind}, @@ -246,45 +246,7 @@ impl ExecEnv { } }, StmtKind::Assign { assignable, value } => { - let value = self.eval_expr(value)?; - match assignable.kind { - AssignableKind::Variable => { - self.get_var_mut(&assignable.ident)?.value.replace(value); - } - AssignableKind::Index { ref indices } => { - let mut cell = self.get_var_rc(&assignable.ident)?; - for index in indices { - let index = self.eval_expr(index)?; - - let next_cell; - match &mut *cell.borrow_mut() { - Value::Cart(c) => { - if let Some(x) = c.get(&index) { - next_cell = Rc::clone(x); - } else { - next_cell = - Rc::new(RefCell::new(Value::Cart(Default::default()))); - c.insert(index, Rc::clone(&next_cell)); - } - } - x => { - // Annoying borrow checker dance - // to move *x. - let mut tmp = Value::Nul; - swap(&mut tmp, x); - - let mut c = tmp.into_cart(); - next_cell = - Rc::new(RefCell::new(Value::Cart(Default::default()))); - c.insert(index, Rc::clone(&next_cell)); - *x = Value::Cart(c); - } - } - cell = next_cell; - } - cell.replace(value); - } - } + self.assign(assignable, self.eval_expr(value)?)?; } StmtKind::Break => { return Ok(HaltStatus::Break(stmt.span.clone())); @@ -312,20 +274,55 @@ impl ExecEnv { value += self.get_bit()? as i32; } - match assignable.kind { - AssignableKind::Variable => { - self.get_var_mut(&assignable.ident)? - .value - .replace(Value::Int(value)); - } - AssignableKind::Index { .. } => todo!(), - } + self.assign(assignable, Value::Int(value))?; } } Ok(HaltStatus::Finished) } + /// Assign a value to an Assignable. + fn assign(&mut self, dest: &Assignable, value: Value) -> Result<(), Error> { + match dest.kind { + AssignableKind::Variable => { + self.get_var_mut(&dest.ident)?.value.replace(value); + } + AssignableKind::Index { ref indices } => { + let mut cell = self.get_var_rc(&dest.ident)?; + for index in indices { + let index = self.eval_expr(index)?; + + let next_cell; + match &mut *cell.borrow_mut() { + Value::Cart(c) => { + if let Some(x) = c.get(&index) { + next_cell = Rc::clone(x); + } else { + next_cell = Rc::new(RefCell::new(Value::Cart(Default::default()))); + c.insert(index, Rc::clone(&next_cell)); + } + } + x => { + // Annoying borrow checker dance + // to move *x. + let mut tmp = Value::Nul; + swap(&mut tmp, x); + + let mut c = tmp.into_cart(); + next_cell = Rc::new(RefCell::new(Value::Cart(Default::default()))); + c.insert(index, Rc::clone(&next_cell)); + *x = Value::Cart(c); + } + } + cell = next_cell; + } + cell.replace(value); + } + } + + Ok(()) + } + /// Call a function with the given arguments (i.e., actual /// parameters). If the function invocation fails for some reason, /// report the error at `span`. From 38a3414e8831536915aefd34355b69078491833c Mon Sep 17 00:00:00 2001 From: Alex Bethel Date: Sat, 27 Nov 2021 11:02:41 -0600 Subject: [PATCH 35/37] Slightly better ExecEnv::assign A little more idiomatic, avoid some borrow checker clumsiness, add comments. --- ablescript/src/interpret.rs | 37 ++++++++++++++++++++++--------------- ablescript/src/variables.rs | 6 ++++++ 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index e1c3af5..5c9cae6 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -11,7 +11,7 @@ use std::{ cell::RefCell, collections::{HashMap, VecDeque}, io::{stdin, stdout, Read, Write}, - mem::swap, + mem::take, ops::Range, process::exit, rc::Rc, @@ -292,28 +292,35 @@ impl ExecEnv { for index in indices { let index = self.eval_expr(index)?; - let next_cell; - match &mut *cell.borrow_mut() { + let next_cell = match &mut *cell.borrow_mut() { Value::Cart(c) => { + // cell is a cart, so we can do simple + // indexing. if let Some(x) = c.get(&index) { - next_cell = Rc::clone(x); + // cell[index] exists, get a shared + // reference to it. + Rc::clone(x) } else { - next_cell = Rc::new(RefCell::new(Value::Cart(Default::default()))); + // cell[index] does not exist, so we + // insert an empty cart by default + // instead. + let next_cell = + Rc::new(RefCell::new(Value::Cart(Default::default()))); c.insert(index, Rc::clone(&next_cell)); + next_cell } } x => { - // Annoying borrow checker dance - // to move *x. - let mut tmp = Value::Nul; - swap(&mut tmp, x); - - let mut c = tmp.into_cart(); - next_cell = Rc::new(RefCell::new(Value::Cart(Default::default()))); - c.insert(index, Rc::clone(&next_cell)); - *x = Value::Cart(c); + // cell is not a cart; `take` it, convert + // it into a cart, and write the result + // back into it. + let mut cart = take(x).into_cart(); + let next_cell = Rc::new(RefCell::new(Value::Cart(Default::default()))); + cart.insert(index, Rc::clone(&next_cell)); + *x = Value::Cart(cart); + next_cell } - } + }; cell = next_cell; } cell.replace(value); diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index fb663a5..99f7955 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -60,6 +60,12 @@ pub enum Value { Cart(Cart), } +impl Default for Value { + fn default() -> Self { + Self::Nul + } +} + impl Hash for Value { fn hash(&self, state: &mut H) { discriminant(self).hash(state); From 716e4997c5c0f906ff7be6971e10ebe6ed0de30e Mon Sep 17 00:00:00 2001 From: Alex Bethel Date: Sat, 27 Nov 2021 11:11:03 -0600 Subject: [PATCH 36/37] Avoid trailing comma in cart printout --- ablescript/src/variables.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 99f7955..5ee99cb 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -532,8 +532,14 @@ impl Display for Value { let mut cart_vec = c.iter().collect::>(); cart_vec.sort_by(|x, y| x.0.partial_cmp(y.0).unwrap_or(std::cmp::Ordering::Less)); - for (key, value) in cart_vec { - write!(f, "{} <= {}, ", value.borrow(), key)?; + for (idx, (key, value)) in cart_vec.into_iter().enumerate() { + write!( + f, + "{}{} <= {}", + if idx != 0 { ", " } else { "" }, + value.borrow(), + key + )?; } write!(f, "]") From da1fcfd861139903d5154bc8eefa797c6e723e2c Mon Sep 17 00:00:00 2001 From: Alex Bethel Date: Sat, 27 Nov 2021 11:15:29 -0600 Subject: [PATCH 37/37] Fix unused code warnings --- ablescript/src/base_55.rs | 62 --------------------------------------- ablescript/src/brian.rs | 3 ++ 2 files changed, 3 insertions(+), 62 deletions(-) diff --git a/ablescript/src/base_55.rs b/ablescript/src/base_55.rs index fa612eb..a822227 100644 --- a/ablescript/src/base_55.rs +++ b/ablescript/src/base_55.rs @@ -60,68 +60,6 @@ pub fn char2num(character: char) -> i32 { _ => 0, } } -pub fn num2char(number: i32) -> char { - match number { - -26 => 'Z', - -25 => 'Y', - -24 => 'X', - -23 => 'W', - -22 => 'V', - -210 => 'U', - -20 => 'T', - -18 => 'R', - -19 => 'S', - -17 => 'Q', - -16 => 'P', - -15 => 'O', - -14 => 'N', - -13 => 'M', - -12 => 'L', - -11 => 'K', - -10 => 'J', - -9 => 'I', - -8 => 'H', - -7 => 'G', - -6 => 'F', - -5 => 'E', - -4 => 'D', - -3 => 'C', - -2 => 'B', - -1 => 'A', - 0 => ' ', - 1 => 'a', - 2 => 'b', - 3 => 'c', - 4 => 'd', - 5 => 'e', - 6 => 'f', - 7 => 'g', - 8 => 'h', - 9 => 'i', - 10 => 'j', - 11 => 'k', - 12 => 'l', - 13 => 'm', - 14 => 'n', - 15 => 'o', - 16 => 'p', - 17 => 'q', - 18 => 'r', - 19 => 's', - 20 => 't', - 21 => 'u', - 22 => 'v', - 23 => 'w', - 24 => 'x', - 25 => 'y', - 26 => 'z', - // NOTE(Able): Why does it jump to 53 here? MY REASONS ARE BEYOND YOUR UNDERSTANDING MORTAL - 53 => '/', - 54 => '\\', - 55 => '.', - _ => ' ', - } -} #[cfg(test)] mod tests { diff --git a/ablescript/src/brian.rs b/ablescript/src/brian.rs index 1a4bf12..630bdb9 100644 --- a/ablescript/src/brian.rs +++ b/ablescript/src/brian.rs @@ -18,6 +18,9 @@ #![deny(missing_docs)] +// Putting this here because we still don't use the entire capabilities of this module. ~~Alex +#![allow(dead_code)] + use std::{ collections::VecDeque, error::Error,