Skip to content

Commit

Permalink
wip: add block comparison between sample definition and its serializa…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
KannarFr committed Apr 9, 2024
1 parent 903ebea commit e7a2e46
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 22 deletions.
8 changes: 7 additions & 1 deletion src/main/java/org/biscuitsec/biscuit/token/Block.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,16 @@ public String print(SymbolTable symbol_table) {
s.append(this.symbols.symbols);
s.append("\n\t\tcontext: ");
s.append(this.context);
s.append("\n\t\tscopes: [");
for (Scope scope : this.scopes) {
s.append("\n\t\t\t");
s.append(symbol_table.print_scope(scope));
}
if(this.externalKey.isDefined()) {
s.append("\n\t\texternal key: ");
s.append(this.externalKey.get().toString());
}
s.append("\n\t\tfacts: [");
s.append("\n\t\t]\n\t\tfacts: [");
for (Fact f : this.facts) {
s.append("\n\t\t\t");
s.append(symbol_table.print_fact(f));
Expand Down Expand Up @@ -208,6 +213,7 @@ static public Either<Error.FormatError, Block> deserialize(Schema.Block b, Optio
}

ArrayList<Scope> scopes = new ArrayList<>();
System.out.println(b.getScopeList());
for (Schema.Scope scope: b.getScopeList()) {
Either<Error.FormatError, Scope> res = Scope.deserialize(scope);
if(res.isLeft()) {
Expand Down
2 changes: 0 additions & 2 deletions src/main/java/org/biscuitsec/biscuit/token/builder/Block.java
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,6 @@ public org.biscuitsec.biscuit.token.Block build() {
publicKeys.add(this.symbols.publicKeys().get(i));
}

publicKeys.addAll(this.publicKeys);

SchemaVersion schemaVersion = new SchemaVersion(this.facts, this.rules, this.checks, this.scopes);

return new org.biscuitsec.biscuit.token.Block(symbols, this.context, this.facts, this.rules, this.checks,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,9 @@ public static Either<Error, Tuple2<String, Expression.Op>> binary_op6(String s)
}

public static Either<Error, Tuple2<String, Expression.Op>> binary_op7(String s) {
if(s.startsWith("intersection")) {
return Either.right(new Tuple2<>(s.substring(12), Expression.Op.Intersection));
}
if(s.startsWith("contains")) {
return Either.right(new Tuple2<>(s.substring(8), Expression.Op.Contains));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
import java.util.function.Function;

public class Parser {
public static Either<Map<Integer, List<Error>>, Block> datalog(long index, SymbolTable baseSymbols, String s) {
return datalog(index, baseSymbols, null, s);
}

/**
* Takes a datalog string with <code>\n</code> as datalog line separator. It tries to parse
* each line using fact, rule, check and scope sequentially.
Expand All @@ -25,24 +29,48 @@ public class Parser {
*
* @param index block index
* @param baseSymbols symbols table
* @param blockSymbols block's custom symbols table (added to baseSymbols)
* @param s datalog string to parse
* @return Either<Map<Integer, List<Error>>, Block>
*/
public static Either<Map<Integer, List<Error>>, Block> datalog(long index, SymbolTable baseSymbols, String s) {
public static Either<Map<Integer, List<Error>>, Block> datalog(long index, SymbolTable baseSymbols, SymbolTable blockSymbols, String s) {
Block blockBuilder = new Block(index, baseSymbols);

// empty block code
if (s.isEmpty()) {
return Either.right(blockBuilder);
}

if (blockSymbols != null) {
blockSymbols.symbols.forEach(blockBuilder::addSymbol);
}

Map<Integer, List<Error>> errors = new HashMap<>();

Stream.of(s.split("\n")).zipWithIndex().forEach(indexedLine -> {
s = removeComments(s);
s = s.replace("\n", "");
s = s.replace("\\\"","\"");
s = s.strip();
String[] codeLines = s.split(";");
codeLines = Arrays.stream(codeLines)
.filter(codeLine -> !codeLine.isEmpty())
.map(String::strip)
.toArray(String[]::new);

Stream.of(codeLines).zipWithIndex().forEach(indexedLine -> {
Integer lineNumber = indexedLine._2;
String codeLine = indexedLine._1;
System.out.println("NEW CODE LINE");
System.out.println(codeLine);
List<Error> lineErrors = new ArrayList<>();

fact(codeLine).bimap(lineErrors::add, r -> r._2).map(blockBuilder::add_fact);
rule(codeLine).bimap(lineErrors::add, r -> r._2).map(blockBuilder::add_rule);
check(codeLine).bimap(lineErrors::add, r -> r._2).map(blockBuilder::add_check);
scope(codeLine).bimap(lineErrors::add, r -> r._2).map(blockBuilder::add_scope);
rule(codeLine).bimap(lineErrors::add, r -> r._2).forEach(blockBuilder::add_rule);
scope(codeLine).bimap(lineErrors::add, r -> r._2).forEach(blockBuilder::add_scope);
fact(codeLine).bimap(lineErrors::add, r -> r._2).forEach(blockBuilder::add_fact);
check(codeLine).bimap(lineErrors::add, r -> r._2).forEach(blockBuilder::add_check);

if (lineErrors.size() > 3) {
lineErrors.forEach(System.out::println);
errors.put(lineNumber, lineErrors);
}
});
Expand Down Expand Up @@ -709,4 +737,43 @@ public static Tuple2<String, String> take_while(String s, Function<Character, Bo

return new Tuple2<>(s.substring(0, index), s.substring(index));
}

public static String removeComments(String str) {
StringBuilder result = new StringBuilder();
boolean inMultilineComment = false;
boolean inSingleLineComment = false;

for (int i = 0; i < str.length(); i++) {
// Check for start of multiline comment if not already in a single-line comment
if (!inSingleLineComment && i < str.length() - 1 && str.charAt(i) == '/' && str.charAt(i + 1) == '*') {
inMultilineComment = true;
i++; // Skip next character to avoid false ending
}
// Check for end of multiline comment
else if (inMultilineComment && i < str.length() - 1 && str.charAt(i) == '*' && str.charAt(i + 1) == '/') {
inMultilineComment = false;
i++; // Skip next character to move past the comment end
continue; // Skip adding the comment end to the result
}
// Check for start of single-line comment if not already in a multiline comment
else if (!inMultilineComment && i < str.length() - 1 && str.charAt(i) == '/' && str.charAt(i + 1) == '/') {
inSingleLineComment = true;
i++; // Skip next character
continue; // Skip adding the start of single-line comment
}
// Check for end of line, marking end of single-line comment
else if (inSingleLineComment && (str.charAt(i) == '\n')) {
inSingleLineComment = false;
// Optionally, add the newline character to the result to preserve line structure
result.append(str.charAt(i));
continue; // Move to the next character
}
// If not in any comment, append the current character
if (!inMultilineComment && !inSingleLineComment) {
result.append(str.charAt(i));
}
}

return result.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,23 @@ void testRuleWithExpressionOrdering() {
res);
}

@Test
void expressionIntersectionAndContainsTest() {
Either<Error, Tuple2<String, Expression>> res =
Parser.expression("[1, 2, 3].intersection([1, 2]).contains(1)");

assertEquals(Either.right(new Tuple2<>("",
new Expression.Binary(
Expression.Op.Contains,
new Expression.Binary(
Expression.Op.Intersection,
new Expression.Value(Utils.set(new HashSet<>(Arrays.asList(Utils.integer(1), Utils.integer(2), Utils.integer(3))))),
new Expression.Value(Utils.set(new HashSet<>(Arrays.asList(Utils.integer(1), Utils.integer(2)))))
),
new Expression.Value(Utils.integer(1))
))), res);
}

@Test
void ruleWithFreeExpressionVariables() {
Either<Error, Tuple2<String, Rule>> res =
Expand Down Expand Up @@ -366,11 +383,11 @@ void testParens() throws org.biscuitsec.biscuit.error.Error.Execution {
void testDatalogSucceeds() throws org.biscuitsec.biscuit.error.Error.Parser {
SymbolTable symbols = Biscuit.default_symbol_table();

String l1 = "fact1(1)";
String l1 = "fact1(1, 2)";
String l2 = "fact2(\"2\")";
String l3 = "rule1(2) <- fact2(\"2\")";
String l4 = "check if rule1(2)";
String toParse = String.join("\n", Arrays.asList(l1, l2, l3, l4));
String toParse = String.join(";", Arrays.asList(l1, l2, l3, l4));

Either<Map<Integer, List<Error>>, Block> output = Parser.datalog(1, symbols, toParse);
assertTrue(output.isRight());
Expand All @@ -392,9 +409,28 @@ void testDatalogFailed() {

String l1 = "fact(1)";
String l2 = "check fact(1)"; // typo missing "if"
String toParse = String.join("\n", Arrays.asList(l1, l2));
String toParse = String.join(";", Arrays.asList(l1, l2));

Either<Map<Integer, List<Error>>, Block> output = Parser.datalog(1, symbols, toParse);
assertTrue(output.isLeft());
}

@Test
void testDatalogRemoveComment() throws org.biscuitsec.biscuit.error.Error.Parser {
SymbolTable symbols = Biscuit.default_symbol_table();

String l0 = "// test comment";
String l1 = "fact1(1, 2);";
String l2 = "fact2(\"2\");";
String l3 = "rule1(2) <- fact2(\"2\");";
String l4 = "// another comment";
String l5 = "/* test multiline";
String l6 = "comment */ check if rule1(2);";
String l7 = " /* another multiline";
String l8 = "comment */";
String toParse = String.join("", Arrays.asList(l0, l1, l2, l3, l4, l5, l6, l7, l8));

Either<Map<Integer, List<Error>>, Block> output = Parser.datalog(1, symbols, toParse);
assertTrue(output.isRight());
}
}
24 changes: 24 additions & 0 deletions src/test/java/org/biscuitsec/biscuit/datalog/ExpressionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;

public class ExpressionTest {

Expand Down Expand Up @@ -114,4 +115,27 @@ public void testNegativeContainsStr() throws Error.Execution {
e.evaluate(new HashMap<>(), new TemporarySymbolTable(symbols))
);
}

@Test
public void testIntersectionAndContains() throws Error.Execution {
SymbolTable symbols = new SymbolTable();

Expression e = new Expression(new ArrayList<Op>(Arrays.asList(
new Op.Value(new Term.Set(new HashSet<>(Arrays.asList(new Term.Integer(1), new Term.Integer(2), new Term.Integer(3))))),
new Op.Value(new Term.Set(new HashSet<>(Arrays.asList(new Term.Integer(1), new Term.Integer(2))))),
new Op.Binary(Op.BinaryOp.Intersection),
new Op.Value(new Term.Integer(1)),
new Op.Binary(Op.BinaryOp.Contains)
)));

assertEquals(
"[1, 2, 3].intersection([1, 2]).contains(1)",
e.print(symbols).get()
);

assertEquals(
new Term.Bool(true),
e.evaluate(new HashMap<>(), new TemporarySymbolTable(symbols))
);
}
}
Loading

0 comments on commit e7a2e46

Please sign in to comment.