@masala/parser
Version:
336 lines (259 loc) • 9.89 kB
JavaScript
import Streams from '../../lib/stream/index';
import {F, C} from '../../lib/parsec/index';
import {GenLex} from "../../lib";
let value = undefined;
let accepted = undefined;
function testParser(parser, string) {
let stream = Streams.ofString(string);
let parsing = parser.parse(stream);
value = parsing.value;
accepted = parsing.isAccepted();
}
export default {
setUp: function(done) {
done();
},
'subStream is ok on string stream':function (test){
const text = 'Hello World';
const parser = F.subStream(6).then(C.string('World'));
const response = parser.parse(Streams.ofString(text));
test.ok(response.isAccepted());
test.equal(7, response.value.size()); // 6 for the stream, one for World
test.done();
},
'subStream is ok on genlex stream':function (test){
const genlex = new GenLex();
genlex.setSeparatorsParser(F.not(C.charIn('+-<>[],.')));
genlex.keywords(['+', '-', '<', '>', '[', ']', ',', '.']);
const grammar = F.subStream(4).drop().then(F.any().rep());
const parser = genlex.use(grammar);
const text = '++++ and then >>';
const response = parser.parse(Streams.ofString(text));
test.ok(response.isAccepted());
test.equal(2,response.value.size());
test.done();
},
'not parser should not eat offset':function(test){
const text = 'this is a line';
const line = text+'\n';
const eol = C.char('\n');
const parser = F.not(eol).rep();
let response = parser.parse(Streams.ofString(line));
test.ok(response.isAccepted());
test.equal(text.length, response.offset);
const withParser = F.not(eol).rep().then(eol);
response = withParser.parse(Streams.ofString(line));
test.ok(response.isAccepted());
test.equal(line.length, response.offset);
test.done();
},
'expect flatten result to be ok': function(test) {
const string = 'foobar';
// tests here
const parser = C.char('f')
.then(C.char('o'))
.then(C.char('o'))
.then(C.string('bar'))
.array();
testParser(parser, string);
test.deepEqual(value, ['f', 'o', 'o', 'bar'], 'flatten result not ok');
test.done();
},
'expect returns to be ok when empty': function(test) {
const string = 'some';
// tests here
const parser = F.any().rep().then(F.eos()).returns([]);
testParser(parser, string);
test.ok(accepted);
test.deepEqual(value, [], 'flatten result not ok');
test.done();
},
'expect startWith to start': function(test) {
const string = ' world';
const object = 'hello';
// tests here
const parser = F.startWith(object)
.then(C.string(' world'))
.then(F.eos().drop());
testParser(parser, string);
test.ok(accepted);
test.equals(value.join(''), 'hello world');
test.done();
},
'test moveUntilFast string': function(test) {
const line = Streams.ofString('soXYZso');
const combinator = F.moveUntil('XYZ');
const parser = combinator.parse(line);
const value = parser.value;
const offset = parser.offset;
test.equals(value, 'so');
test.equals(offset, 2);
test.done();
},
'test moveUntilFast string with continuation': function(test) {
const document = 'start-detect-XYZ-continues';
const line = Streams.ofString(document);
const start = C.string('start-');
const combinator = start
.drop()
.then(F.moveUntil('XYZ'))
.then(C.string('XYZ-continues').drop())
.single();
const parser = combinator.parse(line);
const value = parser.value;
const offset = parser.offset;
test.equals(value, 'detect-');
test.equals(offset, document.length);
test.done();
},
'test moveUntilFast array of string with continuation': function(test) {
const document = 'start-detect-XYZ-continues';
const line = Streams.ofString(document);
const start = C.string('start-');
const combinator = start
.drop()
.then(F.moveUntil(['ABC', 'ZE', 'XYZ']))
.then(C.string('XYZ-continues').drop())
.single();
const parser = combinator.parse(line);
const value = parser.value;
const offset = parser.offset;
test.equals(value, 'detect-');
test.equals(offset, document.length);
test.done();
},
'test moveUntilFast string fails': function(test) {
const document = 'start-detect-XYZ-continues';
const line = Streams.ofString(document);
const start = C.string('start-');
const combinator = start
.drop()
.then(F.moveUntil('EEE'))
.then(C.string('XYZ-continues').drop());
const parsing = combinator.parse(line);
test.ok(!parsing.isAccepted());
test.done();
},
'test moveUntilFast array of string fails': function(test) {
const document = 'start-detect-XYZ-continues';
const line = Streams.ofString(document);
const start = C.string('start-');
const combinator = start
.drop()
.then(F.moveUntil(['ABC', 'ZE', 'EEE']))
.then(C.string('XYZ-continues').drop());
const parsing = combinator.parse(line);
test.ok(!parsing.isAccepted());
test.done();
},
'test moveUntilFast fails if array stream': function(test) {
const document = ['More', 'XYZ'];
const line = Streams.ofArray(document);
const combinator = F.moveUntil(['ABC', 'ZE', 'XYZ']);
let found = false;
try {
combinator.parse(line);
} catch (e) {
if (e === 'Input source must be a String') {
found = true;
}
}
test.ok(found);
test.done();
},
'test moveUntilFastString fails if array stream': function(test) {
const document = ['More', 'XYZ'];
const line = Streams.ofArray(document);
const combinator = F.moveUntil('XYZ');
let found = false;
try {
combinator.parse(line);
} catch (e) {
if (e === 'Input source must be a String') {
found = true;
}
}
test.ok(found);
test.done();
},
'test moveUntil': function(test) {
const line = Streams.ofString('I write until James appears');
const combinator = F.moveUntil(C.string('James')).then(F.any().drop()).single();
const value = combinator.parse(line).value;
test.equals(value, 'I write until ');
test.done();
},
'test moveUntil Not found': function(test) {
const line = Streams.ofString('I write until James appears');
const combinator = F.moveUntil(C.string('Indiana'))
.then(C.string('I'))
.then(F.any().drop());
const accepted = combinator.parse(line).isAccepted();
test.ok(!accepted);
test.done();
},
'test moveUntil found with failing parser': function(test) {
const line = Streams.ofString('I write until James Bond appears');
const combinator = F.moveUntil(C.string('James')).then(F.dropTo(F.eos()));
const accepted = combinator.parse(line).isAccepted();
test.ok(!accepted);
test.done();
},
'test dropTo with string': function(test) {
const line = Streams.ofString('I write until James Bond appears');
const combinator = F.dropTo('James')
.then(C.string(' Bond appears'))
.then(F.eos());
const accepted = combinator.parse(line).isAccepted();
test.ok(accepted);
test.done();
},
'test dropTo with string fail': function(test) {
const line = Streams.ofString('I write until James Bond appears');
const combinator = F.dropTo('James')
.then(C.string(' Bond appears'))
.then(F.eos());
const accepted = combinator.parse(line).isAccepted();
test.ok(accepted);
test.done();
},
'test dropTo with parser': function(test) {
const line = Streams.ofString('I write until James Bond appears');
const combinator = F.dropTo(C.string('James'))
.then(C.string(' Bond appears'))
.then(F.eos());
const accepted = combinator.parse(line).isAccepted();
test.ok(accepted);
test.done();
},
'test moveUntil found with more parsers': function(test) {
const line = Streams.ofString('I write until James Bond appears');
const combinator = F.moveUntil(C.string('James'))
.then(F.dropTo('appears'))
.then(F.eos().drop())
.single();
const value = combinator.parse(line).value;
test.equals(value, 'I write until ');
test.done();
},
'lazy with a class': function(test) {
class SomeLazyParser {
constructor(char) {
this.char = char;
}
first() {
return C.char(this.char).then(
this.second().opt().map(opt => opt.orElse(''))
);
}
second() {
return C.char('b').then(F.lazy(this.first, ['a'], this));
}
}
const line = Streams.ofString('ababa');
const combinator = new SomeLazyParser('a').first().then(F.eos().drop());
const value = combinator.parse(line).value;
test.equals(value.join(''), 'ababa');
test.done();
},
};