Skip to content

Commit 625c1ac

Browse files
committed
added support of curly bracket blocks
1 parent 894c5ec commit 625c1ac

File tree

34 files changed

+4116
-35
lines changed

34 files changed

+4116
-35
lines changed

src/main/java/com/igormaznitsa/prologparser/ParserContext.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ public interface ParserContext {
3131
int FLAG_BLOCK_COMMENTS = 1;
3232
int FLAG_ZERO_SINGLE_QUOTATION_CHAR_CODE = 2;
3333
int FLAG_VAR_AS_FUNCTOR = 4;
34-
int FLAG_ALLOW_ZERO_STRUCT = 8;
34+
int FLAG_ZERO_STRUCT_ALLOWED = 8;
35+
int FLAG_CURLY_BRACKETS_ALLOWED = 16;
3536

3637
boolean hasOpStartsWith(PrologParser source, String namePrefix);
3738

src/main/java/com/igormaznitsa/prologparser/PrologParser.java

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ public abstract class PrologParser implements Iterator<PrologTerm>, Iterable<Pro
6767
private static final int MAX_INTERNAL_POOL_SIZE = 96;
6868
private static final OpContainer OPERATOR_COMMA;
6969
private static final OpContainer OPERATOR_LEFTBRACKET;
70+
private static final OpContainer OPERATOR_LEFTCURLYBRACKET;
7071
private static final OpContainer OPERATOR_RIGHTBRACKET;
72+
private static final OpContainer OPERATOR_RIGHTCURLYBRACKET;
7173
private static final OpContainer OPERATOR_RIGHTSQUAREBRACKET;
7274
private static final OpContainer OPERATOR_DOT;
7375
private static final OpContainer OPERATOR_VERTICALBAR;
@@ -76,13 +78,16 @@ public abstract class PrologParser implements Iterator<PrologTerm>, Iterable<Pro
7678
private static final Koi7CharOpMap OPERATORS_END_LIST;
7779
private static final Koi7CharOpMap OPERATORS_INSIDE_STRUCT;
7880
private static final Koi7CharOpMap OPERATORS_SUBBLOCK;
81+
private static final Koi7CharOpMap OPERATORS_SUBBLOCK_CURLY;
7982

8083
static {
8184
META_OP_MAP = ofOps();
8285

8386
OPERATOR_DOT = META_OP_MAP.add(Op.METAOPERATOR_DOT);
8487
OPERATOR_LEFTBRACKET = META_OP_MAP.add(Op.METAOPERATOR_LEFT_BRACKET);
88+
OPERATOR_LEFTCURLYBRACKET = META_OP_MAP.add(Op.METAOPERATOR_LEFT_CURLY_BRACKET);
8589
OPERATOR_RIGHTBRACKET = META_OP_MAP.add(Op.METAOPERATOR_RIGHT_BRACKET);
90+
OPERATOR_RIGHTCURLYBRACKET = META_OP_MAP.add(Op.METAOPERATOR_RIGHT_CURLY_BRACKET);
8691
META_OP_MAP.add(Op.METAOPERATOR_LEFT_SQUARE_BRACKET);
8792
OPERATOR_RIGHTSQUAREBRACKET = META_OP_MAP.add(Op.METAOPERATOR_RIGHT_SQUARE_BRACKET);
8893
OPERATOR_VERTICALBAR = META_OP_MAP.add(Op.METAOPERATOR_VERTICAL_BAR);
@@ -93,6 +98,7 @@ public abstract class PrologParser implements Iterator<PrologTerm>, Iterable<Pro
9398
OPERATORS_END_LIST = ofOps(OPERATOR_RIGHTSQUAREBRACKET);
9499
OPERATORS_INSIDE_STRUCT = ofOps(OPERATOR_COMMA, OPERATOR_RIGHTBRACKET);
95100
OPERATORS_SUBBLOCK = ofOps(OPERATOR_RIGHTBRACKET);
101+
OPERATORS_SUBBLOCK_CURLY = ofOps(OPERATOR_RIGHTCURLYBRACKET);
96102
}
97103

98104
protected final ParserContext context;
@@ -150,7 +156,7 @@ public static Op findBaseMetaOperator(final String text, final OpAssoc type) {
150156
return result;
151157
}
152158

153-
private static int findFirstCharCode(final String text) {
159+
private static int getOnlyCharCode(final String text) {
154160
if (text == null || text.length() != 1) {
155161
return -1;
156162
} else {
@@ -233,7 +239,7 @@ private PrologStruct readStruct(final PrologTerm functor) {
233239
try {
234240
final String nextText = nextAtom.getResult().getTermText();
235241

236-
switch (findFirstCharCode(nextText)) {
242+
switch (getOnlyCharCode(nextText)) {
237243
case ',': {
238244
listOfAtoms.add(block);
239245
}
@@ -279,7 +285,7 @@ private PrologTerm readList(final TokenizerResult openingBracket) {
279285
try {
280286
final String text = nextAtom.getResult().getTermText();
281287

282-
switch (findFirstCharCode(text)) {
288+
switch (getOnlyCharCode(text)) {
283289
case ']': {
284290
doRead = false;
285291
if (block == null) {
@@ -444,7 +450,8 @@ private PrologTerm readBlock(final Koi7CharOpMap endOperators) {
444450
final String operatorText = readOperator.getTermText();
445451

446452
if (operatorText.length() == 1) {
447-
switch (findFirstCharCode(operatorText)) {
453+
final int onlyCharCode = getOnlyCharCode(operatorText);
454+
switch (onlyCharCode) {
448455
case '[': {
449456
// it's a list
450457
readAtom = readList(readAtomContainer);
@@ -453,31 +460,44 @@ private PrologTerm readBlock(final Koi7CharOpMap endOperators) {
453460
readAtomPrecedence = 0;
454461
}
455462
break;
463+
case '{':
456464
case '(': {
457-
// read sub-block
458-
readAtom = readBlock(OPERATORS_SUBBLOCK);
459-
460-
if (readAtom == null) {
461-
throw new PrologParserException("Illegal start of term",
462-
readAtomContainer.getLine(), readAtomContainer.getPos());
465+
boolean processReadAtom = true;
466+
if (onlyCharCode == '(') {
467+
readAtom = readBlock(OPERATORS_SUBBLOCK);
468+
} else {
469+
if ((this.parserFlags & ParserContext.FLAG_CURLY_BRACKETS_ALLOWED) == 0) {
470+
readAtomPrecedence = readOperator.getPrecedence();
471+
processReadAtom = false;
472+
} else {
473+
readAtom = readBlock(OPERATORS_SUBBLOCK_CURLY);
474+
}
463475
}
464476

465-
readAtom.setLine(readAtomContainer.getLine());
466-
readAtom.setPos(readAtomContainer.getPos());
467-
readAtom = new PrologStruct(Op.VIRTUAL_OPERATOR_BLOCK, new PrologTerm[] {readAtom}, readAtomContainer.getLine(), readAtomContainer.getPos());
477+
if (processReadAtom) {
478+
if (readAtom == null) {
479+
throw new PrologParserException("Illegal start of term",
480+
readAtomContainer.getLine(), readAtomContainer.getPos());
481+
}
468482

469-
final TokenizerResult token = this.tokenizer.readNextToken();
483+
readAtom.setLine(readAtomContainer.getLine());
484+
readAtom.setPos(readAtomContainer.getPos());
470485

471-
final PrologTerm closingAtom;
472-
if (token == null) {
473-
closingAtom = null;
474-
} else {
475-
closingAtom = token.getResult();
476-
token.release();
477-
}
486+
readAtom = new PrologStruct(onlyCharCode == '{' ? Op.VIRTUAL_OPERATOR_CURLY_BLOCK : Op.VIRTUAL_OPERATOR_BLOCK, new PrologTerm[] {readAtom}, readAtomContainer.getLine(), readAtomContainer.getPos());
478487

479-
if (closingAtom == null || !closingAtom.getTermText().equals(OPERATOR_RIGHTBRACKET.getTermText())) {
480-
throw new PrologParserException("Non-closed brakes", this.tokenizer.getLine(), this.tokenizer.getPos());
488+
final TokenizerResult token = this.tokenizer.readNextToken();
489+
490+
final PrologTerm closingAtom;
491+
if (token == null) {
492+
closingAtom = null;
493+
} else {
494+
closingAtom = token.getResult();
495+
token.release();
496+
}
497+
498+
if (closingAtom == null || !closingAtom.getTermText().equals((onlyCharCode == '{' ? OPERATOR_RIGHTCURLYBRACKET : OPERATOR_RIGHTBRACKET).getTermText())) {
499+
throw new PrologParserException("Non-closed brackets: " + onlyCharCode, this.tokenizer.getLine(), this.tokenizer.getPos());
500+
}
481501
}
482502
}
483503
break;
@@ -514,7 +534,7 @@ private PrologTerm readBlock(final Koi7CharOpMap endOperators) {
514534
readAtom = readStruct(readAtom);
515535
if (readAtom == null) {
516536
// we have met the empty brackets
517-
if ((this.parserFlags & FLAG_ALLOW_ZERO_STRUCT) == 0) {
537+
if ((this.parserFlags & FLAG_ZERO_STRUCT_ALLOWED) == 0) {
518538
throw new PrologParserException("Empty structure is not allowed",
519539
nextTokenLineNumber, nextTokenStrPosition);
520540
} else {

src/main/java/com/igormaznitsa/prologparser/terms/PrologStruct.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,12 @@ public PrologStruct copyWithAnotherFunctor(final PrologTerm newFunctor) {
159159

160160
@Override
161161
public boolean isBlock() {
162-
return this.functor == Op.VIRTUAL_OPERATOR_BLOCK;
162+
return this.functor == Op.VIRTUAL_OPERATOR_BLOCK || this.functor == Op.VIRTUAL_OPERATOR_CURLY_BLOCK;
163+
}
164+
165+
@Override
166+
public boolean isCurlyBlock() {
167+
return this.functor == Op.VIRTUAL_OPERATOR_CURLY_BLOCK;
163168
}
164169

165170
@Override
@@ -180,7 +185,11 @@ public String toString() {
180185

181186
if (this.functor.getTermType() == TermType.OPERATOR) {
182187
if (this.isBlock()) {
183-
builder.append('(').append(this.elements[0].toString()).append(')');
188+
if (this.isCurlyBlock()) {
189+
builder.append('{').append(this.elements[0].toString()).append('}');
190+
} else {
191+
builder.append('(').append(this.elements[0].toString()).append(')');
192+
}
184193
} else {
185194
final Op operatorFunctor = (Op) functor;
186195
final String opName = operatorFunctor.getTermText();

src/main/java/com/igormaznitsa/prologparser/terms/PrologTerm.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ public boolean isBlock() {
9494
return false;
9595
}
9696

97+
public boolean isCurlyBlock() {
98+
return false;
99+
}
100+
97101
public Quotation getQuotation() {
98102
return this.quotation;
99103
}

src/main/java/com/igormaznitsa/prologparser/tokenizer/Op.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ public final class Op extends SpecServiceCompound {
6565
public static final Op ISO_DIRECTIVES = make(1200, OpAssoc.FX, "?-", ":-");
6666
public static final Op ISO_BITWISE_AND_OR = make(500, OpAssoc.YFX, "/\\", "\\/");
6767

68+
public static final Op MODIFIERS = make(1150, OpAssoc.FX,
69+
"public",
70+
"dynamic",
71+
"volatile",
72+
"discontiguous",
73+
"multifile",
74+
"initialization"
75+
);
6876

6977
public static final Op GNU_DIV_RDIV = make(400, OpAssoc.YFX, "div", "rdiv");
7078

@@ -73,6 +81,16 @@ public final class Op extends SpecServiceCompound {
7381
public static final Op GNU_STAR_THEN = make(1050, OpAssoc.XFY, "*->");
7482
public static final Op GNU_DOUBLE_DOT = make(600, OpAssoc.XFY, ":");
7583

84+
public static final List<Op> SICTUS_SPECIFIC = Collections.unmodifiableList(Arrays.asList(
85+
MODIFIERS,
86+
make(1150, FX, "mode", "block", "meta_predicate"),
87+
make(1100, XFY, "do"),
88+
make(900, FY, "spy", "nospy"),
89+
make(550, XFY, ":"),
90+
make(500, YFX, "\\"),
91+
GNU_UNARY_PLUS
92+
));
93+
7694
/**
7795
* Set of operators for ISO Prolog standard.
7896
*/
@@ -111,7 +129,8 @@ public final class Op extends SpecServiceCompound {
111129
* Set of operators is specific for SWI Prolog use
112130
*/
113131
public static final List<Op> SWI_SPECIFIC = Collections.unmodifiableList(Arrays.asList(
114-
make(1150, OpAssoc.FX, "dynamic", "discontiguous", "initialization", "meta_predicate", "module_transparent", "multifile", "public", "thread_local", "thread_initialization", "volatile"),
132+
MODIFIERS,
133+
make(1150, OpAssoc.FX, "meta_predicate", "module_transparent", "thread_local", "thread_initialization"),
115134
GNU_STAR_THEN,
116135
make(990, OpAssoc.FY, ":="),
117136
make(700, OpAssoc.XFX, "=@=", "\\=@=", "as", ">:<", ":<"),
@@ -164,9 +183,12 @@ public final class Op extends SpecServiceCompound {
164183
));
165184

166185
public static final Op VIRTUAL_OPERATOR_BLOCK = makeSystem(-1, OpAssoc.FX, "()");
186+
public static final Op VIRTUAL_OPERATOR_CURLY_BLOCK = makeSystem(-1, OpAssoc.FX, "{}");
167187
public static final Op METAOPERATOR_COMMA = makeSystem(1000, OpAssoc.XFY, ",");
168188
public static final Op METAOPERATOR_LEFT_BRACKET = makeSystem(-1, OpAssoc.FX, "(");
189+
public static final Op METAOPERATOR_LEFT_CURLY_BRACKET = makeSystem(-1, OpAssoc.FX, "{");
169190
public static final Op METAOPERATOR_RIGHT_BRACKET = makeSystem(-1, OpAssoc.XF, ")");
191+
public static final Op METAOPERATOR_RIGHT_CURLY_BRACKET = makeSystem(-1, OpAssoc.XF, "}");
170192
public static final Op METAOPERATOR_LEFT_SQUARE_BRACKET = makeSystem(-1, OpAssoc.FX, "[");
171193
public static final Op METAOPERATOR_RIGHT_SQUARE_BRACKET = makeSystem(-1, OpAssoc.XF, "]");
172194
public static final Op METAOPERATOR_DOT = makeSystem(Integer.MAX_VALUE, OpAssoc.XF, ".");

src/main/java/com/igormaznitsa/prologparser/tokenizer/TreeItem.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,11 @@ private boolean isPrecedenceOk() {
226226
}
227227

228228
private boolean isBlock() {
229-
return this.savedTerm.getTermType() == TermType.STRUCT && ((PrologStruct) this.savedTerm).getFunctor() == Op.VIRTUAL_OPERATOR_BLOCK;
229+
return this.savedTerm.getTermType() == TermType.STRUCT
230+
&& (
231+
((PrologStruct) this.savedTerm).getFunctor() == Op.VIRTUAL_OPERATOR_BLOCK
232+
|| ((PrologStruct) this.savedTerm).getFunctor() == Op.VIRTUAL_OPERATOR_CURLY_BLOCK
233+
);
230234
}
231235

232236
private boolean isOperator() {
@@ -320,10 +324,10 @@ public PrologTerm convertToTermAndRelease() {
320324
break;
321325
case STRUCT: {
322326
final PrologStruct thisStruct = (PrologStruct) this.savedTerm;
323-
if (thisStruct.getFunctor() == Op.VIRTUAL_OPERATOR_BLOCK
327+
if ((thisStruct.getFunctor() == Op.VIRTUAL_OPERATOR_BLOCK || thisStruct.getFunctor() == Op.VIRTUAL_OPERATOR_CURLY_BLOCK)
324328
&& thisStruct.getArity() == 1) {
325329
final PrologTerm thatTerm = thisStruct.getTermAt(0);
326-
if (thatTerm.getTermType() == TermType.STRUCT && ((PrologStruct) thatTerm).getFunctor() == Op.VIRTUAL_OPERATOR_BLOCK) {
330+
if (thatTerm.getTermType() == TermType.STRUCT && (((PrologStruct) thatTerm).getFunctor() == Op.VIRTUAL_OPERATOR_BLOCK || ((PrologStruct) thatTerm).getFunctor() == Op.VIRTUAL_OPERATOR_CURLY_BLOCK)) {
327331
result = thatTerm;
328332
} else {
329333
result = thisStruct;

src/test/java/com/igormaznitsa/prologparser/IntegrationTest.java

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.io.StringReader;
2424
import java.math.BigDecimal;
2525
import java.nio.charset.StandardCharsets;
26+
import java.util.Arrays;
2627
import java.util.Collections;
2728
import java.util.HashMap;
2829
import java.util.HashSet;
@@ -568,6 +569,56 @@ private void assertReadTerms(final int expected, final String resource, final Op
568569
}
569570
}
570571

572+
private void assertReadSictusTerms(final int expected, final String resource, final Op... ops) {
573+
final ParserContext defaultContext = of(ParserContext.FLAG_BLOCK_COMMENTS | ParserContext.FLAG_CURLY_BRACKETS_ALLOWED, Op.join(Op.ISO, Op.SICTUS_SPECIFIC, Arrays.asList(ops)));
574+
try (Reader reader = new InputStreamReader(getClass().getResourceAsStream("bench/" + resource), StandardCharsets.UTF_8)) {
575+
final PrologParser parser = new GenericPrologParser(reader, defaultContext);
576+
assertEquals(expected, parser.stream().count());
577+
} catch (IOException ex) {
578+
ex.printStackTrace();
579+
fail("IOException");
580+
}
581+
}
582+
583+
@Test
584+
public void testCurlyBracket() {
585+
assertEquals("{1 , 2 , 3 , 4 , 5}", new GenericPrologParser(new StringReader("{1,2,3,4,5}."), of(FLAG_CURLY_BRACKETS_ALLOWED)).next().toString());
586+
assertEquals("{1 , {2 , {3 , {4} , 5}}}", new GenericPrologParser(new StringReader("{1,{2,{3,{4},5}}}."), of(FLAG_CURLY_BRACKETS_ALLOWED)).next().toString());
587+
assertThrows(PrologParserException.class, () -> new GenericPrologParser(new StringReader("test{1,2,3,4,5}."), of(FLAG_CURLY_BRACKETS_ALLOWED)).next());
588+
}
589+
590+
@Test
591+
public void testParseSictusBench() {
592+
assertReadSictusTerms(136, "boyer.pl");
593+
assertReadSictusTerms(29, "browse.pl");
594+
assertReadSictusTerms(518, "chat_parser.pl");
595+
assertReadSictusTerms(30, "crypt.pl");
596+
assertReadSictusTerms(17, "deriv.pl");
597+
assertReadSictusTerms(9, "dynamic_unit_clause.pl");
598+
assertReadSictusTerms(17, "fast_mu.pl");
599+
assertReadSictusTerms(57, "flatten.pl");
600+
assertReadSictusTerms(10, "harness.pl");
601+
assertReadSictusTerms(5, "itak.pl");
602+
assertReadSictusTerms(27, "main.pl");
603+
assertReadSictusTerms(27, "meta_qsort.pl");
604+
assertReadSictusTerms(18, "mu.pl");
605+
assertReadSictusTerms(7, "nreverse.pl");
606+
assertReadSictusTerms(5, "nreverse_builtin.pl");
607+
assertReadSictusTerms(34, "poly.pl");
608+
assertReadSictusTerms(11, "primes.pl");
609+
610+
assertReadSictusTerms(39, "prover.pl", Op.make(950, XFY, "#"), Op.make(850, XFY, "&"), Op.make(500, FX, "-", "+"));
611+
assertReadSictusTerms(8, "qsort.pl");
612+
assertReadSictusTerms(14, "queens.pl");
613+
assertReadSictusTerms(55, "query.pl");
614+
assertReadSictusTerms(119, "reducer.pl");
615+
assertReadSictusTerms(25, "sendmore.pl");
616+
assertReadSictusTerms(144, "simple_analyzer.pl");
617+
assertReadSictusTerms(5, "tak.pl");
618+
assertReadSictusTerms(64, "unify.pl");
619+
assertReadSictusTerms(8, "zebra.pl");
620+
}
621+
571622
@Test
572623
public void testParseSourceFiles() {
573624
assertReadTerms(17, "calc.p");
@@ -1084,19 +1135,19 @@ public void testVarAsFunctor() {
10841135
@Test
10851136
public void testAllowZeroStruct() {
10861137
assertThrows(PrologParserException.class, () -> new GenericPrologParser(new StringReader("a()."), DefaultParserContext.of(FLAG_NONE)).next());
1087-
final PrologStruct struct = (PrologStruct) new GenericPrologParser(new StringReader("a()."), DefaultParserContext.of(FLAG_ALLOW_ZERO_STRUCT)).next();
1138+
final PrologStruct struct = (PrologStruct) new GenericPrologParser(new StringReader("a()."), DefaultParserContext.of(FLAG_ZERO_STRUCT_ALLOWED)).next();
10881139
final PrologAtom functor = (PrologAtom) struct.getFunctor();
10891140
assertEquals("a", functor.getTermText());
10901141
assertEquals(0, struct.getArity());
10911142
assertEquals("a()", struct.toString());
10921143

1093-
final PrologStruct structB = (PrologStruct) new GenericPrologParser(new StringReader("a(/*some comment*/)."), DefaultParserContext.of(FLAG_ALLOW_ZERO_STRUCT | FLAG_BLOCK_COMMENTS)).next();
1144+
final PrologStruct structB = (PrologStruct) new GenericPrologParser(new StringReader("a(/*some comment*/)."), DefaultParserContext.of(FLAG_ZERO_STRUCT_ALLOWED | FLAG_BLOCK_COMMENTS)).next();
10941145
assertEquals("a()", structB.toString());
10951146

1096-
final PrologStruct structC = (PrologStruct) new GenericPrologParser(new StringReader("a(),b(),c()."), DefaultParserContext.of(FLAG_ALLOW_ZERO_STRUCT | FLAG_BLOCK_COMMENTS)).next();
1147+
final PrologStruct structC = (PrologStruct) new GenericPrologParser(new StringReader("a(),b(),c()."), DefaultParserContext.of(FLAG_ZERO_STRUCT_ALLOWED | FLAG_BLOCK_COMMENTS)).next();
10971148
assertEquals("a() , b() , c()", structC.toString());
10981149

1099-
final PrologStruct structD = (PrologStruct) new GenericPrologParser(new StringReader("A(),X(),Z()."), DefaultParserContext.of(FLAG_VAR_AS_FUNCTOR | FLAG_ALLOW_ZERO_STRUCT | FLAG_BLOCK_COMMENTS)).next();
1150+
final PrologStruct structD = (PrologStruct) new GenericPrologParser(new StringReader("A(),X(),Z()."), DefaultParserContext.of(FLAG_VAR_AS_FUNCTOR | FLAG_ZERO_STRUCT_ALLOWED | FLAG_BLOCK_COMMENTS)).next();
11001151
assertEquals("A() , X() , Z()", structD.toString());
11011152

11021153
}

0 commit comments

Comments
 (0)