Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: create TRUE and FALSE constants #47

Merged
merged 1 commit into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 24 additions & 35 deletions src/evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl<'a> Evaluator<'a> {

let mut result = match node.kind {
AstKind::Null => Value::null(self.arena),
AstKind::Bool(b) => Value::bool(self.arena, b),
AstKind::Bool(b) => Value::bool(b),
AstKind::String(ref s) => Value::string(self.arena, s),
AstKind::Number(n) => Value::number(self.arena, n),
AstKind::Block(ref exprs) => self.evaluate_block(exprs, input, frame)?,
Expand Down Expand Up @@ -450,29 +450,23 @@ impl<'a> Evaluator<'a> {
if lhs.is_number() && rhs.is_number() {
let lhs = lhs.as_f64();
let rhs = rhs.as_f64();
return Ok(Value::bool(
self.arena,
match op {
BinaryOp::LessThan => lhs < rhs,
BinaryOp::LessThanEqual => lhs <= rhs,
BinaryOp::GreaterThan => lhs > rhs,
BinaryOp::GreaterThanEqual => lhs >= rhs,
_ => unreachable!(),
},
));
return Ok(Value::bool(match op {
BinaryOp::LessThan => lhs < rhs,
BinaryOp::LessThanEqual => lhs <= rhs,
BinaryOp::GreaterThan => lhs > rhs,
BinaryOp::GreaterThanEqual => lhs >= rhs,
_ => unreachable!(),
}));
}

if let (Value::String(ref lhs), Value::String(ref rhs)) = (lhs, rhs) {
return Ok(Value::bool(
self.arena,
match op {
BinaryOp::LessThan => lhs < rhs,
BinaryOp::LessThanEqual => lhs <= rhs,
BinaryOp::GreaterThan => lhs > rhs,
BinaryOp::GreaterThanEqual => lhs >= rhs,
_ => unreachable!(),
},
));
return Ok(Value::bool(match op {
BinaryOp::LessThan => lhs < rhs,
BinaryOp::LessThanEqual => lhs <= rhs,
BinaryOp::GreaterThan => lhs > rhs,
BinaryOp::GreaterThanEqual => lhs >= rhs,
_ => unreachable!(),
}));
}

Err(Error::T2009BinaryOpMismatch(
Expand All @@ -487,17 +481,14 @@ impl<'a> Evaluator<'a> {
let rhs = self.evaluate(rhs_ast, input, frame)?;

if lhs.is_undefined() || rhs.is_undefined() {
return Ok(Value::bool(self.arena, false));
return Ok(Value::bool(false));
}

Ok(Value::bool(
self.arena,
match op {
BinaryOp::Equal => lhs == rhs,
BinaryOp::NotEqual => lhs != rhs,
_ => unreachable!(),
},
))
Ok(Value::bool(match op {
BinaryOp::Equal => lhs == rhs,
BinaryOp::NotEqual => lhs != rhs,
_ => unreachable!(),
}))
}

BinaryOp::Range => {
Expand Down Expand Up @@ -555,12 +546,10 @@ impl<'a> Evaluator<'a> {
}

BinaryOp::And => Ok(Value::bool(
self.arena,
lhs.is_truthy() && self.evaluate(rhs_ast, input, frame)?.is_truthy(),
)),

BinaryOp::Or => Ok(Value::bool(
self.arena,
lhs.is_truthy() || self.evaluate(rhs_ast, input, frame)?.is_truthy(),
)),

Expand Down Expand Up @@ -612,18 +601,18 @@ impl<'a> Evaluator<'a> {
let rhs = self.evaluate(rhs_ast, input, frame)?;

if lhs.is_undefined() || rhs.is_undefined() {
return Ok(Value::bool(self.arena, false));
return Ok(Value::bool(false));
}

let rhs = Value::wrap_in_array_if_needed(self.arena, rhs, ArrayFlags::empty());

for item in rhs.members() {
if item == lhs {
return Ok(Value::bool(self.arena, true));
return Ok(Value::bool(true));
}
}

Ok(Value::bool(self.arena, false))
Ok(Value::bool(false))
}

_ => unimplemented!("TODO: binary op not supported yet: {:#?}", *op),
Expand Down
33 changes: 15 additions & 18 deletions src/evaluator/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,30 +155,30 @@ pub fn fn_boolean<'a>(
let arg = args.first().copied().unwrap_or_else(Value::undefined);
Ok(match arg {
Value::Undefined => Value::undefined(),
Value::Null => Value::bool(context.arena, false),
Value::Bool(b) => Value::bool(context.arena, *b),
Value::Null => Value::bool(false),
Value::Bool(b) => Value::bool(*b),
Value::Number(n) => {
arg.is_valid_number()?;
Value::bool(context.arena, *n != 0.0)
Value::bool(*n != 0.0)
}
Value::String(ref str) => Value::bool(context.arena, !str.is_empty()),
Value::Object(ref obj) => Value::bool(context.arena, !obj.is_empty()),
Value::String(ref str) => Value::bool(!str.is_empty()),
Value::Object(ref obj) => Value::bool(!obj.is_empty()),
Value::Array { .. } => match arg.len() {
0 => Value::bool(context.arena, false),
0 => Value::bool(false),
1 => fn_boolean(context.clone(), &[arg.get_member(0)])?,
_ => {
for item in arg.members() {
if fn_boolean(context.clone(), &[item])?.as_bool() {
return Ok(Value::bool(context.arena, true));
return Ok(Value::bool(true));
}
}
Value::bool(context.arena, false)
Value::bool(false)
}
},
Value::Lambda { .. } | Value::NativeFn { .. } | Value::Transformer { .. } => {
Value::bool(context.arena, false)
Value::bool(false)
}
Value::Range(ref range) => Value::bool(context.arena, !range.is_empty()),
Value::Range(ref range) => Value::bool(!range.is_empty()),
})
}

Expand Down Expand Up @@ -420,15 +420,15 @@ pub fn fn_string<'a>(
}

pub fn fn_not<'a>(
context: FunctionContext<'a, '_>,
_context: FunctionContext<'a, '_>,
args: &[&'a Value<'a>],
) -> Result<&'a Value<'a>> {
let arg = args.first().copied().unwrap_or_else(Value::undefined);

Ok(if arg.is_undefined() {
Value::undefined()
} else {
Value::bool(context.arena, !arg.is_truthy())
Value::bool(!arg.is_truthy())
})
}

Expand Down Expand Up @@ -562,10 +562,7 @@ pub fn fn_contains<'a>(
let str_value = str_value.as_str();
let token_value = token_value.as_str();

Ok(Value::bool(
context.arena,
str_value.contains(&token_value.to_string()),
))
Ok(Value::bool(str_value.contains(&token_value.to_string())))
}

pub fn fn_replace<'a>(
Expand Down Expand Up @@ -871,8 +868,8 @@ pub fn fn_exists<'a>(
let arg = args.first().copied().unwrap_or_else(Value::undefined);

match arg {
Value::Undefined => Ok(Value::bool(context.arena, false)),
_ => Ok(Value::bool(context.arena, true)),
Value::Undefined => Ok(Value::bool(false)),
_ => Ok(Value::bool(true)),
}
}

Expand Down
17 changes: 10 additions & 7 deletions src/evaluator/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ bitflags! {
}

pub const UNDEFINED: Value = Value::Undefined;
pub const TRUE: Value = Value::Bool(true);
pub const FALSE: Value = Value::Bool(false);

/// The core value type for input, output and evaluation. There's a lot of lifetimes here to avoid
/// cloning any part of the input that should be kept in the output, avoiding heap allocations for
Expand Down Expand Up @@ -79,8 +81,12 @@ impl<'a> Value<'a> {
arena.alloc(Value::Null)
}

pub fn bool(arena: &Bump, value: bool) -> &mut Value {
arena.alloc(Value::Bool(value))
pub fn bool(value: bool) -> &'a Value<'a> {
if value {
unsafe { std::mem::transmute::<&Value<'static>, &'a Value<'a>>(&TRUE) }
} else {
unsafe { std::mem::transmute::<&Value<'static>, &'a Value<'a>>(&FALSE) }
}
}

pub fn number(arena: &Bump, value: impl Into<f64>) -> &mut Value {
Expand Down Expand Up @@ -496,11 +502,8 @@ impl<'a> Value<'a> {
Self::Undefined => arena.alloc(Value::Undefined),
Self::Null => Value::null(arena),
Self::Number(n) => Value::number(arena, *n),
Self::Bool(b) => Value::bool(arena, *b),
// TODO: clean up
Self::String(s) => {
arena.alloc(Value::String(BumpString::from_str_in(s.as_str(), arena)))
}
Self::Bool(b) => arena.alloc(Value::Bool(*b)),
Self::String(s) => arena.alloc(Value::String(s.clone())),
Self::Array(a, f) => Value::array_from(arena, a.clone(), *f),
Self::Object(o) => Value::object_from(o, arena),
Self::Lambda { ast, input, frame } => Value::lambda(arena, ast, input, frame.clone()),
Expand Down
6 changes: 3 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl<'a> JsonAta<'a> {
fn json_value_to_value(&self, json_value: &serde_json::Value) -> &'a mut Value<'a> {
return match json_value {
serde_json::Value::Null => Value::null(self.arena),
serde_json::Value::Bool(b) => Value::bool(self.arena, *b),
serde_json::Value::Bool(b) => self.arena.alloc(Value::Bool(*b)),
serde_json::Value::Number(n) => Value::number(self.arena, n.as_f64().unwrap()),
serde_json::Value::String(s) => Value::string(self.arena, s),

Expand Down Expand Up @@ -219,9 +219,9 @@ mod tests {
fn register_function_filter_even() {
let arena = Bump::new();
let jsonata = JsonAta::new("$filter([1,4,9,16], $even)", &arena).unwrap();
jsonata.register_function("even", 1, |ctx, args| {
jsonata.register_function("even", 1, |_ctx, args| {
let num = &args[0];
return Ok(Value::bool(ctx.arena, (num.as_f64()) % 2.0 == 0.0));
return Ok(Value::bool((num.as_f64()) % 2.0 == 0.0));
});

let result = jsonata.evaluate(Some(r#"anything"#), None);
Expand Down