Skip to content

Commit 2b7aa44

Browse files
committed
add datalog parser for block
1 parent 45a163c commit 2b7aa44

File tree

2 files changed

+79
-4
lines changed

2 files changed

+79
-4
lines changed

src/main/java/org/biscuitsec/biscuit/token/builder/parser/Parser.java

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package org.biscuitsec.biscuit.token.builder.parser;
22

33
import biscuit.format.schema.Schema;
4+
import io.vavr.collection.Stream;
45
import org.biscuitsec.biscuit.crypto.PublicKey;
6+
import org.biscuitsec.biscuit.datalog.SymbolTable;
57
import org.biscuitsec.biscuit.token.Policy;
68
import io.vavr.Tuple2;
79
import io.vavr.Tuple4;
@@ -10,12 +12,48 @@
1012

1113
import java.time.OffsetDateTime;
1214
import java.time.format.DateTimeParseException;
13-
import java.util.ArrayList;
14-
import java.util.List;
15-
import java.util.HashSet;
15+
import java.util.*;
1616
import java.util.function.Function;
1717

1818
public class Parser {
19+
/**
20+
* Takes a datalog string with <code>\n</code> as datalog line separator. It tries to parse
21+
* each line using fact, rule, check and scope sequentially.
22+
*
23+
* If one succeeds it returns Right(Block)
24+
* else it returns a Map[lineNumber, List[Error]]
25+
*
26+
* @param index block index
27+
* @param baseSymbols symbols table
28+
* @param s datalog string to parse
29+
* @return Either<Map<Integer, List<Error>>, Block>
30+
*/
31+
public static Either<Map<Integer, List<Error>>, Block> datalog(long index, SymbolTable baseSymbols, String s) {
32+
Block blockBuilder = new Block(index, baseSymbols);
33+
Map<Integer, List<Error>> errors = new HashMap<>();
34+
35+
Stream.of(s.split("\n")).zipWithIndex().forEach(indexedLine -> {
36+
Integer lineNumber = indexedLine._2;
37+
String codeLine = indexedLine._1;
38+
List<Error> lineErrors = new ArrayList<>();
39+
40+
fact(codeLine).bimap(lineErrors::add, r -> r._2).map(blockBuilder::add_fact);
41+
rule(codeLine).bimap(lineErrors::add, r -> r._2).map(blockBuilder::add_rule);
42+
check(codeLine).bimap(lineErrors::add, r -> r._2).map(blockBuilder::add_check);
43+
scope(codeLine).bimap(lineErrors::add, r -> r._2).map(blockBuilder::add_scope);
44+
45+
if (lineErrors.size() > 3) {
46+
errors.put(lineNumber, lineErrors);
47+
}
48+
});
49+
50+
if (!errors.isEmpty()) {
51+
return Either.left(errors);
52+
}
53+
54+
return Either.right(blockBuilder);
55+
}
56+
1957
public static Either<Error, Tuple2<String, Fact>> fact(String s) {
2058
Either<Error, Tuple2<String, Predicate>> res = fact_predicate(s);
2159
if (res.isLeft()) {

src/test/java/org/biscuitsec/biscuit/builder/parser/ParserTest.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.biscuitsec.biscuit.datalog.SymbolTable;
66
import org.biscuitsec.biscuit.datalog.TemporarySymbolTable;
77
import org.biscuitsec.biscuit.datalog.expressions.Op;
8+
import org.biscuitsec.biscuit.token.Biscuit;
89
import org.biscuitsec.biscuit.token.builder.parser.Error;
910
import org.biscuitsec.biscuit.token.builder.parser.Parser;
1011
import io.vavr.Tuple2;
@@ -15,7 +16,7 @@
1516
import org.junit.jupiter.api.Test;
1617

1718
import static org.biscuitsec.biscuit.datalog.Check.Kind.One;
18-
import static org.junit.jupiter.api.Assertions.assertEquals;
19+
import static org.junit.jupiter.api.Assertions.*;
1920

2021
import java.util.*;
2122

@@ -360,4 +361,40 @@ void testParens() throws org.biscuitsec.biscuit.error.Error.Execution {
360361
assertEquals(new org.biscuitsec.biscuit.datalog.Term.Integer(9), value2);
361362
assertEquals("(1 + 2) * 3", ex2.print(s2).get());
362363
}
364+
365+
@Test
366+
void testDatalogSucceeds() throws org.biscuitsec.biscuit.error.Error.Parser {
367+
SymbolTable symbols = Biscuit.default_symbol_table();
368+
369+
String l1 = "fact1(1)";
370+
String l2 = "fact2(\"2\")";
371+
String l3 = "rule1(2) <- fact2(\"2\")";
372+
String l4 = "check if rule1(2)";
373+
String toParse = String.join("\n", Arrays.asList(l1, l2, l3, l4));
374+
375+
Either<Map<Integer, List<Error>>, Block> output = Parser.datalog(1, symbols, toParse);
376+
assertTrue(output.isRight());
377+
378+
Block validBlock = new Block(1, symbols);
379+
validBlock.add_fact(l1);
380+
validBlock.add_fact(l2);
381+
validBlock.add_rule(l3);
382+
validBlock.add_check(l4);
383+
384+
output.forEach(block ->
385+
assertArrayEquals(block.build().to_bytes().get(), validBlock.build().to_bytes().get())
386+
);
387+
}
388+
389+
@Test
390+
void testDatalogFailed() {
391+
SymbolTable symbols = Biscuit.default_symbol_table();
392+
393+
String l1 = "fact(1)";
394+
String l2 = "check fact(1)"; // typo missing "if"
395+
String toParse = String.join("\n", Arrays.asList(l1, l2));
396+
397+
Either<Map<Integer, List<Error>>, Block> output = Parser.datalog(1, symbols, toParse);
398+
assertTrue(output.isLeft());
399+
}
363400
}

0 commit comments

Comments
 (0)