feat(len): len operator implementation

main
flavien 2023-12-18 09:05:50 +01:00
parent 967891fb7b
commit 7567312055
No known key found for this signature in database
9 changed files with 62 additions and 12 deletions

View File

@ -54,14 +54,16 @@ var: z => val: 8
- print statement OK
- string / char => indexing OK / escaping OK
- local scope for { statements } OK
- array OK => iterators NOK
- read / write
- array OK => len keyword OK
- read / write => file, standard io, network
- dict
- program arguments
- standard lib
- types declaration
- type checking before runtime
- types inference
- program arguments
- structs => methods (list container?)
- for loop and iterators NOK
- pow / bitwise / bitshift operators
- range
- import from other files

View File

@ -238,6 +238,7 @@ impl UnaryCompute for UnaryOp {
Ok(match self {
UnaryOp::Minus => Value::Number(-expr.evaluate(env)?.int()?),
UnaryOp::Not => Value::Boolean(!expr.evaluate(env)?.truth()?),
UnaryOp::Len => Value::Number(expr.evaluate(env)?.len()?),
})
}
}

View File

@ -7,11 +7,13 @@ use super::{
};
use crate::parser::syntax::{Expr, Value};
#[allow(clippy::len_without_is_empty)]
pub trait EvaluateValue {
fn int(&self) -> Result<i64, String>;
fn truth(&self) -> Result<bool, String>;
fn str(&self) -> Result<Rc<Vec<u8>>, String>;
fn char(&self) -> Result<u8, String>;
fn len(&self) -> Result<i64, String>;
}
impl EvaluateValue for Value {
@ -42,6 +44,16 @@ impl EvaluateValue for Value {
_ => Err(format!("char intended here, not {}", self.get_type())),
}
}
fn len(&self) -> Result<i64, String> {
match self {
Value::String(string) => Ok(string.len() as i64),
Value::Array(array) => Ok(array.len() as i64),
_ => Err(format!(
"string or array intended with len operator, not {}",
self.get_type()
)),
}
}
}
fn evaluate_variable(

View File

@ -1014,6 +1014,11 @@ mod tests {
_ => panic!("b should be Value::Char"),
};
assert_eq!(e, b'\'');
let f = match environment.get("f") {
Some(Value::Number(value)) => value,
_ => panic!("b should be Number::Char"),
};
assert_eq!(f, 12);
}
#[test]
@ -1083,5 +1088,23 @@ mod tests {
_ => panic!("e should be defined"),
};
assert_eq!(format!("{}", e), "[1, 4, 3]");
let f = match environment.get("f") {
Some(value) => match value {
Value::Array(_) => value,
_ => panic!("f should be Value::Array"),
},
_ => panic!("f should be defined"),
};
assert_eq!(format!("{}", f), "[2, 4, 6]");
}
#[test]
fn test_len_not_array_str() {
let environment = run_string("var x = len 2;");
assert!(environment.is_err());
assert_eq!(
environment.unwrap_err(),
"string or array intended with len operator, not number"
)
}
}

View File

@ -26,7 +26,7 @@ lazy_static::lazy_static! {
.op(Op::infix(op_lt, Left) | Op::infix(op_gt, Left) | Op::infix(op_eq, Left) | Op::infix(op_ge, Left) | Op::infix(op_le, Left) | Op::infix(op_ne, Left))
.op(Op::infix(op_add, Left) | Op::infix(op_sub, Left))
.op(Op::infix(op_mul, Left) | Op::infix(op_div, Left) | Op::infix(op_mod, Left))
.op(Op::prefix(op_neg) | Op::prefix(op_not))
.op(Op::prefix(op_neg) | Op::prefix(op_not) | Op::prefix(op_len))
};
}
@ -178,6 +178,7 @@ fn build_expr(pair: Pair<Rule>) -> Result<Expr, String> {
(_, Err(err)) => Err(err),
(Rule::op_neg, Ok(rhs)) => Ok(Expr::UnaryOp(Box::new(rhs), UnaryOp::Minus)),
(Rule::op_not, Ok(rhs)) => Ok(Expr::UnaryOp(Box::new(rhs), UnaryOp::Not)),
(Rule::op_len, Ok(rhs)) => Ok(Expr::UnaryOp(Box::new(rhs), UnaryOp::Len)),
(rule, _) => Err(format!(
"unary operation expected operator, found {:?}",
rule

View File

@ -39,6 +39,7 @@ op_and = { "&&" }
op_not = { "!" }
op_neg = { "-" }
op_index = { "[" ~ expr ~ "]" }
op_len = { "len" }
op_binary = _{
op_add |
@ -57,7 +58,8 @@ op_binary = _{
}
op_unary = _{
op_neg |
op_not
op_not |
op_len
}
value = _{ call | boolean | number | variable | string | char | array | "(" ~ expr ~ ")" }

View File

@ -46,6 +46,7 @@ impl Display for BinaryOp {
pub enum UnaryOp {
Minus,
Not,
Len,
}
impl Display for UnaryOp {
@ -53,6 +54,7 @@ impl Display for UnaryOp {
match self {
UnaryOp::Minus => write!(f, "-"),
UnaryOp::Not => write!(f, "!"),
UnaryOp::Len => write!(f, "len "),
}
}
}

View File

@ -7,4 +7,10 @@ var b = [a[0] + 2, double(a[4])]; // indexing, expr
var c = a + b; // array concat
var d = a + b[1]; // value push
var e = [1, 2, 3];
e[1] = 4; // indexing, assignment
e[1] = 4; // indexing, assignment
var f = [1, 2, 3];
var l = len f; // len op
while (l > 0) {
l = l - 1;
f[l] = f[l] * 2;
}

View File

@ -1,10 +1,11 @@
var x = "hello ";
var y = "world";
var a = '!';
var z = x + y + a;
a = a * 3;
x[1] = 'a';
var b = x[2];
var z = x + y + a; // concat
a = a * 3; // repeat
x[1] = 'a'; // indexing
var b = x[2]; // indexing
var c = (y + ' ') * 3;
var d = "{\n\ttest: \"test\"\n}\n";
var e = '\'';
var d = "{\n\ttest: \"test\"\n}\n"; // escape
var e = '\''; // escape
var f = len z; // len op