Skip to content

Commit 2b88200

Browse files
committed
added flag to support ./2 as list
1 parent 1cc5186 commit 2b88200

File tree

6 files changed

+316
-207
lines changed

6 files changed

+316
-207
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ public String toString() {
211211
PrologTerm convertToTermAndRelease(final PrologParser parser) {
212212
PrologTerm result;
213213

214-
switch (savedTerm.getType()) {
214+
switch (this.savedTerm.getType()) {
215215
case OPERATOR: {
216216
final TermWrapper wrapper = (TermWrapper) this.savedTerm;
217217
if (this.leftItem == null && this.rightItem == null) {

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ public interface ParserContext {
5959
* Example: {a,{b,!,c}}
6060
*/
6161
int FLAG_CURLY_BRACKETS = 16;
62+
/**
63+
* Recognize '.'(_,_) as a list term.
64+
*/
65+
int FLAG_DOT2_AS_LIST = 32;
6266

6367
/**
6468
* Check that the context contains an operator starts with some string

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -341,8 +341,7 @@ private PrologTerm readBlock(final Koi7CharOpMap endOperators) {
341341
// check the atom to be the end atom
342342
if (isEndOperator(readAtom, endOperators)) {
343343
// it's an end atom so we push it back and end the cycle
344-
tokenizer.push(readAtomContainer);
345-
readAtomContainer = null;
344+
this.tokenizer.push(readAtomContainer);
346345
break;
347346
}
348347

@@ -498,14 +497,12 @@ private PrologTerm readBlock(final Koi7CharOpMap endOperators) {
498497
}
499498
} else {
500499
tokenizer.push(nextToken);
501-
nextToken = null;
502500
throw new PrologParserException("You must have an atom as the structure functor",
503501
nextTokenLineNumber, nextTokenStrPosition);
504502
}
505503
} else {
506504
// push back the next atom
507505
tokenizer.push(nextToken);
508-
nextToken = null;
509506
}
510507
}
511508
}
@@ -584,7 +581,15 @@ private PrologTerm readBlock(final Koi7CharOpMap endOperators) {
584581
if (currentTreeItem == null) {
585582
return null;
586583
} else {
587-
return currentTreeItem.findRoot().convertToTermAndRelease(this);
584+
PrologTerm result = currentTreeItem.findRoot().convertToTermAndRelease(this);
585+
if ((this.parserFlags & FLAG_DOT2_AS_LIST) != 0
586+
&& result.getType() == TermType.STRUCT
587+
&& result.getText().equals(".")
588+
&& result.getArity() == 2) {
589+
final PrologStruct asStruct = (PrologStruct) result;
590+
result = new PrologList(asStruct.getTermAt(0), asStruct.getTermAt(1));
591+
}
592+
return result;
588593
}
589594
}
590595

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/*
2+
* Copyright 2019 Igor Maznitsa.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.igormaznitsa.prologparser;
17+
18+
import static com.igormaznitsa.prologparser.DefaultParserContext.of;
19+
import static com.igormaznitsa.prologparser.ParserContext.FLAG_BLOCK_COMMENTS;
20+
import static com.igormaznitsa.prologparser.ParserContext.FLAG_CURLY_BRACKETS;
21+
import static com.igormaznitsa.prologparser.ParserContext.FLAG_DOT2_AS_LIST;
22+
import static com.igormaznitsa.prologparser.ParserContext.FLAG_NONE;
23+
import static com.igormaznitsa.prologparser.ParserContext.FLAG_ZERO_QUOTATION_CHARCODE;
24+
import com.igormaznitsa.prologparser.terms.OpContainer;
25+
import com.igormaznitsa.prologparser.terms.PrologInt;
26+
import com.igormaznitsa.prologparser.terms.PrologStruct;
27+
import com.igormaznitsa.prologparser.terms.PrologTerm;
28+
import com.igormaznitsa.prologparser.terms.TermType;
29+
import static com.igormaznitsa.prologparser.terms.TermType.ATOM;
30+
import com.igormaznitsa.prologparser.tokenizer.Op;
31+
import com.igormaznitsa.prologparser.tokenizer.OpAssoc;
32+
import java.io.IOException;
33+
import java.io.InputStreamReader;
34+
import java.io.Reader;
35+
import java.io.StringReader;
36+
import java.nio.charset.StandardCharsets;
37+
import java.util.Arrays;
38+
import java.util.List;
39+
import java.util.Map;
40+
import static org.junit.jupiter.api.Assertions.assertEquals;
41+
import static org.junit.jupiter.api.Assertions.assertFalse;
42+
import static org.junit.jupiter.api.Assertions.assertTrue;
43+
import static org.junit.jupiter.api.Assertions.fail;
44+
import static org.mockito.Mockito.mock;
45+
import static org.mockito.Mockito.when;
46+
47+
abstract class AbstractIntegrationTest {
48+
public PrologParser parseCpl(final String str) {
49+
return new GenericPrologParser(new StringReader(str), DefaultParserContext.of(FLAG_BLOCK_COMMENTS | FLAG_ZERO_QUOTATION_CHARCODE | FLAG_CURLY_BRACKETS, Op.SWI, Op.SWI_CPL));
50+
}
51+
52+
public PrologParser parseIso(final String str) {
53+
return new GenericPrologParser(new StringReader(str), DefaultParserContext.of(FLAG_ZERO_QUOTATION_CHARCODE | FLAG_DOT2_AS_LIST, Op.ISO));
54+
}
55+
56+
public PrologParser parseEd(final String str) {
57+
final ParserContext parserContext = mock(ParserContext.class);
58+
when(parserContext.getMaxTokenizerBufferLength()).thenReturn(1024);
59+
when(parserContext.getFlags()).thenReturn(FLAG_BLOCK_COMMENTS | FLAG_ZERO_QUOTATION_CHARCODE | FLAG_CURLY_BRACKETS);
60+
return parseEd(str, parserContext);
61+
}
62+
63+
public PrologParser parseEd(final String str, final ParserContext context) {
64+
return parseEd(new StringReader(str), context);
65+
}
66+
67+
public PrologParser parseEd(final Reader reader, final ParserContext context) {
68+
return new GenericPrologParser(reader, ParserContextChain.of(
69+
DefaultParserContext.of(FLAG_BLOCK_COMMENTS | FLAG_ZERO_QUOTATION_CHARCODE | FLAG_CURLY_BRACKETS, Op.SWI), context));
70+
}
71+
72+
public PrologParser parseGen(final String str, final ParserContext context) {
73+
final ParserContext parserContext = mock(ParserContext.class);
74+
when(parserContext.getMaxTokenizerBufferLength()).thenReturn(1024);
75+
when(parserContext.getFlags()).thenReturn(ParserContext.FLAG_BLOCK_COMMENTS | FLAG_ZERO_QUOTATION_CHARCODE | FLAG_CURLY_BRACKETS);
76+
return new GenericPrologParser(new StringReader(str), ParserContextChain.of(context, parserContext));
77+
}
78+
79+
public GenericPrologParser parseGen(final String str) {
80+
final ParserContext parserContext = mock(ParserContext.class);
81+
when(parserContext.getMaxTokenizerBufferLength()).thenReturn(1024);
82+
when(parserContext.getFlags()).thenReturn(ParserContext.FLAG_BLOCK_COMMENTS | FLAG_ZERO_QUOTATION_CHARCODE);
83+
return new GenericPrologParser(new StringReader(str), parserContext);
84+
}
85+
86+
public void assertReadTerms(final int expected, final String resource, final List<Op> ops) {
87+
assertReadTerms(expected, resource, ops.toArray(new Op[0]));
88+
}
89+
90+
public void assertReadTerms(final int expected, final String resource, final Op... ops) {
91+
final ParserContext defaultContext = of(ParserContext.FLAG_BLOCK_COMMENTS, ops);
92+
try (Reader reader = new InputStreamReader(getClass().getResourceAsStream(resource), StandardCharsets.UTF_8)) {
93+
final PrologParser parser = parseEd(reader, defaultContext);
94+
assertEquals(expected, parser.stream().count());
95+
} catch (IOException ex) {
96+
ex.printStackTrace();
97+
fail("IOException");
98+
}
99+
}
100+
101+
public ParserContext makeSictusContext(final Op... ops) {
102+
return of(ParserContext.FLAG_BLOCK_COMMENTS | ParserContext.FLAG_CURLY_BRACKETS, Op.ISO, Op.SICTUS_SPECIFIC, Arrays.asList(ops));
103+
}
104+
105+
public void assertReadSictusTerms(final int expected, final String resource, final Op... ops) {
106+
final ParserContext defaultContext = makeSictusContext(ops);
107+
try (Reader reader = new InputStreamReader(getClass().getResourceAsStream("bench/" + resource), StandardCharsets.UTF_8)) {
108+
final PrologParser parser = new GenericPrologParser(reader, defaultContext);
109+
assertEquals(expected, parser.stream().count());
110+
} catch (IOException ex) {
111+
ex.printStackTrace();
112+
fail("IOException");
113+
}
114+
}
115+
116+
public void assertOperatorAsFunctor(final String goal, final String opText, final OpAssoc assoc, final int arity, final String expectedText) {
117+
final PrologParser parser = parseEd(goal);
118+
assertTrue(parser.hasNext());
119+
final PrologTerm term = parser.next();
120+
assertFalse(parser.hasNext());
121+
assertEquals(TermType.OPERATOR, term.getFunctor().getType(), term.toString());
122+
assertEquals(opText, term.getText(), term.toString());
123+
assertEquals(assoc, ((Op) term.getFunctor()).getAssoc(), term.toString());
124+
assertEquals(arity, term.getArity(), term.toString());
125+
assertEquals(expectedText, term.toString());
126+
}
127+
128+
public void assertOperatorAsFunctor(final String expected, final PrologTerm term) {
129+
assertTrue(term instanceof PrologStruct);
130+
final PrologStruct struct = (PrologStruct) term;
131+
assertEquals(TermType.OPERATOR, struct.getFunctor().getType(), term.toString());
132+
assertEquals(struct.getFunctor().getArity(), struct.getArity(), term.toString());
133+
assertEquals(expected, term.toString(), term.toString());
134+
}
135+
136+
public void checkIntegerWithoutPPE(final String atomToBeChecked, final long expectedNumber) {
137+
PrologTerm atom = parseEd(atomToBeChecked + '.').next();
138+
assertEquals(ATOM, atom.getType(), "Type: " + atom.getType());
139+
assertEquals(PrologInt.class, atom.getClass(), "Class: " + atom.getClass());
140+
assertEquals(expectedNumber, ((PrologInt) atom).getNumber().longValue(), "Number: " + ((PrologInt) atom).getNumber().longValue());
141+
assertEquals(Long.toString(expectedNumber), atom.getText(), "Text: " + atom.getText());
142+
}
143+
144+
145+
146+
public static class StubContext implements ParserContext {
147+
148+
private final Map<String, OpContainer> operators;
149+
150+
public StubContext(final Map<String, OpContainer> operators) {
151+
this.operators = operators;
152+
}
153+
154+
@Override
155+
public int getMaxTokenizerBufferLength() {
156+
return 1000;
157+
}
158+
159+
@Override
160+
public int getFlags() {
161+
return FLAG_NONE;
162+
}
163+
164+
@Override
165+
public boolean hasOpStartsWith(final PrologParser source,
166+
final String operatorNameStartSubstring) {
167+
for (final String string : operators.keySet()) {
168+
if (string.startsWith(operatorNameStartSubstring)) {
169+
return true;
170+
}
171+
}
172+
173+
return false;
174+
}
175+
176+
@Override
177+
public OpContainer findOpForName(final PrologParser source,
178+
final String operatorName) {
179+
return operators.get(operatorName);
180+
}
181+
182+
}
183+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright 2019 Igor Maznitsa.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.igormaznitsa.prologparser;
17+
18+
import static com.igormaznitsa.prologparser.ParserContext.FLAG_NONE;
19+
import com.igormaznitsa.prologparser.terms.PrologInt;
20+
import com.igormaznitsa.prologparser.terms.PrologList;
21+
import com.igormaznitsa.prologparser.terms.PrologStruct;
22+
import com.igormaznitsa.prologparser.tokenizer.Op;
23+
import java.io.InputStreamReader;
24+
import static org.junit.jupiter.api.Assertions.assertEquals;
25+
import static org.junit.jupiter.api.Assertions.assertTrue;
26+
import org.junit.jupiter.api.Test;
27+
28+
class BigDataTest extends AbstractIntegrationTest {
29+
30+
@Test
31+
public void testBigSource_ClausesSplitted() {
32+
final int CLAUSES = 1000;
33+
assertEquals(CLAUSES, new GenericPrologParser(new InputStreamReader(new PrologSourceKoi7Generator(CLAUSES, true)), DefaultParserContext.of(FLAG_NONE, Op.SWI)).stream().count());
34+
}
35+
36+
@Test
37+
public void testBigSource_ClausesNotSplitted() {
38+
final int CLAUSES = 1000;
39+
assertEquals(CLAUSES, new GenericPrologParser(new InputStreamReader(new PrologSourceKoi7Generator(CLAUSES, false)), DefaultParserContext.of(FLAG_NONE, Op.SWI)).stream().count());
40+
}
41+
42+
43+
@Test
44+
void testVeryLongStructure() {
45+
final int ELEMENTS = 100_000;
46+
47+
final StringBuilder buffer = new StringBuilder(ELEMENTS);
48+
buffer.append("test(");
49+
boolean nonfirst = false;
50+
for (int i = 0; i < ELEMENTS; i++) {
51+
if (nonfirst) {
52+
buffer.append(',');
53+
} else {
54+
nonfirst = true;
55+
}
56+
buffer.append(i - 100);
57+
}
58+
buffer.append(").");
59+
60+
PrologStruct struct = (PrologStruct) parseEd(buffer.toString()).next();
61+
62+
assertEquals(ELEMENTS, struct.getArity());
63+
assertEquals("test", struct.getFunctor().getText());
64+
for (int i = 0; i < ELEMENTS; i++) {
65+
assertEquals(i - 100, ((PrologInt) struct.getTermAt(i)).getNumber().intValue());
66+
}
67+
}
68+
69+
@Test
70+
void testVeryLongList() {
71+
final int ELEMENTS = 100_000;
72+
73+
final StringBuilder buffer = new StringBuilder(ELEMENTS);
74+
75+
buffer.append('[');
76+
boolean nonFirst = false;
77+
78+
for (int i = 0; i < ELEMENTS; i++) {
79+
if (nonFirst) {
80+
buffer.append(',');
81+
} else {
82+
nonFirst = true;
83+
}
84+
buffer.append(i);
85+
}
86+
buffer.append("].");
87+
88+
PrologList list = (PrologList) parseEd(buffer.toString()).next();
89+
90+
for (int i = 0; i < ELEMENTS; i++) {
91+
final PrologInt head = (PrologInt) list.getHead();
92+
assertEquals(i, head.getNumber().intValue());
93+
list = (PrologList) list.getTail();
94+
}
95+
96+
assertTrue(list.isEmpty());
97+
}
98+
99+
}

0 commit comments

Comments
 (0)