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
27 changes: 27 additions & 0 deletions ports/javascript/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,14 @@ class Blaze {
if (match) entry.skip = true;
}
}

checkpoint() {
return this.evaluated.length;
}

rewind(checkpoint) {
this.evaluated.length = checkpoint;
Comment thread
jviotti marked this conversation as resolved.
}
}

function evaluateInstructionFast(instruction, instance, depth, template, evaluator) {
Expand Down Expand Up @@ -1646,16 +1654,21 @@ function LogicalOr(instruction, instance, depth, template, evaluator) {
let result = false;
if (exhaustive) {
for (let index = 0; index < children.length; index++) {
const checkpoint = evaluator.trackMode ? evaluator.checkpoint() : 0;
if (evaluateInstruction(children[index], target, depth + 1, template, evaluator)) {
result = true;
} else if (evaluator.trackMode) {
evaluator.rewind(checkpoint);
}
}
} else {
for (let index = 0; index < children.length; index++) {
const checkpoint = evaluator.trackMode ? evaluator.checkpoint() : 0;
if (evaluateInstruction(children[index], target, depth + 1, template, evaluator)) {
result = true;
break;
}
if (evaluator.trackMode) evaluator.rewind(checkpoint);
}
}
if (evaluator.callbackMode) evaluator.callbackPop(instruction, result);
Expand Down Expand Up @@ -1687,13 +1700,16 @@ function LogicalXor(instruction, instance, depth, template, evaluator) {
let hasMatched = false;
if (children) {
for (let index = 0; index < children.length; index++) {
const checkpoint = evaluator.trackMode ? evaluator.checkpoint() : 0;
if (evaluateInstruction(children[index], target, depth + 1, template, evaluator)) {
if (hasMatched) {
result = false;
if (!exhaustive) break;
} else {
hasMatched = true;
}
} else if (evaluator.trackMode) {
evaluator.rewind(checkpoint);
}
}
}
Expand All @@ -1712,13 +1728,15 @@ function LogicalCondition(instruction, instance, depth, template, evaluator) {

const target = resolveInstance(instance, instruction[2]);

const checkpoint = evaluator.trackMode ? evaluator.checkpoint() : 0;
let conditionResult = true;
for (let cursor = 0; cursor < thenStart; cursor++) {
if (!evaluateInstruction(children[cursor], target, depth + 1, template, evaluator)) {
conditionResult = false;
break;
}
}
if (!conditionResult && evaluator.trackMode) evaluator.rewind(checkpoint);

let consequenceStart;
let consequenceEnd;
Expand Down Expand Up @@ -2818,11 +2836,15 @@ function LogicalOr_fast(instruction, instance, depth, template, evaluator) {
let result = false;
if (exhaustive) {
for (let index = 0; index < children.length; index++) {
const checkpoint = evaluator.trackMode ? evaluator.checkpoint() : 0;
if (evaluateInstruction(children[index], target, depth + 1, template, evaluator)) result = true;
else if (evaluator.trackMode) evaluator.rewind(checkpoint);
}
} else {
for (let index = 0; index < children.length; index++) {
const checkpoint = evaluator.trackMode ? evaluator.checkpoint() : 0;
if (evaluateInstruction(children[index], target, depth + 1, template, evaluator)) return true;
if (evaluator.trackMode) evaluator.rewind(checkpoint);
}
}
return result;
Expand Down Expand Up @@ -2867,13 +2889,16 @@ function LogicalXor_fast(instruction, instance, depth, template, evaluator) {
let hasMatched = false;
if (children) {
for (let index = 0; index < children.length; index++) {
const checkpoint = evaluator.trackMode ? evaluator.checkpoint() : 0;
if (evaluateInstruction(children[index], target, depth + 1, template, evaluator)) {
if (hasMatched) {
result = false;
if (!exhaustive) break;
} else {
hasMatched = true;
}
} else if (evaluator.trackMode) {
evaluator.rewind(checkpoint);
}
}
}
Expand Down Expand Up @@ -2972,13 +2997,15 @@ function LogicalCondition_fast(instruction, instance, depth, template, evaluator
const childrenSize = children ? children.length : 0;
const relInstance = instruction[2];
const target = relInstance.length === 0 ? instance : resolveInstance(instance, relInstance);
const checkpoint = evaluator.trackMode ? evaluator.checkpoint() : 0;
let conditionResult = true;
for (let cursor = 0; cursor < thenStart; cursor++) {
if (!evaluateInstruction(children[cursor], target, depth + 1, template, evaluator)) {
conditionResult = false;
break;
}
}
if (!conditionResult && evaluator.trackMode) evaluator.rewind(checkpoint);
let consequenceStart;
let consequenceEnd;
if (conditionResult) {
Expand Down
9 changes: 8 additions & 1 deletion ports/javascript/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions src/evaluator/include/sourcemeta/blaze/evaluator.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,20 @@ class SOURCEMETA_BLAZE_EVALUATOR_EXPORT Evaluator {
}
}

// A subschema that ends up failing must not contribute any of the marks it
// made along the way, so a disjunction records the length here before each
// branch and truncates back to it when the branch does not hold. Marks are
// only ever appended, never inserted earlier, so everything a branch adds
// sits past the recorded length and nothing from outside it can be lost
[[nodiscard]] auto checkpoint() const -> std::size_t {
return this->evaluated_.size();
}

auto rewind(const std::size_t checkpoint) -> void {
assert(checkpoint <= this->evaluated_.size());
this->evaluated_.resize(checkpoint);
}

#if defined(_MSC_VER)
#pragma warning(disable : 4251 4275)
#endif
Expand Down
45 changes: 45 additions & 0 deletions src/evaluator/include/sourcemeta/blaze/evaluator_dispatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -1214,16 +1214,37 @@ INSTRUCTION_HANDLER(LogicalOr) {
// This boolean value controls whether we should be exhaustive
if (value) {
for (const auto &child : instruction.children) {
// A branch that does not hold contributes nothing, including any
// evaluation it marked before failing. Only a schema that tracks
// evaluation can ever observe those marks
[[maybe_unused]] std::size_t checkpoint{0};
if constexpr (Track) {
checkpoint = context.evaluator->checkpoint();
}

if (EVALUATE_RECURSE(child, target)) {
result = true;
} else {
if constexpr (Track) {
context.evaluator->rewind(checkpoint);
}
}
}
} else {
for (const auto &child : instruction.children) {
[[maybe_unused]] std::size_t checkpoint{0};
if constexpr (Track) {
checkpoint = context.evaluator->checkpoint();
}

if (EVALUATE_RECURSE(child, target)) {
result = true;
break;
}

if constexpr (Track) {
context.evaluator->rewind(checkpoint);
}
}
}

Expand Down Expand Up @@ -1308,6 +1329,13 @@ INSTRUCTION_HANDLER(LogicalXor) {
resolve_instance(instance, instruction.relative_instance_location)};
const auto value{assume_value_copy<ValueBoolean>(instruction.value)};
for (const auto &child : instruction.children) {
// A branch that does not hold contributes nothing, including any
// evaluation it marked before failing
[[maybe_unused]] std::size_t checkpoint{0};
if constexpr (Track) {
checkpoint = context.evaluator->checkpoint();
}

if (EVALUATE_RECURSE(child, target)) {
if (has_matched) [[unlikely]] {
result = false;
Expand All @@ -1318,6 +1346,10 @@ INSTRUCTION_HANDLER(LogicalXor) {
} else {
has_matched = true;
}
} else {
if constexpr (Track) {
context.evaluator->rewind(checkpoint);
}
}
}

Expand All @@ -1341,13 +1373,26 @@ INSTRUCTION_HANDLER(LogicalCondition) {
const auto &target{
resolve_instance(instance, instruction.relative_instance_location)};

// A condition that holds does contribute the evaluation it marked, but one
// that does not hold contributes nothing at all
[[maybe_unused]] std::size_t checkpoint{0};
if constexpr (Track) {
checkpoint = context.evaluator->checkpoint();
}

for (std::size_t cursor = 0; cursor < value.first; cursor++) {
if (!EVALUATE_RECURSE(instruction.children[cursor], target)) {
result = false;
break;
}
}

if (!result) {
if constexpr (Track) {
context.evaluator->rewind(checkpoint);
}
}

// On a passing condition the then branch runs, otherwise the else branch,
// which is absent when it starts at zero
std::size_t consequence_start;
Expand Down
Loading
Loading