blob: d3cbbaff5b67dd61d3d9dd2eaa83f26c7d9838c3 [file] [log] [blame]
suite('parser', function() {
var string = Parser.string;
var regex = Parser.regex;
var letter = Parser.letter;
var digit = Parser.digit;
var any = Parser.any;
var optWhitespace = Parser.optWhitespace;
var eof = Parser.eof;
var succeed = Parser.succeed;
var all = Parser.all;
test('Parser.string', function() {
var parser = string('x');
assert.equal(parser.parse('x'), 'x');
assert.throws(function() { parser.parse('y') })
});
test('Parser.regex', function() {
var parser = regex(/^[0-9]/);
assert.equal(parser.parse('1'), '1');
assert.equal(parser.parse('4'), '4');
assert.throws(function() { parser.parse('x'); });
assert.throws(function() { regex(/./) }, 'must be anchored');
});
suite('then', function() {
test('with a parser, uses the last return value', function() {
var parser = string('x').then(string('y'));
assert.equal(parser.parse('xy'), 'y');
assert.throws(function() { parser.parse('y'); });
assert.throws(function() { parser.parse('xz'); });
});
test('asserts that a parser is returned', function() {
var parser1 = letter.then(function() { return 'not a parser' });
assert.throws(function() { parser1.parse('x'); });
var parser2 = letter.then('x');
assert.throws(function() { letter.parse('xx'); });
});
test('with a function that returns a parser, continues with that parser', function() {
var piped;
var parser = string('x').then(function(x) {
piped = x;
return string('y');
});
assert.equal(parser.parse('xy'), 'y');
assert.equal(piped, 'x');
assert.throws(function() { parser.parse('x'); });
});
});
suite('map', function() {
test('with a function, pipes the value in and uses that return value', function() {
var piped;
var parser = string('x').map(function(x) {
piped = x;
return 'y';
});
assert.equal(parser.parse('x'), 'y')
assert.equal(piped, 'x');
});
});
suite('result', function() {
test('returns a constant result', function() {
var myResult = 1;
var oneParser = string('x').result(1);
assert.equal(oneParser.parse('x'), 1);
var myFn = function() {};
var fnParser = string('x').result(myFn);
assert.equal(fnParser.parse('x'), myFn);
});
});
suite('skip', function() {
test('uses the previous return value', function() {
var parser = string('x').skip(string('y'));
assert.equal(parser.parse('xy'), 'x');
assert.throws(function() { parser.parse('x'); });
});
});
suite('or', function() {
test('two parsers', function() {
var parser = string('x').or(string('y'));
assert.equal(parser.parse('x'), 'x');
assert.equal(parser.parse('y'), 'y');
assert.throws(function() { parser.parse('z') });
});
test('with then', function() {
var parser = string('\\')
.then(function() {
return string('y')
}).or(string('z'));
assert.equal(parser.parse('\\y'), 'y');
assert.equal(parser.parse('z'), 'z');
assert.throws(function() { parser.parse('\\z') });
});
});
function assertEqualArray(arr1, arr2) {
assert.equal(arr1.join(), arr2.join());
}
suite('many', function() {
test('simple case', function() {
var letters = letter.many();
assertEqualArray(letters.parse('x'), ['x']);
assertEqualArray(letters.parse('xyz'), ['x','y','z']);
assertEqualArray(letters.parse(''), []);
assert.throws(function() { letters.parse('1'); });
assert.throws(function() { letters.parse('xyz1'); });
});
test('followed by then', function() {
var parser = string('x').many().then(string('y'));
assert.equal(parser.parse('y'), 'y');
assert.equal(parser.parse('xy'), 'y');
assert.equal(parser.parse('xxxxxy'), 'y');
});
});
suite('times', function() {
test('zero case', function() {
var zeroLetters = letter.times(0);
assertEqualArray(zeroLetters.parse(''), []);
assert.throws(function() { zeroLetters.parse('x'); });
});
test('nonzero case', function() {
var threeLetters = letter.times(3);
assertEqualArray(threeLetters.parse('xyz'), ['x', 'y', 'z']);
assert.throws(function() { threeLetters.parse('xy'); });
assert.throws(function() { threeLetters.parse('xyzw'); });
var thenDigit = threeLetters.then(digit);
assert.equal(thenDigit.parse('xyz1'), '1');
assert.throws(function() { thenDigit.parse('xy1'); });
assert.throws(function() { thenDigit.parse('xyz'); });
assert.throws(function() { thenDigit.parse('xyzw'); });
});
test('with a min and max', function() {
var someLetters = letter.times(2, 4);
assertEqualArray(someLetters.parse('xy'), ['x', 'y']);
assertEqualArray(someLetters.parse('xyz'), ['x', 'y', 'z']);
assertEqualArray(someLetters.parse('xyzw'), ['x', 'y', 'z', 'w']);
assert.throws(function() { someLetters.parse('xyzwv'); });
assert.throws(function() { someLetters.parse('x'); });
var thenDigit = someLetters.then(digit);
assert.equal(thenDigit.parse('xy1'), '1');
assert.equal(thenDigit.parse('xyz1'), '1');
assert.equal(thenDigit.parse('xyzw1'), '1');
assert.throws(function() { thenDigit.parse('xy'); });
assert.throws(function() { thenDigit.parse('xyzw'); });
assert.throws(function() { thenDigit.parse('xyzwv1'); });
assert.throws(function() { thenDigit.parse('x1'); });
});
test('atLeast', function() {
var atLeastTwo = letter.atLeast(2);
assertEqualArray(atLeastTwo.parse('xy'), ['x', 'y']);
assertEqualArray(atLeastTwo.parse('xyzw'), ['x', 'y', 'z', 'w']);
assert.throws(function() { atLeastTwo.parse('x'); });
});
});
suite('fail', function() {
var fail = Parser.fail;
var succeed = Parser.succeed;
test('use Parser.fail to fail dynamically', function() {
var parser = any.then(function(ch) {
return fail('character '+ch+' not allowed');
}).or(string('x'));
assert.throws(function() { parser.parse('y'); });
assert.equal(parser.parse('x'), 'x');
});
test('use Parser.succeed or Parser.fail to branch conditionally', function() {
var allowedOperator;
var parser =
string('x')
.then(string('+').or(string('*')))
.then(function(operator) {
if (operator === allowedOperator) return succeed(operator);
else return fail('expected '+allowedOperator);
})
.skip(string('y'))
;
allowedOperator = '+';
assert.equal(parser.parse('x+y'), '+');
assert.throws(function() { parser.parse('x*y'); });
allowedOperator = '*';
assert.equal(parser.parse('x*y'), '*');
assert.throws(function() { parser.parse('x+y'); });
});
});
test('eof', function() {
var parser = optWhitespace.skip(eof).or(all.result('default'));
assert.equal(parser.parse(' '), ' ')
assert.equal(parser.parse('x'), 'default');
});
});