feat(len): len operator implementation
parent
967891fb7b
commit
7567312055
|
@ -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
|
||||
|
|
|
@ -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()?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ~ ")" }
|
||||
|
|
|
@ -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 "),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue