Skip to content
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
110 changes: 65 additions & 45 deletions src/languages/rego/compiler/destructuring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::compiler::destructuring_planner::plans::{
AssignmentPlan, BindingPlan, DestructuringPlan, WildcardSide,
};
use crate::lexer::Span;
use crate::rvm::instructions::Instruction;
use crate::rvm::instructions::{GuardMode, Instruction};
use crate::value::Value;
use anyhow::{bail, Result};

Expand Down Expand Up @@ -91,19 +91,6 @@ impl<'a> Compiler<'a> {
AssignmentPlan::EqualityCheck { lhs_expr, rhs_expr } => {
let lhs_reg = self.compile_rego_expr_with_span(lhs_expr, lhs_expr.span(), false)?;
let rhs_reg = self.compile_rego_expr_with_span(rhs_expr, rhs_expr.span(), false)?;
if !self.soft_assert_mode {
// AssertEq handles the equality assertion inline; the returned
// register is not used as a boolean by the caller — it is the
// expression's "result register" for potential downstream use.
self.emit_instruction(
Instruction::AssertEq {
left: lhs_reg,
right: rhs_reg,
},
span,
);
return Ok(lhs_reg);
}
let dest = self.alloc_register();
self.emit_instruction(
Instruction::Eq {
Expand All @@ -113,6 +100,15 @@ impl<'a> Compiler<'a> {
},
span,
);
if !self.soft_assert_mode {
self.emit_instruction(
Instruction::Guard {
register: dest,
mode: GuardMode::Condition,
},
span,
);
}
Ok(dest)
}
AssignmentPlan::WildcardMatch {
Expand All @@ -125,7 +121,10 @@ impl<'a> Compiler<'a> {
let rhs_reg =
self.compile_rego_expr_with_span(rhs_expr, rhs_expr.span(), false)?;
self.emit_instruction(
Instruction::AssertNotUndefined { register: rhs_reg },
Instruction::Guard {
register: rhs_reg,
mode: GuardMode::NotUndefined,
},
span,
);
Ok(self.load_bool_literal(true, span))
Expand All @@ -134,7 +133,10 @@ impl<'a> Compiler<'a> {
let lhs_reg =
self.compile_rego_expr_with_span(lhs_expr, lhs_expr.span(), false)?;
self.emit_instruction(
Instruction::AssertNotUndefined { register: lhs_reg },
Instruction::Guard {
register: lhs_reg,
mode: GuardMode::NotUndefined,
},
span,
);
Ok(self.load_bool_literal(true, span))
Expand Down Expand Up @@ -206,44 +208,44 @@ impl<'a> Compiler<'a> {
DestructuringPlan::EqualityExpr(expected_expr) => {
let expected_reg =
self.compile_rego_expr_with_span(expected_expr, expected_expr.span(), false)?;
let cmp_reg = self.alloc_register();
self.emit_instruction(
Instruction::Eq {
dest: cmp_reg,
left: value_register,
right: expected_reg,
},
span,
);
if self.soft_assert_mode {
let cmp_reg = self.alloc_register();
self.emit_instruction(
Instruction::Eq {
dest: cmp_reg,
left: value_register,
right: expected_reg,
},
span,
);
return Ok(Some(cmp_reg));
}
self.emit_instruction(
Instruction::AssertEq {
left: value_register,
right: expected_reg,
Instruction::Guard {
register: cmp_reg,
mode: GuardMode::Condition,
},
span,
);
}
DestructuringPlan::EqualityValue(expected_value) => {
let expected_reg = self.load_literal_value(expected_value, span);
let cmp_reg = self.alloc_register();
self.emit_instruction(
Instruction::Eq {
dest: cmp_reg,
left: value_register,
right: expected_reg,
},
span,
);
if self.soft_assert_mode {
let cmp_reg = self.alloc_register();
self.emit_instruction(
Instruction::Eq {
dest: cmp_reg,
left: value_register,
right: expected_reg,
},
span,
);
return Ok(Some(cmp_reg));
}
self.emit_instruction(
Instruction::AssertEq {
left: value_register,
right: expected_reg,
Instruction::Guard {
register: cmp_reg,
mode: GuardMode::Condition,
},
span,
);
Expand All @@ -263,8 +265,9 @@ impl<'a> Compiler<'a> {
);
if context.require_defined_values() {
self.emit_instruction(
Instruction::AssertNotUndefined {
Instruction::Guard {
register: element_reg,
mode: GuardMode::NotUndefined,
},
span,
);
Expand All @@ -289,8 +292,9 @@ impl<'a> Compiler<'a> {
span,
);
self.emit_instruction(
Instruction::AssertNotUndefined {
Instruction::Guard {
register: field_reg,
mode: GuardMode::NotUndefined,
},
span,
);
Expand All @@ -310,8 +314,9 @@ impl<'a> Compiler<'a> {
span,
);
self.emit_instruction(
Instruction::AssertNotUndefined {
Instruction::Guard {
register: field_reg,
mode: GuardMode::NotUndefined,
},
span,
);
Expand Down Expand Up @@ -349,7 +354,13 @@ impl<'a> Compiler<'a> {
self.add_variable(var_name, dest);

if context.require_defined_values() {
self.emit_instruction(Instruction::AssertNotUndefined { register: dest }, span);
self.emit_instruction(
Instruction::Guard {
register: dest,
mode: GuardMode::NotUndefined,
},
span,
);
}

Ok(())
Expand Down Expand Up @@ -393,13 +404,22 @@ impl<'a> Compiler<'a> {
span,
);

let cmp_reg = self.alloc_register();
self.emit_instruction(
Instruction::AssertEq {
Instruction::Eq {
dest: cmp_reg,
left: actual_len_reg,
right: expected_len_reg,
},
span,
);
self.emit_instruction(
Instruction::Guard {
register: cmp_reg,
mode: GuardMode::Condition,
},
span,
);
Ok(())
}
}
11 changes: 7 additions & 4 deletions src/languages/rego/compiler/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use super::{Compiler, CompilerError, Register, Result};
use crate::ast::{Expr, ExprRef};
use crate::compiler::destructuring_planner::plans::BindingPlan;
use crate::lexer::Span;
use crate::rvm::instructions::GuardMode;
use crate::rvm::Instruction;
use crate::Value;
use alloc::{format, string::ToString};
Expand All @@ -32,8 +33,9 @@ impl<'a> Compiler<'a> {
let result_reg = reg;
if assert_condition {
self.emit_instruction(
Instruction::AssertCondition {
condition: result_reg,
Instruction::Guard {
register: result_reg,
mode: GuardMode::Condition,
},
span,
);
Expand Down Expand Up @@ -113,8 +115,9 @@ impl<'a> Compiler<'a> {

if assert_condition {
self.emit_instruction(
Instruction::AssertCondition {
condition: result_reg,
Instruction::Guard {
register: result_reg,
mode: GuardMode::Condition,
},
span,
);
Expand Down
18 changes: 17 additions & 1 deletion src/languages/rego/compiler/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

use super::{Compiler, CompilerError, ComprehensionType, ContextType, Result};
use crate::ast::{self, LiteralStmt, Query};
use crate::rvm::instructions::GuardMode;
use crate::rvm::program::RuleType;
use crate::rvm::Instruction;
use alloc::format;
Expand Down Expand Up @@ -242,7 +243,22 @@ impl<'a> Compiler<'a> {
compiler.compile_rego_expr_with_span(expr, expr.span(), false)
})?;

self.emit_instruction(Instruction::AssertNot { operand: expr_reg }, &stmt.span);
let negated_reg = self.alloc_register();
self.emit_instruction(
Instruction::Not {
dest: negated_reg,
operand: expr_reg,
},
&stmt.span,
);

self.emit_instruction(
Instruction::Guard {
register: negated_reg,
mode: GuardMode::Condition,
},
&stmt.span,
);
}
}
Ok(())
Expand Down
2 changes: 0 additions & 2 deletions src/languages/rego/compiler/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,14 +543,12 @@ impl<'a> Compiler<'a> {
// A definition has a known static value if every body (including
// else-branches) would produce the same literal.
let def_static_value = if bodies.is_empty() {
// No bodies — value comes from the head's value_expr.
let head_value = self
.context_stack
.last()
.and_then(|ctx| ctx.value_expr.clone());
Self::static_value_of_expr(&head_value)
} else {
// Replay the same value_expr resolution as the body loop.
let head_value = self
.context_stack
.last()
Expand Down
61 changes: 27 additions & 34 deletions src/rvm/instructions/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use alloc::format;
use alloc::string::String;
use alloc::vec::Vec;

use super::types::GuardMode;
use super::{Instruction, InstructionData, LiteralOrRegister};

impl Instruction {
Expand Down Expand Up @@ -65,32 +66,25 @@ impl Instruction {
)
},
),
Instruction::ObjectCreate { params_index } => {
instruction_data
.get_object_create_params(params_index)
.map_or_else(
|| format!("OBJECT_CREATE P({}) [INVALID INDEX]", params_index),
|params| {
let mut field_parts = Vec::new();

// Add literal key fields
for &(literal_idx, value_reg) in params.literal_key_field_pairs() {
field_parts.push(format!("L({}):R({})", literal_idx, value_reg));
}

// Add non-literal key fields
for &(key_reg, value_reg) in params.field_pairs() {
field_parts.push(format!("R({}):R({})", key_reg, value_reg));
}

let fields_str = field_parts.join(" ");
format!(
"OBJECT_CREATE R({}) L({}) [{}]",
params.dest, params.template_literal_idx, fields_str
)
},
)
}
Instruction::ObjectCreate { params_index } => instruction_data
.get_object_create_params(params_index)
.map_or_else(
|| format!("OBJECT_CREATE P({}) [INVALID INDEX]", params_index),
|params| {
let mut field_parts = Vec::new();
for &(literal_idx, value_reg) in params.literal_key_field_pairs() {
field_parts.push(format!("L({}):R({})", literal_idx, value_reg));
}
for &(key_reg, value_reg) in params.field_pairs() {
field_parts.push(format!("R({}):R({})", key_reg, value_reg));
}
let fields_str = field_parts.join(" ");
format!(
"OBJECT_CREATE R({}) L({}) [{}]",
params.dest, params.template_literal_idx, fields_str
)
},
),
Instruction::VirtualDataDocumentLookup { params_index } => instruction_data
.get_virtual_data_document_lookup_params(params_index)
.map_or_else(
Expand Down Expand Up @@ -245,14 +239,13 @@ impl core::fmt::Display for Instruction {
Instruction::AssertEq { left, right } => {
format!("ASSERT_EQ R({}) R({})", left, right)
}
Instruction::AssertNot { operand } => {
format!("ASSERT_NOT R({})", operand)
}
Instruction::AssertCondition { condition } => {
format!("ASSERT_CONDITION R({})", condition)
}
Instruction::AssertNotUndefined { register } => {
format!("ASSERT_NOT_UNDEFINED R({})", register)
Instruction::Guard { register, mode } => {
let name = match mode {
GuardMode::Not => "ASSERT_NOT",
GuardMode::Condition => "ASSERT_CONDITION",
GuardMode::NotUndefined => "ASSERT_NOT_UNDEFINED",
};
format!("{} R({})", name, register)
}
Instruction::LoopStart { params_index } => {
format!("LOOP_START P({})", params_index)
Expand Down
Loading
Loading