Revert "Merge branch 'fix/unused-code'"

This reverts commit 6ee12a7c91, reversing
changes made to 706d39e860.
This commit is contained in:
Erin 2021-12-07 20:54:23 +01:00 committed by ondra05
parent 6ee12a7c91
commit 3a59501217
7 changed files with 319 additions and 653 deletions

View file

@ -15,71 +15,26 @@ use crate::variables::Value;
type Span = std::ops::Range<usize>; type Span = std::ops::Range<usize>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Ident { pub struct Iden {
pub ident: String, pub iden: String,
pub span: Span, pub span: Span,
} }
impl Ident { impl Iden {
pub fn new(ident: String, span: Span) -> Self { pub fn new(iden: String, span: Span) -> Self {
Self { ident, span } Self { iden, span }
} }
} }
impl PartialEq for Ident { impl PartialEq for Iden {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.ident == other.ident self.iden == other.iden
} }
} }
impl Hash for Ident { impl Hash for Iden {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.ident.hash(state) self.iden.hash(state)
}
}
#[derive(Debug, PartialEq, Clone, Hash)]
pub struct Assignable {
pub ident: Ident,
pub kind: AssignableKind,
}
#[derive(Debug, PartialEq, Clone, Hash)]
pub enum AssignableKind {
Variable,
Index { indices: Vec<Expr> },
}
impl Assignable {
pub fn from_expr(expr: Expr) -> Result<Assignable, ()> {
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<Assignable, ()> {
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 },
})
} }
} }
@ -121,21 +76,21 @@ pub enum StmtKind {
HopBack, HopBack,
Var { Var {
ident: Ident, iden: Iden,
init: Option<Expr>, init: Option<Expr>,
}, },
Assign { Assign {
assignable: Assignable, iden: Iden,
value: Expr, value: Expr,
}, },
Functio { Functio {
ident: Ident, iden: Iden,
params: Vec<Ident>, params: Vec<Iden>,
body: Block, body: Block,
}, },
BfFunctio { BfFunctio {
ident: Ident, iden: Iden,
tape_len: Option<Expr>, tape_len: Option<Expr>,
code: Vec<u8>, code: Vec<u8>,
}, },
@ -144,8 +99,8 @@ pub enum StmtKind {
args: Vec<Expr>, args: Vec<Expr>,
}, },
Print(Expr), Print(Expr),
Read(Assignable), Read(Iden),
Melo(Ident), Melo(Iden),
Rlyeh, Rlyeh,
Rickroll, Rickroll,
} }
@ -187,7 +142,7 @@ pub enum ExprKind {
Literal(Value), Literal(Value),
Cart(Vec<(Expr, Expr)>), Cart(Vec<(Expr, Expr)>),
Index { Index {
expr: Box<Expr>, cart: Box<Expr>,
index: Box<Expr>, index: Box<Expr>,
}, },
Variable(String), Variable(String),
@ -209,6 +164,8 @@ pub enum BinOpKind {
Less, Less,
Equal, Equal,
NotEqual, NotEqual,
And,
Or,
} }
impl BinOpKind { impl BinOpKind {
@ -224,6 +181,8 @@ impl BinOpKind {
Token::LessThan => Ok(Self::Less), Token::LessThan => Ok(Self::Less),
Token::EqualEqual => Ok(Self::Equal), Token::EqualEqual => Ok(Self::Equal),
Token::NotEqual => Ok(Self::NotEqual), Token::NotEqual => Ok(Self::NotEqual),
Token::And => Ok(Self::And),
Token::Or => Ok(Self::Or),
t => Err(crate::error::ErrorKind::UnexpectedToken(t)), t => Err(crate::error::ErrorKind::UnexpectedToken(t)),
} }
} }

View file

@ -60,6 +60,68 @@ pub fn char2num(character: char) -> i32 {
_ => 0, _ => 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)] #[cfg(test)]
mod tests { mod tests {

View file

@ -18,9 +18,6 @@
#![deny(missing_docs)] #![deny(missing_docs)]
// Putting this here because we still don't use the entire capabilities of this module. ~~Alex
#![allow(dead_code)]
use std::{ use std::{
collections::VecDeque, collections::VecDeque,
error::Error, error::Error,

View file

@ -11,7 +11,6 @@ use std::{
cell::RefCell, cell::RefCell,
collections::{HashMap, VecDeque}, collections::{HashMap, VecDeque},
io::{stdin, stdout, Read, Write}, io::{stdin, stdout, Read, Write},
mem::take,
ops::Range, ops::Range,
process::exit, process::exit,
rc::Rc, rc::Rc,
@ -20,9 +19,9 @@ use std::{
use rand::random; use rand::random;
use crate::{ use crate::{
ast::{Assignable, AssignableKind, Expr, ExprKind, Ident, Stmt, StmtKind}, ast::{Expr, ExprKind, Iden, Stmt, StmtKind},
base_55, base_55,
consts::ablescript_consts, consts::{self, ablescript_consts},
error::{Error, ErrorKind}, error::{Error, ErrorKind},
variables::{Functio, Value, Variable}, variables::{Functio, Value, Variable},
}; };
@ -135,23 +134,66 @@ impl ExecEnv {
fn eval_expr(&self, expr: &Expr) -> Result<Value, Error> { fn eval_expr(&self, expr: &Expr) -> Result<Value, Error> {
use crate::ast::BinOpKind::*; use crate::ast::BinOpKind::*;
use crate::ast::ExprKind::*; use crate::ast::ExprKind::*;
use Value::*;
Ok(match &expr.kind { Ok(match &expr.kind {
BinOp { lhs, rhs, kind } => { BinOp { lhs, rhs, kind } => {
let lhs = self.eval_expr(lhs)?; let lhs = self.eval_expr(lhs)?;
let rhs = self.eval_expr(rhs)?; let rhs = self.eval_expr(rhs)?;
match kind { match kind {
Add => lhs + rhs, // Arithmetic operators.
Subtract => lhs - rhs, Add | Subtract | Multiply | Divide => {
Multiply => lhs * rhs, let lhs = lhs.to_i32();
Divide => lhs / rhs, let rhs = rhs.to_i32();
Greater => Value::Bool(lhs > rhs),
Less => Value::Bool(lhs < rhs), let res = match kind {
Equal => Value::Bool(lhs == rhs), Add => lhs.checked_add(rhs),
NotEqual => Value::Bool(lhs != 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)
} }
} }
Not(expr) => !self.eval_expr(expr)?, }
Not(expr) => Bool(!self.eval_expr(expr)?.to_bool()),
Literal(value) => value.clone(), Literal(value) => value.clone(),
ExprKind::Cart(members) => Value::Cart( ExprKind::Cart(members) => Value::Cart(
members members
@ -164,21 +206,18 @@ impl ExecEnv {
}) })
.collect::<Result<HashMap<_, _>, _>>()?, .collect::<Result<HashMap<_, _>, _>>()?,
), ),
Index { expr, index } => { Index { cart, index } => {
let value = self.eval_expr(expr)?; let cart = self.eval_expr(cart)?;
let index = self.eval_expr(index)?; let index = self.eval_expr(index)?;
value // TODO: this probably shouldn't be cloned
.into_cart() cart.index(&index).borrow().clone()
.get(&index)
.map(|x| x.borrow().clone())
.unwrap_or(Value::Nul)
} }
// TODO: not too happy with constructing an artificial // TODO: not too happy with constructing an artificial
// Ident here. // Iden here.
Variable(name) => self.get_var(&Ident { Variable(name) => self.get_var(&Iden {
ident: name.to_owned(), iden: name.to_owned(),
span: expr.span.clone(), span: expr.span.clone(),
})?, })?,
}) })
@ -190,52 +229,52 @@ impl ExecEnv {
StmtKind::Print(expr) => { StmtKind::Print(expr) => {
println!("{}", self.eval_expr(expr)?); println!("{}", self.eval_expr(expr)?);
} }
StmtKind::Var { ident, init } => { StmtKind::Var { iden, init } => {
let init = match init { let init = match init {
Some(e) => self.eval_expr(e)?, Some(e) => self.eval_expr(e)?,
None => Value::Nul, None => Value::Nul,
}; };
self.decl_var(&ident.ident, init); self.decl_var(&iden.iden, init);
} }
StmtKind::Functio { StmtKind::Functio { iden, params, body } => {
ident,
params,
body,
} => {
self.decl_var( self.decl_var(
&ident.ident, &iden.iden,
Value::Functio(Functio::AbleFunctio { Value::Functio(Functio::AbleFunctio {
params: params.iter().map(|ident| ident.ident.to_owned()).collect(), params: params.iter().map(|iden| iden.iden.to_string()).collect(),
body: body.block.to_owned(), body: body.block.to_owned(),
}), }),
); );
} }
StmtKind::BfFunctio { StmtKind::BfFunctio {
ident, iden,
tape_len, tape_len,
code, code,
} => { } => {
self.decl_var( self.decl_var(
&ident.ident, &iden.iden,
Value::Functio(Functio::BfFunctio { Value::Functio(Functio::BfFunctio {
instructions: code.to_owned(), instructions: code.to_owned(),
tape_len: tape_len tape_len: tape_len
.as_ref() .as_ref()
.map(|tape_len| self.eval_expr(tape_len).map(|v| v.into_i32() as usize)) .map(|tape_len| self.eval_expr(tape_len).map(|v| v.to_i32() as usize))
.unwrap_or(Ok(crate::brian::DEFAULT_TAPE_SIZE_LIMIT))?, .unwrap_or(Ok(crate::brian::DEFAULT_TAPE_SIZE_LIMIT))?,
}), }),
); );
} }
StmtKind::If { cond, body } => { StmtKind::If { cond, body } => {
if self.eval_expr(cond)?.into_bool() { if self.eval_expr(cond)?.to_bool() {
return self.eval_stmts_hs(&body.block, true); return self.eval_stmts_hs(&body.block, true);
} }
} }
StmtKind::Call { expr, args } => { StmtKind::Call { expr, args } => {
let func = self.eval_expr(expr)?.into_functio(); let func = self.eval_expr(expr)?;
if let Value::Functio(func) = func {
self.fn_call(func, args, &stmt.span)?; self.fn_call(func, args, &stmt.span)?;
} else {
// Fail silently for now.
}
} }
StmtKind::Loop { body } => loop { StmtKind::Loop { body } => loop {
let res = self.eval_stmts_hs(&body.block, true)?; let res = self.eval_stmts_hs(&body.block, true)?;
@ -245,8 +284,9 @@ impl ExecEnv {
HaltStatus::Hopback(_) => continue, HaltStatus::Hopback(_) => continue,
} }
}, },
StmtKind::Assign { assignable, value } => { StmtKind::Assign { iden, value } => {
self.assign(assignable, self.eval_expr(value)?)?; let value = self.eval_expr(value)?;
self.get_var_mut(iden)?.value.replace(value);
} }
StmtKind::Break => { StmtKind::Break => {
return Ok(HaltStatus::Break(stmt.span.clone())); return Ok(HaltStatus::Break(stmt.span.clone()));
@ -254,8 +294,8 @@ impl ExecEnv {
StmtKind::HopBack => { StmtKind::HopBack => {
return Ok(HaltStatus::Hopback(stmt.span.clone())); return Ok(HaltStatus::Hopback(stmt.span.clone()));
} }
StmtKind::Melo(ident) => { StmtKind::Melo(iden) => {
self.get_var_mut(ident)?.melo = true; self.get_var_mut(iden)?.melo = true;
} }
StmtKind::Rlyeh => { StmtKind::Rlyeh => {
// Maybe print a creepy error message or something // Maybe print a creepy error message or something
@ -267,69 +307,20 @@ impl ExecEnv {
.write_all(include_str!("rickroll").as_bytes()) .write_all(include_str!("rickroll").as_bytes())
.expect("Failed to write to stdout"); .expect("Failed to write to stdout");
} }
StmtKind::Read(assignable) => { StmtKind::Read(iden) => {
let mut value = 0; let mut value = 0;
for _ in 0..READ_BITS { for _ in 0..READ_BITS {
value <<= 1; value <<= 1;
value += self.get_bit()? as i32; value += self.get_bit()? as i32;
} }
self.assign(assignable, Value::Int(value))?; self.get_var_mut(iden)?.value.replace(Value::Int(value));
} }
} }
Ok(HaltStatus::Finished) 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) => {
// cell is a cart, so we can do simple
// indexing.
if let Some(x) = c.get(&index) {
// cell[index] exists, get a shared
// reference to it.
Rc::clone(x)
} else {
// 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 => {
// 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);
}
}
Ok(())
}
/// Call a function with the given arguments (i.e., actual /// Call a function with the given arguments (i.e., actual
/// parameters). If the function invocation fails for some reason, /// parameters). If the function invocation fails for some reason,
/// report the error at `span`. /// report the error at `span`.
@ -340,8 +331,8 @@ impl ExecEnv {
.iter() .iter()
.map(|arg| { .map(|arg| {
if let ExprKind::Variable(name) = &arg.kind { if let ExprKind::Variable(name) = &arg.kind {
self.get_var_rc(&Ident { self.get_var_rc(&Iden {
ident: name.to_owned(), iden: name.to_owned(),
span: arg.span.clone(), span: arg.span.clone(),
}) })
} else { } else {
@ -396,17 +387,6 @@ impl ExecEnv {
self.stack.pop(); self.stack.pop();
res?; res?;
} }
Functio::Eval(code) => {
if !args.is_empty() {
return Err(Error {
kind: ErrorKind::MismatchedArgumentError,
span: span.to_owned(),
});
}
let stmts = crate::parser::Parser::new(&code).init()?;
self.eval_stmts(&stmts)?;
}
} }
Ok(()) Ok(())
} }
@ -433,9 +413,9 @@ impl ExecEnv {
/// Get the value of a variable. Throw an error if the variable is /// Get the value of a variable. Throw an error if the variable is
/// inaccessible or banned. /// inaccessible or banned.
fn get_var(&self, name: &Ident) -> Result<Value, Error> { fn get_var(&self, name: &Iden) -> Result<Value, Error> {
// One-letter names are reserved as base55 numbers. // One-letter names are reserved as base55 numbers.
let mut chars = name.ident.chars(); let mut chars = name.iden.chars();
if let (Some(first), None) = (chars.next(), chars.next()) { if let (Some(first), None) = (chars.next(), chars.next()) {
return Ok(Value::Int(base_55::char2num(first))); return Ok(Value::Int(base_55::char2num(first)));
} }
@ -446,20 +426,20 @@ impl ExecEnv {
.stack .stack
.iter() .iter()
.rev() .rev()
.find_map(|scope| scope.variables.get(&name.ident)) .find_map(|scope| scope.variables.get(&name.iden))
{ {
Some(var) => { Some(var) => {
if !var.melo { if !var.melo {
Ok(var.value.borrow().clone()) Ok(var.value.borrow().clone())
} else { } else {
Err(Error { Err(Error {
kind: ErrorKind::MeloVariable(name.ident.to_owned()), kind: ErrorKind::MeloVariable(name.iden.to_owned()),
span: name.span.clone(), span: name.span.clone(),
}) })
} }
} }
None => Err(Error { None => Err(Error {
kind: ErrorKind::UnknownVariable(name.ident.to_owned()), kind: ErrorKind::UnknownVariable(name.iden.to_owned()),
span: name.span.clone(), span: name.span.clone(),
}), }),
} }
@ -467,27 +447,27 @@ impl ExecEnv {
/// Get a mutable reference to a variable. Throw an error if the /// Get a mutable reference to a variable. Throw an error if the
/// variable is inaccessible or banned. /// variable is inaccessible or banned.
fn get_var_mut(&mut self, name: &Ident) -> Result<&mut Variable, Error> { fn get_var_mut(&mut self, name: &Iden) -> Result<&mut Variable, Error> {
// This function has a lot of duplicated code with `get_var`, // This function has a lot of duplicated code with `get_var`,
// which I feel like is a bad sign... // which I feel like is a bad sign...
match self match self
.stack .stack
.iter_mut() .iter_mut()
.rev() .rev()
.find_map(|scope| scope.variables.get_mut(&name.ident)) .find_map(|scope| scope.variables.get_mut(&name.iden))
{ {
Some(var) => { Some(var) => {
if !var.melo { if !var.melo {
Ok(var) Ok(var)
} else { } else {
Err(Error { Err(Error {
kind: ErrorKind::MeloVariable(name.ident.to_owned()), kind: ErrorKind::MeloVariable(name.iden.to_owned()),
span: name.span.clone(), span: name.span.clone(),
}) })
} }
} }
None => Err(Error { None => Err(Error {
kind: ErrorKind::UnknownVariable(name.ident.to_owned()), kind: ErrorKind::UnknownVariable(name.iden.to_owned()),
span: name.span.clone(), span: name.span.clone(),
}), }),
} }
@ -495,7 +475,7 @@ impl ExecEnv {
/// Get an Rc'd pointer to the value of a variable. Throw an error /// Get an Rc'd pointer to the value of a variable. Throw an error
/// if the variable is inaccessible or banned. /// if the variable is inaccessible or banned.
fn get_var_rc(&mut self, name: &Ident) -> Result<Rc<RefCell<Value>>, Error> { fn get_var_rc(&mut self, name: &Iden) -> Result<Rc<RefCell<Value>>, Error> {
Ok(self.get_var_mut(name)?.value.clone()) Ok(self.get_var_mut(name)?.value.clone())
} }
@ -591,7 +571,7 @@ mod tests {
span: 1..1 span: 1..1
}) })
.unwrap(), .unwrap(),
Value::Int(-2147483648) Value::Int(42)
); );
// And the same for divide by zero. // And the same for divide by zero.
@ -599,7 +579,7 @@ mod tests {
env.eval_expr(&Expr { env.eval_expr(&Expr {
kind: ExprKind::BinOp { kind: ExprKind::BinOp {
lhs: Box::new(Expr { lhs: Box::new(Expr {
kind: ExprKind::Literal(Value::Int(84)), kind: ExprKind::Literal(Value::Int(1)),
span: 1..1, span: 1..1,
}), }),
rhs: Box::new(Expr { rhs: Box::new(Expr {
@ -611,7 +591,7 @@ mod tests {
span: 1..1 span: 1..1
}) })
.unwrap(), .unwrap(),
Value::Int(2) Value::Int(42)
); );
} }
@ -637,8 +617,8 @@ mod tests {
// Declaring and reading from a variable. // Declaring and reading from a variable.
eval(&mut env, "var foo = 32; var bar = foo + 1;").unwrap(); eval(&mut env, "var foo = 32; var bar = foo + 1;").unwrap();
assert_eq!( assert_eq!(
env.get_var(&Ident { env.get_var(&Iden {
ident: "bar".to_owned(), iden: "bar".to_owned(),
span: 1..1, span: 1..1,
}) })
.unwrap(), .unwrap(),
@ -648,8 +628,8 @@ mod tests {
// Assigning an existing variable. // Assigning an existing variable.
eval(&mut env, "foo = \"hi\";").unwrap(); eval(&mut env, "foo = \"hi\";").unwrap();
assert_eq!( assert_eq!(
env.get_var(&Ident { env.get_var(&Iden {
ident: "foo".to_owned(), iden: "foo".to_owned(),
span: 1..1, span: 1..1,
}) })
.unwrap(), .unwrap(),
@ -674,8 +654,8 @@ mod tests {
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
env.get_var(&Ident { env.get_var(&Iden {
ident: "foo".to_owned(), iden: "foo".to_owned(),
span: 1..1, span: 1..1,
}) })
.unwrap(), .unwrap(),

View file

@ -64,7 +64,13 @@ pub enum Token {
#[token("!=")] #[token("!=")]
NotEqual, NotEqual,
#[regex("!|aint")] // also add aint as a not keyword #[token("&")]
And,
#[token("|")]
Or,
#[token("!|aint")] // also add aint as a not keyword
Not, Not,
// Keywords // Keywords
@ -117,7 +123,7 @@ pub enum Token {
// Literals // Literals
/// True, False /// True, False
#[regex("true|false", get_value)] #[regex("true|false", get_bool)]
Bool(bool), Bool(bool),
/// Always, Sometimes, Never /// Always, Sometimes, Never
@ -133,11 +139,11 @@ pub enum Token {
String(String), String(String),
/// Integer /// Integer
#[regex(r"-?[0-9]+", get_value)] #[regex(r"-?[0-9]+", get_int)]
Integer(i32), Integer(i32),
/// A C-complaint identifier /// A C-complaint identifier
#[regex(r"[a-zA-Z_][a-zA-Z_0-9]*", get_ident)] #[regex(r"[a-zA-Z_][a-zA-Z_0-9]*", get_iden)]
Identifier(String), Identifier(String),
#[regex(r"owo .*")] #[regex(r"owo .*")]
@ -151,7 +157,11 @@ pub enum Token {
Error, Error,
} }
fn get_value<T: std::str::FromStr>(lexer: &mut Lexer<Token>) -> Option<T> { fn get_bool(lexer: &mut Lexer<Token>) -> Option<bool> {
lexer.slice().parse().ok()
}
fn get_int(lexer: &mut Lexer<Token>) -> Option<i32> {
lexer.slice().parse().ok() lexer.slice().parse().ok()
} }
@ -168,7 +178,7 @@ fn get_abool(lexer: &mut Lexer<Token>) -> Option<Abool> {
} }
} }
fn get_ident(lexer: &mut Lexer<Token>) -> String { fn get_iden(lexer: &mut Lexer<Token>) -> String {
lexer.slice().to_owned() lexer.slice().to_owned()
} }

View file

@ -76,19 +76,19 @@ impl<'source> Parser<'source> {
Token::Melo => Ok(Stmt::new(self.melo_flow()?, start..self.lexer.span().end)), 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::Loop => Ok(Stmt::new(self.loop_flow()?, start..self.lexer.span().end)),
Token::Break => Ok(Stmt::new( Token::Break => Ok(Stmt::new(
self.semicolon_terminated(StmtKind::Break)?, self.semi_terminated(StmtKind::Break)?,
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
Token::HopBack => Ok(Stmt::new( Token::HopBack => Ok(Stmt::new(
self.semicolon_terminated(StmtKind::HopBack)?, self.semi_terminated(StmtKind::HopBack)?,
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
Token::Rlyeh => Ok(Stmt::new( Token::Rlyeh => Ok(Stmt::new(
self.semicolon_terminated(StmtKind::Rlyeh)?, self.semi_terminated(StmtKind::Rlyeh)?,
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
Token::Rickroll => Ok(Stmt::new( Token::Rickroll => Ok(Stmt::new(
self.semicolon_terminated(StmtKind::Rickroll)?, self.semi_terminated(StmtKind::Rickroll)?,
start..self.lexer.span().end, start..self.lexer.span().end,
)), )),
@ -98,8 +98,6 @@ impl<'source> Parser<'source> {
| Token::Integer(_) | Token::Integer(_)
| Token::Abool(_) | Token::Abool(_)
| Token::Bool(_) | Token::Bool(_)
| Token::Nul
| Token::Not
| Token::LeftBracket | Token::LeftBracket
| Token::LeftParen => Ok(Stmt::new( | Token::LeftParen => Ok(Stmt::new(
self.value_flow(token)?, self.value_flow(token)?,
@ -116,7 +114,7 @@ impl<'source> Parser<'source> {
/// Require statement to be semicolon terminated /// Require statement to be semicolon terminated
/// ///
/// Utility function for short statements /// Utility function for short statements
fn semicolon_terminated(&mut self, stmt_kind: StmtKind) -> Result<StmtKind, Error> { fn semi_terminated(&mut self, stmt_kind: StmtKind) -> Result<StmtKind, Error> {
self.require(Token::Semicolon)?; self.require(Token::Semicolon)?;
Ok(stmt_kind) Ok(stmt_kind)
} }
@ -131,13 +129,13 @@ impl<'source> Parser<'source> {
} }
/// Get an Identifier /// Get an Identifier
fn get_ident(&mut self) -> Result<Ident, Error> { fn get_iden(&mut self) -> Result<Iden, Error> {
match self.checked_next()? { match self.checked_next()? {
Token::Identifier(ident) => Ok(Ident { Token::Identifier(iden) => Ok(Iden {
ident: if self.tdark { iden: if self.tdark {
ident.replace("lang", "script") iden.replace("lang", "script")
} else { } else {
ident iden
}, },
span: self.lexer.span(), span: self.lexer.span(),
}), }),
@ -194,7 +192,7 @@ impl<'source> Parser<'source> {
Token::LeftBracket => match buf.take() { Token::LeftBracket => match buf.take() {
Some(buf) => Ok(Expr::new( Some(buf) => Ok(Expr::new(
ExprKind::Index { ExprKind::Index {
expr: Box::new(buf), cart: Box::new(buf),
index: Box::new(self.expr_flow(Token::RightBracket)?), index: Box::new(self.expr_flow(Token::RightBracket)?),
}, },
start..self.lexer.span().end, start..self.lexer.span().end,
@ -210,7 +208,9 @@ impl<'source> Parser<'source> {
| Token::EqualEqual | Token::EqualEqual
| Token::NotEqual | Token::NotEqual
| Token::LessThan | Token::LessThan
| Token::GreaterThan => Ok(Expr::new( | Token::GreaterThan
| Token::And
| Token::Or => Ok(Expr::new(
self.binop_flow( self.binop_flow(
BinOpKind::from_token(token).map_err(|e| Error::new(e, self.lexer.span()))?, BinOpKind::from_token(token).map_err(|e| Error::new(e, self.lexer.span()))?,
buf, buf,
@ -340,7 +340,7 @@ impl<'source> Parser<'source> {
let stmt = StmtKind::Print(buf.take().ok_or_else(|| { let stmt = StmtKind::Print(buf.take().ok_or_else(|| {
Error::new(ErrorKind::UnexpectedToken(Token::Print), self.lexer.span()) Error::new(ErrorKind::UnexpectedToken(Token::Print), self.lexer.span())
})?); })?);
break self.semicolon_terminated(stmt)?; break self.semi_terminated(stmt)?;
} }
// Functio call // Functio call
@ -355,29 +355,26 @@ impl<'source> Parser<'source> {
// Variable Assignment // Variable Assignment
Token::Equal => { Token::Equal => {
if let Some(Ok(assignable)) = buf.take().map(Assignable::from_expr) { if let Some(Expr {
kind: ExprKind::Variable(iden),
span,
}) = buf
{
break StmtKind::Assign { break StmtKind::Assign {
assignable, iden: Iden::new(iden, span),
value: self.expr_flow(Token::Semicolon)?, value: self.expr_flow(Token::Semicolon)?,
}; };
} else {
return Err(Error::new(
ErrorKind::UnexpectedToken(Token::Equal),
self.lexer.span(),
));
} }
} }
// Read input // Read input
Token::Read => { Token::Read => {
if let Some(Ok(assignable)) = buf.take().map(Assignable::from_expr) { if let Some(Expr {
self.require(Token::Semicolon)?; kind: ExprKind::Variable(iden),
break StmtKind::Read(assignable); span,
} else { }) = buf
return Err(Error::new( {
ErrorKind::UnexpectedToken(Token::Read), break self.semi_terminated(StmtKind::Read(Iden::new(iden, span)))?;
self.lexer.span(),
));
} }
} }
@ -403,9 +400,9 @@ impl<'source> Parser<'source> {
/// Parse functio flow /// Parse functio flow
/// ///
/// functio $ident (a, b, c) { ... } /// functio $iden (a, b, c) { ... }
fn functio_flow(&mut self) -> Result<StmtKind, Error> { fn functio_flow(&mut self) -> Result<StmtKind, Error> {
let ident = self.get_ident()?; let iden = self.get_iden()?;
self.require(Token::LeftParen)?; self.require(Token::LeftParen)?;
@ -414,7 +411,7 @@ impl<'source> Parser<'source> {
match self.checked_next()? { match self.checked_next()? {
Token::RightParen => break, Token::RightParen => break,
Token::Identifier(i) => { Token::Identifier(i) => {
params.push(Ident::new(i, self.lexer.span())); params.push(Iden::new(i, self.lexer.span()));
// Require comma (next) or right paren (end) after identifier // Require comma (next) or right paren (end) after identifier
match self.checked_next()? { match self.checked_next()? {
@ -434,18 +431,14 @@ impl<'source> Parser<'source> {
let body = self.get_block()?; let body = self.get_block()?;
Ok(StmtKind::Functio { Ok(StmtKind::Functio { iden, params, body })
ident,
params,
body,
})
} }
/// Parse BF function declaration /// Parse BF function declaration
/// ///
/// `bff $ident ([tapelen]) { ... }` /// `bff $iden ([tapelen]) { ... }`
fn bff_flow(&mut self) -> Result<StmtKind, Error> { fn bff_flow(&mut self) -> Result<StmtKind, Error> {
let ident = self.get_ident()?; let iden = self.get_iden()?;
let tape_len = match self.checked_next()? { let tape_len = match self.checked_next()? {
Token::LeftParen => { Token::LeftParen => {
@ -479,7 +472,7 @@ impl<'source> Parser<'source> {
} }
Ok(StmtKind::BfFunctio { Ok(StmtKind::BfFunctio {
ident, iden,
tape_len, tape_len,
code, code,
}) })
@ -520,20 +513,20 @@ impl<'source> Parser<'source> {
/// Parse variable declaration /// Parse variable declaration
fn var_flow(&mut self) -> Result<StmtKind, Error> { fn var_flow(&mut self) -> Result<StmtKind, Error> {
let ident = self.get_ident()?; let iden = self.get_iden()?;
let init = match self.checked_next()? { let init = match self.checked_next()? {
Token::Equal => Some(self.expr_flow(Token::Semicolon)?), Token::Equal => Some(self.expr_flow(Token::Semicolon)?),
Token::Semicolon => None, Token::Semicolon => None,
t => return Err(Error::new(ErrorKind::UnexpectedToken(t), self.lexer.span())), t => return Err(Error::new(ErrorKind::UnexpectedToken(t), self.lexer.span())),
}; };
Ok(StmtKind::Var { ident, init }) Ok(StmtKind::Var { iden, init })
} }
/// Parse Melo flow /// Parse Melo flow
fn melo_flow(&mut self) -> Result<StmtKind, Error> { fn melo_flow(&mut self) -> Result<StmtKind, Error> {
let ident = self.get_ident()?; let iden = self.get_iden()?;
self.semicolon_terminated(StmtKind::Melo(ident)) self.semi_terminated(StmtKind::Melo(iden))
} }
/// Parse loop flow /// Parse loop flow
@ -565,7 +558,7 @@ mod tests {
rhs: Box::new(Expr { rhs: Box::new(Expr {
kind: ExprKind::BinOp { kind: ExprKind::BinOp {
lhs: Box::new(Expr { lhs: Box::new(Expr {
kind: ExprKind::Variable("a".to_owned()), kind: ExprKind::Variable("a".to_string()),
span: 5..6, span: 5..6,
}), }),
rhs: Box::new(Expr { rhs: Box::new(Expr {
@ -600,8 +593,8 @@ mod tests {
let code = r#"var a = 42;"#; let code = r#"var a = 42;"#;
let expected = &[Stmt { let expected = &[Stmt {
kind: StmtKind::Var { kind: StmtKind::Var {
ident: Ident { iden: Iden {
ident: "a".to_owned(), iden: "a".to_string(),
span: 4..5, span: 4..5,
}, },
init: Some(Expr { init: Some(Expr {
@ -638,7 +631,7 @@ mod tests {
body: Block { body: Block {
block: vec![Stmt { block: vec![Stmt {
kind: StmtKind::Print(Expr { kind: StmtKind::Print(Expr {
kind: ExprKind::Literal(Value::Str("Buy Able products!".to_owned())), kind: ExprKind::Literal(Value::Str("Buy Able products!".to_string())),
span: 19..39, span: 19..39,
}), }),
span: 19..46, span: 19..46,
@ -657,18 +650,18 @@ mod tests {
let code = r#"T-Dark { var lang = "lang" + lang; }"#; let code = r#"T-Dark { var lang = "lang" + lang; }"#;
let expected = &[Stmt { let expected = &[Stmt {
kind: StmtKind::Var { kind: StmtKind::Var {
ident: Ident { iden: Iden {
ident: "script".to_owned(), iden: "script".to_string(),
span: 13..17, span: 13..17,
}, },
init: Some(Expr { init: Some(Expr {
kind: ExprKind::BinOp { kind: ExprKind::BinOp {
lhs: Box::new(Expr { lhs: Box::new(Expr {
kind: ExprKind::Literal(Value::Str("script".to_owned())), kind: ExprKind::Literal(Value::Str("script".to_string())),
span: 20..26, span: 20..26,
}), }),
rhs: Box::new(Expr { rhs: Box::new(Expr {
kind: ExprKind::Variable("script".to_owned()), kind: ExprKind::Variable("script".to_string()),
span: 29..33, span: 29..33,
}), }),
kind: BinOpKind::Add, kind: BinOpKind::Add,
@ -691,7 +684,7 @@ mod tests {
kind: ExprKind::Cart(vec![ kind: ExprKind::Cart(vec![
( (
Expr { Expr {
kind: ExprKind::Literal(Value::Str("able".to_owned())), kind: ExprKind::Literal(Value::Str("able".to_string())),
span: 1..7, span: 1..7,
}, },
Expr { Expr {
@ -701,7 +694,7 @@ mod tests {
), ),
( (
Expr { Expr {
kind: ExprKind::Literal(Value::Str("script".to_owned())), kind: ExprKind::Literal(Value::Str("script".to_string())),
span: 14..22, span: 14..22,
}, },
Expr { Expr {
@ -735,14 +728,14 @@ mod tests {
let expected = &[Stmt { let expected = &[Stmt {
kind: StmtKind::Print(Expr { kind: StmtKind::Print(Expr {
kind: ExprKind::Index { kind: ExprKind::Index {
expr: Box::new(Expr { cart: Box::new(Expr {
kind: ExprKind::Cart(vec![( kind: ExprKind::Cart(vec![(
Expr { Expr {
kind: ExprKind::Literal(Value::Str("able".to_owned())), kind: ExprKind::Literal(Value::Str("able".to_string())),
span: 1..7, span: 1..7,
}, },
Expr { Expr {
kind: ExprKind::Literal(Value::Str("ablecorp".to_owned())), kind: ExprKind::Literal(Value::Str("ablecorp".to_string())),
span: 11..21, span: 11..21,
}, },
)]), )]),

View file

@ -1,13 +1,13 @@
use std::{ use std::{
cell::RefCell, collections::HashMap, fmt::Display, hash::Hash, io::Write, mem::discriminant, cell::RefCell, collections::HashMap, convert::TryFrom, fmt::Display, hash::Hash, io::Write,
ops, rc::Rc, vec, mem::discriminant, rc::Rc,
}; };
use rand::Rng; use rand::Rng;
use crate::{ast::Stmt, consts}; use crate::{ast::Stmt, consts};
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum Abool { pub enum Abool {
Never = -1, Never = -1,
Sometimes = 0, Sometimes = 0,
@ -44,11 +44,8 @@ pub enum Functio {
params: Vec<String>, params: Vec<String>,
body: Vec<Stmt>, body: Vec<Stmt>,
}, },
Eval(String),
} }
pub type Cart = HashMap<Value, Rc<RefCell<Value>>>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Value { pub enum Value {
Nul, Nul,
@ -57,13 +54,7 @@ pub enum Value {
Bool(bool), Bool(bool),
Abool(Abool), Abool(Abool),
Functio(Functio), Functio(Functio),
Cart(Cart), Cart(HashMap<Value, Rc<RefCell<Value>>>),
}
impl Default for Value {
fn default() -> Self {
Self::Nul
}
} }
impl Hash for Value { impl Hash for Value {
@ -81,6 +72,24 @@ 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 { impl Value {
/// Write an AbleScript value to a Brainfuck input stream by /// Write an AbleScript value to a Brainfuck input stream by
/// coercing the value to an integer, then truncating that integer /// coercing the value to an integer, then truncating that integer
@ -89,408 +98,73 @@ impl Value {
/// any IO errors will cause a panic. /// any IO errors will cause a panic.
pub fn bf_write(&self, stream: &mut impl Write) { pub fn bf_write(&self, stream: &mut impl Write) {
stream stream
.write_all(&[self.clone().into_i32() as u8]) .write_all(&[self.clone().to_i32() as u8])
.expect("Failed to write to Brainfuck input"); .expect("Failed to write to Brainfuck input");
} }
/// Coerce a value to an integer. /// Coerce a value to an integer.
pub fn into_i32(self) -> i32 { pub fn to_i32(&self) -> i32 {
match self { match self {
Value::Abool(a) => a as _, Value::Abool(a) => *a as _,
Value::Bool(b) => b as _, Value::Bool(b) => *b as _,
Value::Functio(func) => match func { 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 { Functio::BfFunctio {
instructions, instructions,
tape_len, tape_len,
} => (instructions.len() + tape_len) as _, } => (instructions.len() + tape_len) as _,
Functio::AbleFunctio { params, body } => { Functio::AbleFunctio { params, body } => (params.len() + body.len()) as _,
(params.len() + format!("{:?}", body).len()) as _
}
Functio::Eval(s) => s.len() as _,
}, },
Value::Int(i) => i, Value::Int(i) => *i,
Value::Nul => consts::ANSWER, Value::Nul => consts::ANSWER,
Value::Str(text) => text.parse().unwrap_or(consts::ANSWER), Value::Str(text) => text.parse().unwrap_or(consts::ANSWER),
Value::Cart(c) => c.len() as _, Value::Cart(c) => c.len() as _,
} }
} }
/// Coerce a value to a boolean. /// Coerce a Value to a boolean. The conversion cannot fail.
pub fn into_bool(self) -> bool { pub fn to_bool(&self) -> bool {
match self { match self {
Value::Abool(b) => b.into(), Value::Abool(b) => (*b).into(),
Value::Bool(b) => b, Value::Bool(b) => *b,
Value::Functio(_) => true, Value::Functio(_) => true,
Value::Int(x) => x != 0, Value::Int(x) => *x != 0,
Value::Nul => false, Value::Nul => true,
Value::Str(s) => match s.to_lowercase().as_str() { Value::Str(s) => !s.is_empty(),
"false" | "no" | "🇳🇴" => false,
"true" | "yes" => true,
s => !s.is_empty(),
},
Value::Cart(c) => !c.is_empty(), Value::Cart(c) => !c.is_empty(),
} }
} }
/// Coerce a value to an aboolean. /// Index a value with another value, as in the "a[b]" syntax.
pub fn into_abool(self) -> Abool { pub fn index(&self, index: &Value) -> Rc<RefCell<Value>> {
match self { Rc::new(RefCell::new(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(_) => todo!(),
Value::Bool(_) => todo!(),
Value::Abool(_) => todo!(),
Value::Functio(f) => f,
Value::Cart(_) => todo!(),
}
}
/// Coerce a value into a cart.
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::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::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,
}
}
}
impl ops::Add for Value {
type Output = Value;
fn add(self, rhs: Self) -> Self::Output {
match self {
Value::Nul => match rhs {
Value::Nul => Value::Nul, Value::Nul => Value::Nul,
Value::Str(_) => Value::Str(self.to_string()) + rhs, Value::Str(s) => Value::Int(
Value::Int(_) => Value::Int(self.into_i32()) + rhs, usize::try_from(index.to_i32() - 1)
Value::Bool(_) => Value::Bool(self.into_bool()) + rhs, .ok()
Value::Abool(_) => Value::Abool(self.into_abool()) + rhs, .and_then(|idx| s.as_bytes().get(idx).cloned())
Value::Functio(_) => Value::Functio(self.into_functio()) + rhs, .map(|value| value as i32)
Value::Cart(_) => Value::Cart(self.into_cart()) + rhs, .unwrap_or(0),
},
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(_) => {
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())
}
}
}
}
impl ops::Sub for Value {
type Output = Value;
fn sub(self, rhs: Self) -> Self::Output {
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(_) => (self.clone() + rhs.clone()) * !(self * rhs),
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()
}),
}
}
}
impl ops::Mul for Value {
type Output = Value;
fn mul(self, rhs: Self) -> Self::Output {
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(_) => {
Value::Abool(Value::Int(self.into_i32().min(rhs.into_i32())).into_abool())
}
Value::Functio(_) => 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(),
)
}
}
}
}
impl ops::Div for Value {
type Output = Value;
fn div(self, rhs: Self) -> Self::Output {
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(i.wrapping_div(match rhs.into_i32() { Value::Int(i) => Value::Int(
0 => consts::ANSWER, usize::try_from(index.to_i32() - 1)
x => x, .ok()
})), .and_then(|idx| format!("{}", i).as_bytes().get(idx).cloned())
Value::Bool(b) => Value::Bool(!b || rhs.into_bool()), .map(|value| value as i32)
Value::Abool(_) => !self + rhs, .unwrap_or(0),
Value::Functio(_) => todo!(),
Value::Cart(c) => {
let cart_len = c.len();
let chunk_len = rhs.into_i32() as usize;
Value::Cart(
c.into_iter()
.collect::<Vec<_>>()
.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.iter().cloned().collect()))),
)
})
.collect(),
)
}
}
}
}
impl ops::Not for Value {
type Output = Value;
fn not(self) -> Self::Output {
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(),
), ),
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)))
} }
} }))
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
let other = other.clone();
match self {
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(),
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<std::cmp::Ordering> {
use std::cmp::Ordering::*;
let other = other.clone();
match self {
Value::Nul => {
if other == Value::Nul {
Some(Equal)
} else {
None
}
}
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(_) => self.clone().into_i32().partial_cmp(&other.into_i32()),
Value::Cart(c) => Some(c.len().cmp(&other.into_cart().len())),
}
} }
} }
@ -525,21 +199,12 @@ impl Display for Value {
body, body,
) )
} }
Functio::Eval(s) => write!(f, "{}", s),
}, },
Value::Cart(c) => { Value::Cart(c) => {
write!(f, "[")?; write!(f, "[")?;
let mut cart_vec = c.iter().collect::<Vec<_>>();
cart_vec.sort_by(|x, y| x.0.partial_cmp(y.0).unwrap_or(std::cmp::Ordering::Less));
for (idx, (key, value)) in cart_vec.into_iter().enumerate() { for (key, value) in c {
write!( write!(f, "{} <= {},", value.borrow(), key)?;
f,
"{}{} <= {}",
if idx != 0 { ", " } else { "" },
value.borrow(),
key
)?;
} }
write!(f, "]") write!(f, "]")