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 19, 2024
1 parent 903ebea commit 4ceee3a
Show file tree
Hide file tree
Showing 7 changed files with 376 additions and 61 deletions.
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 @@ -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
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 @@ -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 = expr7(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
127 changes: 113 additions & 14 deletions src/main/java/org/biscuitsec/biscuit/token/builder/parser/Parser.java
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,26 +29,82 @@ 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);
Map<Integer, List<Error>> errors = new HashMap<>();

Stream.of(s.split("\n")).zipWithIndex().forEach(indexedLine -> {
Integer lineNumber = indexedLine._2;
String codeLine = indexedLine._1;
List<Error> lineErrors = new ArrayList<>();
// empty block code
if (s.isEmpty()) {
return Either.right(blockBuilder);
}

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);
if (blockSymbols != null) {
blockSymbols.symbols.forEach(blockBuilder::addSymbol);
}

if (lineErrors.size() > 3) {
errors.put(lineNumber, lineErrors);
}
Map<Integer, List<Error>> errors = new HashMap<>();

s = removeCommentsAndWhitespaces(s);
String[] codeLines = s.split(";");

Stream.of(codeLines)
.zipWithIndex()
.forEach(indexedLine -> {
String code = indexedLine._1.strip();

if (!code.isEmpty()) {
int lineNumber = indexedLine._2;
System.out.println("NEW CODE LINE");
System.out.println(code);
List<Error> lineErrors = new ArrayList<>();

boolean parsed = false;
parsed = rule(code).fold(e -> {
lineErrors.add(e);
return false;
}, r -> {
blockBuilder.add_rule(r._2);
return true;
});

if (!parsed) {
parsed = scope(code).fold(e -> {
lineErrors.add(e);
return false;
}, r -> {
blockBuilder.add_scope(r._2);
return true;
});
}

if (!parsed) {
parsed = fact(code).fold(e -> {
lineErrors.add(e);
return false;
}, r -> {
blockBuilder.add_fact(r._2);
return true;
});
}

if (!parsed) {
parsed = check(code).fold(e -> {
lineErrors.add(e);
return false;
}, r -> {
blockBuilder.add_check(r._2);
return true;
});
}

if (!parsed) {
lineErrors.forEach(System.out::println);
errors.put(lineNumber, lineErrors);
}
}
});

if (!errors.isEmpty()) {
Expand Down Expand Up @@ -569,7 +629,7 @@ public static Either<Error, Tuple2<String, Term.Integer>> integer(String s) {
}

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 Expand Up @@ -709,4 +769,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 removeCommentsAndWhitespaces(String s) {
s = removeComments(s);
s = s.replace("\n", "").replace("\\\"", "\"").strip();
return s;
}

public static String removeComments(String str) {
StringBuilder result = new StringBuilder();
String remaining = str;

while (!remaining.isEmpty()) {
remaining = space(remaining); // Skip leading whitespace
if (remaining.startsWith("/*")) {
// Find the end of the multiline comment
remaining = remaining.substring(2); // Skip "/*"
String finalRemaining = remaining;
Tuple2<String, String> split = take_while(remaining, c -> !finalRemaining.startsWith("*/"));
remaining = split._2.length() > 2 ? split._2.substring(2) : ""; // Skip "*/"
} else if (remaining.startsWith("//")) {
// Find the end of the single-line comment
remaining = remaining.substring(2); // Skip "//"
Tuple2<String, String> split = take_while(remaining, c -> c != '\n' && c != '\r');
remaining = split._2;
if (!remaining.isEmpty()) {
result.append(remaining.charAt(0)); // Preserve line break
remaining = remaining.substring(1);
}
} else {
// Take non-comment text until the next comment or end of string
String finalRemaining = remaining;
Tuple2<String, String> split = take_while(remaining, c -> !finalRemaining.startsWith("/*") && !finalRemaining.startsWith("//"));
result.append(split._1);
remaining = split._2;
}
}

return result.toString();
}
}
Loading

0 comments on commit 4ceee3a

Please sign in to comment.