Skip to content

Commit

Permalink
parser fixes and API usability changes (#94)
Browse files Browse the repository at this point in the history
Co-authored-by: kannar <[email protected]>
Co-authored-by: Aurélien Mino <[email protected]>
  • Loading branch information
3 people authored May 1, 2024
1 parent c2836d8 commit 3dd2f8a
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 62 deletions.
5 changes: 5 additions & 0 deletions src/main/java/org/biscuitsec/biscuit/datalog/SymbolTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,11 @@ public SymbolTable(SymbolTable s) {
publicKeys.addAll(s.publicKeys);
}

public SymbolTable(List<String> symbols) {
this.symbols = new ArrayList<>(symbols);
this.publicKeys = new ArrayList<>();
}

public SymbolTable(List<String> symbols, List<PublicKey> publicKeys) {
this.symbols = new ArrayList<>();
this.symbols.addAll(symbols);
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/org/biscuitsec/biscuit/token/Block.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@ public String print(SymbolTable symbol_table) {
s.append("\n\t\texternal key: ");
s.append(this.externalKey.get().toString());
}
s.append("\n\t\tfacts: [");
s.append("\n\t\tscopes: [");
for (Scope scope : this.scopes) {
s.append("\n\t\t\t");
s.append(symbol_table.print_scope(scope));
}
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
31 changes: 30 additions & 1 deletion src/main/java/org/biscuitsec/biscuit/token/builder/Block.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public class Block {
List<Rule> rules;
List<Check> checks;
List<Scope> scopes;
List<PublicKey> publicKeys;
Option<PublicKey> externalKey;

public Block(long index, SymbolTable base_symbols) {
this.index = index;
Expand All @@ -43,6 +45,33 @@ public Block(long index, SymbolTable base_symbols) {
this.rules = new ArrayList<>();
this.checks = new ArrayList<>();
this.scopes = new ArrayList<>();
this.publicKeys = new ArrayList<>();
this.externalKey = Option.none();
}

public Block setExternalKey(Option<PublicKey> externalKey) {
this.externalKey = externalKey;
return this;
}

public Block addPublicKey(PublicKey publicKey) {
this.publicKeys.add(publicKey);
return this;
}

public Block addPublicKeys(List<PublicKey> publicKeys) {
this.publicKeys.addAll(publicKeys);
return this;
}

public Block setPublicKeys(List<PublicKey> publicKeys) {
this.publicKeys = publicKeys;
return this;
}

public Block addSymbol(String symbol) {
this.symbols.add(symbol);
return this;
}

public Block add_fact(org.biscuitsec.biscuit.token.builder.Fact f) {
Expand Down Expand Up @@ -124,7 +153,7 @@ public org.biscuitsec.biscuit.token.Block build() {
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,
this.scopes, publicKeys, Option.none(), schemaVersion.version());
this.scopes, publicKeys, this.externalKey, schemaVersion.version());
}

public Block check_right(String right) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,43 +306,57 @@ public static Either<Error, Tuple2<String, Expression>> expr7(String s) {
return Either.left(res1.getLeft());
}
Tuple2<String, Expression> t1 = res1.get();
s = space(t1._1);
Expression e1 = t1._2;

if(!s.startsWith(".")) {
return Either.right(new Tuple2<>(s, e1));
}
s = s.substring(1);

Either<Error, Tuple2<String, Expression.Op>> res2 = binary_op7(s);
if (res2.isLeft()) {
return Either.left(res2.getLeft());
}
Tuple2<String, Expression.Op> t2 = res2.get();
s = space(t2._1);
Expression.Op op = t2._2;

if(!s.startsWith("(")) {
return Either.left(new Error(s, "missing ("));
}

s = space(s.substring(1));
s = t1._1;
Expression e = t1._2;

Either<Error, Tuple2<String, Expression>> res3 = expr(s);
if (res3.isLeft()) {
return Either.left(res3.getLeft());
}
while(true) {
s = space(s);
if(s.isEmpty()) {
break;
}

Tuple2<String, Expression> t3 = res3.get();
if (!s.startsWith(".")) {
return Either.right(new Tuple2<>(s, e));
}

s = space(t3._1);
if(!s.startsWith(")")) {
return Either.left(new Error(s, "missing )"));
s = s.substring(1);
Either<Error, Tuple2<String, Expression.Op>> res2 = binary_op7(s);
if (!res2.isLeft()) {
Tuple2<String, Expression.Op> t2 = res2.get();
s = space(t2._1);
Expression.Op op = t2._2;

if (!s.startsWith("(")) {
return Either.left(new Error(s, "missing ("));
}

s = space(s.substring(1));

Either<Error, Tuple2<String, Expression>> res3 = expr_term(s);
if (res3.isLeft()) {
return Either.left(res3.getLeft());
}

Tuple2<String, Expression> t3 = res3.get();

s = space(t3._1);
if (!s.startsWith(")")) {
return Either.left(new Error(s, "missing )"));
}
s = space(s.substring(1));
Expression e2 = t3._2;

e = new Expression.Binary(op, e, e2);
} else {
if (s.startsWith("length()")) {
e = new Expression.Unary(Expression.Op.Length, e);
s = s.substring(9);
}
}
}
s = space(s.substring(1));
Expression e2 = t3._2;

return Either.right(new Tuple2<>(s, new Expression.Binary(op, e1, e2)));
return Either.right(new Tuple2<>(s, e));
}

public static Either<Error, Tuple2<String, Expression>> expr_term(String s) {
Expand Down Expand Up @@ -517,6 +531,12 @@ 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("union")) {
return Either.right(new Tuple2<>(s.substring(5), Expression.Op.Union));
}
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
@@ -1,7 +1,9 @@
package org.biscuitsec.biscuit.token.builder.parser;

import biscuit.format.schema.Schema;
import io.vavr.collection.Stream;
import org.biscuitsec.biscuit.crypto.PublicKey;
import org.biscuitsec.biscuit.datalog.SymbolTable;
import org.biscuitsec.biscuit.token.Policy;
import io.vavr.Tuple2;
import io.vavr.Tuple4;
Expand All @@ -10,9 +12,7 @@

import java.time.OffsetDateTime;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;
import java.util.*;
import java.util.function.Function;

public class Parser {
Expand Down Expand Up @@ -524,14 +524,14 @@ public static Either<Error, Tuple2<String, Term.Integer>> integer(String s) {
return Either.left(new Error(s, "not an integer"));
}

Integer i = Integer.parseInt(s.substring(0, index2));
long i = Long.parseLong(s.substring(0, index2));
String remaining = s.substring(index2);

return Either.right(new Tuple2<String, Term.Integer>(remaining, (Term.Integer) Utils.integer(i.intValue())));
return Either.right(new Tuple2<String, Term.Integer>(remaining, (Term.Integer) Utils.integer(i)));
}

public static Either<Error, Tuple2<String, Term.Date>> date(String s) {
Tuple2<String, String> t = take_while(s, (c) -> c != ' ' && c != ',' && c != ')');
Tuple2<String, String> t = take_while(s, (c) -> c != ' ' && c != ',' && c != ')' && c != ']');

try {
OffsetDateTime d = OffsetDateTime.parse(t._1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.biscuitsec.biscuit.datalog.SymbolTable;
import org.biscuitsec.biscuit.datalog.TemporarySymbolTable;
import org.biscuitsec.biscuit.datalog.expressions.Op;
import org.biscuitsec.biscuit.token.Biscuit;
import org.biscuitsec.biscuit.token.builder.parser.Error;
import org.biscuitsec.biscuit.token.builder.parser.Parser;
import io.vavr.Tuple2;
Expand All @@ -15,7 +16,7 @@
import org.junit.jupiter.api.Test;

import static org.biscuitsec.biscuit.datalog.Check.Kind.One;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.*;

import java.util.*;

Expand Down Expand Up @@ -132,6 +133,43 @@ 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 expressionIntersectionAndContainsAndLengthEqualsTest() {
Either<Error, Tuple2<String, Expression>> res =
Parser.expression("[1, 2, 3].intersection([1, 2]).length() == 2");

assertEquals(Either.right(new Tuple2<>("",
new Expression.Binary(
Expression.Op.Equal,
new Expression.Unary(
Expression.Op.Length,
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(2))
))), res);
}

@Test
void ruleWithFreeExpressionVariables() {
Either<Error, Tuple2<String, Rule>> res =
Expand Down
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 3dd2f8a

Please sign in to comment.