diff --git a/ablescript/src/ast.rs b/ablescript/src/ast.rs index a5f19055..3a7941e7 100644 --- a/ablescript/src/ast.rs +++ b/ablescript/src/ast.rs @@ -190,6 +190,7 @@ pub enum ExprKind { expr: Box, index: Box, }, + Len(Box), Variable(String), } diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 183eb9ff..bb79d335 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -175,6 +175,7 @@ impl ExecEnv { .map(|x| x.borrow().clone()) .unwrap_or(Value::Nul) } + Len(expr) => Value::Int(self.eval_expr(expr)?.len()), // TODO: not too happy with constructing an artificial // Ident here. diff --git a/ablescript/src/parser.rs b/ablescript/src/parser.rs index 6f7ebb66..9fd351e9 100644 --- a/ablescript/src/parser.rs +++ b/ablescript/src/parser.rs @@ -195,10 +195,7 @@ impl<'source> Parser<'source> { Token::LeftBracket => match buf.take() { Some(buf) => Ok(Expr::new( - ExprKind::Index { - expr: Box::new(buf), - index: Box::new(self.expr_flow(Token::RightBracket)?), - }, + self.index_flow(buf)?, start..self.lexer.span().end, )), None => Ok(Expr::new(self.cart_flow()?, start..self.lexer.span().end)), @@ -279,6 +276,27 @@ impl<'source> Parser<'source> { Ok(ExprKind::Cart(cart)) } + /// Flow for indexing operations + /// + /// Indexing with empty index resolves to length of expression, else it indexes + fn index_flow(&mut self, expr: Expr) -> Result { + let mut buf = None; + Ok(loop { + match self.checked_next()? { + Token::RightBracket => match buf { + Some(index) => { + break ExprKind::Index { + expr: Box::new(expr), + index: Box::new(index), + } + } + None => break ExprKind::Len(Box::new(expr)), + }, + token => buf = Some(self.parse_expr(token, &mut buf)?), + } + }) + } + /// Flow for operators /// /// Generates operation from LHS buffer and next expression as RHS diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 5d42a198..545f2d45 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -122,36 +122,36 @@ impl Value { match self { 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 + Value::Functio(f) => match f { Functio::Bf { instructions, tape_len, - } => (instructions.len() + tape_len) as _, - Functio::Able { params, body } => (params.len() + format!("{:?}", body).len()) as _, - Functio::Chain { functios, kind } => { - let (lhs, rhs) = *functios; - match kind { - FunctioChainKind::Equal => { - Value::Int(Value::Functio(lhs).into_i32()) - + Value::Int(Value::Functio(rhs).into_i32()) - } - FunctioChainKind::ByArity => { - Value::Int(Value::Functio(lhs).into_i32()) - * Value::Int(Value::Functio(rhs).into_i32()) - } - } - .into_i32() + } => instructions.into_iter().map(|x| x as i32).sum::() * tape_len as i32, + Functio::Able { params, body } => { + params + .into_iter() + .map(|x| x.bytes().map(|x| x as i32).sum::()) + .sum::() + + body.len() as i32 } - Functio::Eval(s) => s.len() as _, + Functio::Chain { functios, kind } => { + let (lf, rf) = *functios; + Value::Functio(lf).into_i32() + + Value::Functio(rf).into_i32() + * match kind { + FunctioChainKind::Equal => -1, + FunctioChainKind::ByArity => 1, + } + } + Functio::Eval(code) => code.bytes().map(|x| x as i32).sum(), }, Value::Int(i) => i, Value::Nul => consts::ANSWER, Value::Str(text) => text.parse().unwrap_or(consts::ANSWER), - Value::Cart(c) => c.len() as _, + Value::Cart(c) => c + .into_iter() + .map(|(i, v)| i.into_i32() * v.borrow().clone().into_i32()) + .sum(), } } @@ -410,6 +410,55 @@ impl Value { Value::Cart(c) => c, } } + + /// Get a lenght of a value + pub fn len(&self) -> i32 { + match self { + Value::Nul => 0, + Value::Str(s) => s.len() as _, + Value::Int(i) => i.count_zeros() as _, + Value::Bool(b) if *b => -2, + Value::Bool(_) => 2, + Value::Abool(a) => match a { + Abool::Never => -3, + Abool::Sometimes => { + if rand::thread_rng().gen() { + 3 + } else { + -3 + } + } + Abool::Always => 3, + }, + Value::Functio(f) => match 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 + Functio::Bf { + instructions, + tape_len, + } => (instructions.len() + tape_len) as _, + Functio::Able { params, body } => (params.len() + format!("{:?}", body).len()) as _, + Functio::Chain { functios, kind } => { + let (lhs, rhs) = *functios.clone(); + match kind { + FunctioChainKind::Equal => { + Value::Int(Value::Functio(lhs).into_i32()) + + Value::Int(Value::Functio(rhs).into_i32()) + } + FunctioChainKind::ByArity => { + Value::Int(Value::Functio(lhs).into_i32()) + * Value::Int(Value::Functio(rhs).into_i32()) + } + } + .into_i32() + } + Functio::Eval(s) => s.len() as _, + }, + Value::Cart(c) => c.len() as _, + } + } } impl ops::Add for Value {