package com.xfestudio.xfeservermanager.core.trigger;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
/** Structural and budget validation for Trigger Program V2. */
public final class TriggerProgramValidator {
public static final int MAX_NODES = 4_096;
public static final int MAX_NESTING_DEPTH = 32;
public static final int MAX_CALL_DEPTH = 16;
public static final int MAX_LOOP_ITERATIONS = 10_000;
public static final int MAX_INSTRUCTIONS = 100_000;
private TriggerProgramValidator() { }
public static void validate(TriggerProgramV2 program) {
validate(program.events(), program.declarations(), program.functions(), program.statements());
}
static void validate(
List<TriggerProgramV2.EventBinding> events,
List<TriggerProgramV2.VariableDeclaration> declarations,
List<TriggerProgramV2.FunctionDeclaration> functionDeclarations,
List<TriggerProgramV2.Statement> rootStatements) {
Counter counter = new Counter();
Set<UUID> ids = new HashSet<>();
Set<String> names = new HashSet<>();
for (TriggerProgramV2.EventBinding event : events) add(event.nodeId(), ids, counter);
for (TriggerProgramV2.VariableDeclaration declaration : declarations) {
add(declaration.nodeId(), ids, counter);
if (!names.add(declaration.name())) {
throw new IllegalArgumentException("duplicate declaration: " + declaration.name());
}
expression(declaration.initialValue(), 1, ids, counter);
}
Set<String> functions = new HashSet<>();
for (TriggerProgramV2.FunctionDeclaration function : functionDeclarations) {
add(function.nodeId(), ids, counter);
if (!functions.add(function.name())) {
throw new IllegalArgumentException("duplicate function: " + function.name());
}
Set<String> parameters = new HashSet<>();
function.parameters().forEach(parameter -> {
if (!parameters.add(parameter.name())) {
throw new IllegalArgumentException("duplicate parameter in " + function.name() + ": " + parameter.name());
}
});
for (TriggerProgramV2.VariableDeclaration local : function.locals()) {
add(local.nodeId(), ids, counter);
expression(local.initialValue(), 1, ids, counter);
}
statements(function.statements(), 1, ids, counter);
}
statements(rootStatements, 1, ids, counter);
TriggerProgramTypeChecker.validate(declarations, functionDeclarations, rootStatements);
}
private static void statements(
List<TriggerProgramV2.Statement> statements, int depth, Set<UUID> ids, Counter counter) {
if (depth > MAX_NESTING_DEPTH) {
throw new IllegalArgumentException("trigger nesting exceeds " + MAX_NESTING_DEPTH);
}
for (TriggerProgramV2.Statement statement : statements) {
add(statement.nodeId(), ids, counter);
expression(statement.expression(), depth, ids, counter);
statement.inputs().values().forEach(value -> expression(value, depth, ids, counter));
statements(statement.statements(), depth + 1, ids, counter);
statements(statement.elseStatements(), depth + 1, ids, counter);
for (TriggerProgramV2.SwitchCase branch : statement.cases()) {
add(branch.nodeId(), ids, counter);
expression(branch.match(), depth + 1, ids, counter);
statements(branch.statements(), depth + 1, ids, counter);
}
}
}
private static void expression(
TriggerExpression expression, int depth, Set<UUID> ids, Counter counter) {
if (expression == null) return;
if (depth > MAX_NESTING_DEPTH) {
throw new IllegalArgumentException("expression nesting exceeds " + MAX_NESTING_DEPTH);
}
add(expression.nodeId(), ids, counter);
for (TriggerExpression argument : expression.arguments()) {
expression(argument, depth + 1, ids, counter);
}
}
private static void add(UUID id, Set<UUID> ids, Counter counter) {
if (!ids.add(id)) throw new IllegalArgumentException("duplicate trigger nodeId: " + id);
if (++counter.value > MAX_NODES) {
throw new IllegalArgumentException("trigger program exceeds " + MAX_NODES + " nodes");
}
}
private static final class Counter { private int value; }
}
package com.xfestudio.xfeservermanager.core.trigger;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
/** Structural and budget validation for Trigger Program V2. */
public final class TriggerProgramValidator {
public static final int MAX_NODES = 4_096;
public static final int MAX_NESTING_DEPTH = 32;
public static final int MAX_CALL_DEPTH = 16;
public static final int MAX_LOOP_ITERATIONS = 10_000;
public static final int MAX_INSTRUCTIONS = 100_000;
private TriggerProgramValidator() { }
public static void validate(TriggerProgramV2 program) {
validate(program.events(), program.declarations(), program.functions(), program.statements());
}
static void validate(
List<TriggerProgramV2.EventBinding> events,
List<TriggerProgramV2.VariableDeclaration> declarations,
List<TriggerProgramV2.FunctionDeclaration> functionDeclarations,
List<TriggerProgramV2.Statement> rootStatements) {
Counter counter = new Counter();
Set<UUID> ids = new HashSet<>();
Set<String> names = new HashSet<>();
for (TriggerProgramV2.EventBinding event : events) add(event.nodeId(), ids, counter);
for (TriggerProgramV2.VariableDeclaration declaration : declarations) {
add(declaration.nodeId(), ids, counter);
if (!names.add(declaration.name())) {
throw new IllegalArgumentException("duplicate declaration: " + declaration.name());
}
expression(declaration.initialValue(), 1, ids, counter);
}
Set<String> functions = new HashSet<>();
for (TriggerProgramV2.FunctionDeclaration function : functionDeclarations) {
add(function.nodeId(), ids, counter);
if (!functions.add(function.name())) {
throw new IllegalArgumentException("duplicate function: " + function.name());
}
Set<String> parameters = new HashSet<>();
function.parameters().forEach(parameter -> {
if (!parameters.add(parameter.name())) {
throw new IllegalArgumentException("duplicate parameter in " + function.name() + ": " + parameter.name());
}
});
for (TriggerProgramV2.VariableDeclaration local : function.locals()) {
add(local.nodeId(), ids, counter);
expression(local.initialValue(), 1, ids, counter);
}
statements(function.statements(), 1, ids, counter);
}
statements(rootStatements, 1, ids, counter);
TriggerProgramTypeChecker.validate(declarations, functionDeclarations, rootStatements);
}
private static void statements(
List<TriggerProgramV2.Statement> statements, int depth, Set<UUID> ids, Counter counter) {
if (depth > MAX_NESTING_DEPTH) {
throw new IllegalArgumentException("trigger nesting exceeds " + MAX_NESTING_DEPTH);
}
for (TriggerProgramV2.Statement statement : statements) {
add(statement.nodeId(), ids, counter);
expression(statement.expression(), depth, ids, counter);
statement.inputs().values().forEach(value -> expression(value, depth, ids, counter));
statements(statement.statements(), depth + 1, ids, counter);
statements(statement.elseStatements(), depth + 1, ids, counter);
for (TriggerProgramV2.SwitchCase branch : statement.cases()) {
add(branch.nodeId(), ids, counter);
expression(branch.match(), depth + 1, ids, counter);
statements(branch.statements(), depth + 1, ids, counter);
}
}
}
private static void expression(
TriggerExpression expression, int depth, Set<UUID> ids, Counter counter) {
if (expression == null) return;
if (depth > MAX_NESTING_DEPTH) {
throw new IllegalArgumentException("expression nesting exceeds " + MAX_NESTING_DEPTH);
}
add(expression.nodeId(), ids, counter);
for (TriggerExpression argument : expression.arguments()) {
expression(argument, depth + 1, ids, counter);
}
}
private static void add(UUID id, Set<UUID> ids, Counter counter) {
if (!ids.add(id)) throw new IllegalArgumentException("duplicate trigger nodeId: " + id);
if (++counter.value > MAX_NODES) {
throw new IllegalArgumentException("trigger program exceeds " + MAX_NODES + " nodes");
}
}
private static final class Counter { private int value; }
}