UNPKG

jsleri

Version:

A JavaScript Left-right parser

381 lines (311 loc) 12.3 kB
import assert from 'assert'; import { version, noop, Keyword, Regex, Token, Tokens, Sequence, Choice, Repeat, List, Optional, Ref, Prio, THIS, Grammar, EOS } from './jsleri'; class JsonGrammar extends Grammar { static START = Ref(Choice); static r_string = Regex('^(")(?:(?=(\\\\?))\\2.)*?\\1'); static r_float = Regex('^-?[0-9]+\\.?[0-9]+'); static r_integer = Regex('^-?[0-9]+'); static k_true = Keyword('true'); static k_false = Keyword('false'); static k_null = Keyword('null'); static json_map_item = Sequence( JsonGrammar.r_string, Token(':'), JsonGrammar.START ); static json_map = Sequence( Token('{'), List(JsonGrammar.json_map_item, Token(','), 0, undefined, false), Token('}') ); static json_array = Sequence( Token('['), List(JsonGrammar.START, Token(','), 0, undefined, false), Token(']') ); constructor() { super(JsonGrammar.START, '^\\w+'); JsonGrammar.START.set(Choice( JsonGrammar.r_string, JsonGrammar.r_float, JsonGrammar.r_integer, JsonGrammar.k_true, JsonGrammar.k_false, JsonGrammar.k_null, JsonGrammar.json_map, JsonGrammar.json_array )); } } describe('Test version string', () => { it('should return a version string', () => { assert.equal(typeof version, 'string'); // Only test when using import from ./dist/jsleri // assert.equal(version, '1.1.4'); }); }); describe('Test Keyword', () => { it('should parse `Keyword` as expected', () => { let hi = Keyword('hi'); let grammar = Grammar(hi); // assert statements assert.equal(Keyword, hi.constructor); assert.equal(false, hi.ignCase); assert.equal(true, grammar.parse('hi').isValid); assert.equal(true, grammar.parse(' hi ').isValid); assert.equal(false, grammar.parse('Hi').isValid); assert.equal(false, grammar.parse('hello').isValid); assert.deepEqual([], grammar.parse('hi').expecting); assert.deepEqual([hi], grammar.parse('').expecting); assert.deepEqual([EOS], grammar.parse('hi!').expecting); }); it('should parse `Keyword` (ignCase) as expected', () => { let hi = Keyword('hi', true); let grammar = Grammar(hi); // assert statements assert.equal(true, hi.ignCase); assert.equal(true, grammar.parse('hi').isValid); assert.equal(true, grammar.parse('Hi').isValid); assert.equal(false, grammar.parse('').isValid); }); }); describe('Test Sequence', () => { it('should parse `Sequence` as expected', () => { let hi = Keyword('hi', true); let iris = Keyword('iris', true); let seq = Sequence(hi, iris); let grammar = Grammar(seq); // assert statements assert.equal(Sequence, seq.constructor); assert.equal(true, grammar.parse('hi iris').isValid); assert.equal(false, grammar.parse('hi sasha').isValid); }); }); describe('Test Choice', () => { it('should parse `Choice` as expected', () => { let hi = Keyword('hi'); let iris = Keyword('iris'); let seq = Sequence(hi, iris); let choice = Choice(hi, seq); let grammar = Grammar(choice); // assert statements assert.equal(Choice, choice.constructor); assert.equal(true, grammar.parse('hi').isValid); assert.equal(true, grammar.parse('hi iris').isValid); assert.equal(false, grammar.parse('hi sasha').isValid); }); }); describe('Test Optional', () => { it('should parse `Optional` as expected', () => { let hi = Keyword('hi'); let optional = Optional(hi); let grammar = Grammar(optional); // assert statements assert.equal(Optional, optional.constructor); assert.equal(true, grammar.parse('hi').isValid); assert.equal(true, grammar.parse('').isValid); assert.equal(false, grammar.parse('hello').isValid); assert.equal(0, grammar.parse('').pos); assert.deepEqual([hi, EOS], grammar.parse('x').expecting); }); }); describe('Test Token', () => { it('should parse `Token` with single char as expected', () => { let dot = Token('.'); let grammar = Grammar(dot); // assert statements assert.equal(Token, dot.constructor); assert.equal(true, grammar.parse('.').isValid); assert.equal(false, grammar.parse('..').isValid); assert.equal(false, grammar.parse('').isValid); }); it('should parse `Token` with multiple chars as expected', () => { let not = Token('!='); let grammar = Grammar(not); // assert statements assert.equal(true, grammar.parse(' != ').isValid); assert.equal(false, grammar.parse('!').isValid); }); }); describe('Test List', () => { it('should parse `List` with default options as expected', () => { let hi = Keyword('hi'); let list = List(hi); let grammar = Grammar(list); // assert statements assert.equal(List, list.constructor); assert.equal(0, list.min); assert.equal(null, list.max); assert.equal(false, list.opt); assert.equal(true, grammar.parse('hi, hi, hi').isValid); assert.equal(true, grammar.parse('hi').isValid); assert.equal(true, grammar.parse('').isValid); assert.equal(false, grammar.parse('hi,').isValid); }); it('should parse `List` with alternative options as expected', () => { let hi = Keyword('hi'); let list = List(hi, '-', 1, 3, true); let grammar = Grammar(list); // assert statements assert.equal(1, list.min); assert.equal(3, list.max); assert.equal(true, list.opt); assert.equal(true, grammar.parse('hi - hi - hi').isValid); assert.equal(true, grammar.parse('hi-hi-hi-').isValid); assert.equal(true, grammar.parse('hi').isValid); assert.equal(false, grammar.parse('').isValid); assert.equal(false, grammar.parse('-').isValid); assert.equal(false, grammar.parse('hi-hi-hi-hi').isValid); }); }); describe('Test Repeat', () => { it('should parse `Repeat` with default options as expected', () => { let hi = Keyword('hi'); let repeat = Repeat(hi); let grammar = Grammar(repeat); // assert statements assert.equal(Repeat, repeat.constructor); assert.equal(0, repeat.min); assert.equal(null, repeat.max); assert.equal(true, grammar.parse('hi hi hi').isValid); assert.equal(true, grammar.parse('hi').isValid); assert.equal(true, grammar.parse('').isValid); assert.equal(false, grammar.parse('hihi').isValid); assert.equal(false, grammar.parse('ha').isValid); }); it('should parse `Repeat` with alternative options as expected', () => { let hi = Keyword('hi'); let repeat = Repeat(hi, 1, 3); let grammar = Grammar(repeat); // assert statements assert.equal(1, repeat.min); assert.equal(3, repeat.max); assert.equal(true, grammar.parse('hi hi hi').isValid); assert.equal(true, grammar.parse('hi').isValid); assert.equal(false, grammar.parse('').isValid); assert.equal(false, grammar.parse('hi hi hi hi').isValid); }); }); describe('Test Tokens', () => { it('should parse `Tokens` as expected', () => { let tokens = Tokens('== != >= <= > < '); let grammar = Grammar(tokens); // assert statements assert.equal(Tokens, tokens.constructor); assert.equal(true, grammar.parse('==').isValid); assert.equal(true, grammar.parse('<=').isValid); assert.equal(true, grammar.parse('>').isValid); assert.equal(false, grammar.parse('').isValid); assert.equal(false, grammar.parse('=').isValid); assert.deepEqual(['==', '!=', '>=', '<=', '>', '<'], tokens.tokens); }); }); describe('Test Regex', () => { it('should parse `Regex` as expected', () => { let pattern = '(/[^/\\\\]*(?:\\\\.[^/\\\\]*)*/i?)'; let regex = Regex(pattern); let grammar = Grammar(regex); // assert statements assert.equal(Regex, regex.constructor); assert.equal(true, grammar.parse('/hi/').isValid); assert.equal(true, grammar.parse('/hi/i').isValid); assert.equal(true, grammar.parse(' //i ').isValid); assert.equal(false, grammar.parse('x//i ').isValid); assert.equal(false, grammar.parse('//x').isValid); assert.equal(false, grammar.parse('').isValid); assert.equal(false, grammar.parse('/').isValid); assert.equal(false, grammar.parse('///').isValid); assert.equal(pattern, regex.re); }); }); describe('Test Ref', () => { it('should parse `Ref` as expected', () => { let ref = Ref(Keyword); let hi = Keyword('hi'); let grammar = Grammar(ref); ref.set(hi); // assert statements assert.equal(Keyword, ref.constructor); assert.equal(true, grammar.parse('hi').isValid); assert.equal(false, grammar.parse('').isValid); }); }); describe('Test Prio', () => { it('should parse `Prio` as expected', () => { let prio = Prio( Keyword('hi'), Keyword('bye'), Sequence('(', THIS, ')'), Sequence(THIS, Keyword('or'), THIS), Sequence(THIS, Keyword('and'), THIS) ); let grammar = Grammar(prio); // assert statements assert.equal(Prio, prio.element.constructor); assert.equal(true, grammar.parse('hi').isValid); assert.equal(true, grammar.parse('(bye)').isValid); assert.equal(true, grammar.parse('(hi and bye)').isValid); assert.equal(true, grammar.parse('(hi or hi) and (hi or hi)').isValid); assert.equal(true, grammar.parse('(hi or (hi and bye))').isValid); assert.equal(false, grammar.parse('').isValid); assert.equal(false, grammar.parse('(hi').isValid); assert.equal(false, grammar.parse('()').isValid); assert.equal(false, grammar.parse('(hi or hi) and').isValid); }); }); describe('Test JsonGrammar', () => { it('should successfully initialize JsonGrammar', () => { let jsonGrammar = new JsonGrammar(); assert.equal(typeof jsonGrammar.parse, 'function'); }); it('should parse json', () => { let jsonGrammar = new JsonGrammar(); assert.equal(true, jsonGrammar.parse('{"json": [1, 2, 3]}').isValid); }); it('should parse invalid json', () => { let jsonGrammar = new JsonGrammar(); assert.equal(false, jsonGrammar.parse('{"json": [1, 2, 3]').isValid); }); }); describe('Test Names', () => { it('should set names to the elements', () => { class TestGrammar extends Grammar { static kwHi = Keyword('Hi'); static kwJsleri = Keyword('Jsleri') static START = Sequence(this.kwHi, this.kwJsleri); } let testGrammar = new TestGrammar(); let res = testGrammar.parse('Hi Jsleri'); assert.equal(res.tree.children[0].element.name, 'START'); assert.equal(res.tree.children[0].children[0].element.name, 'kwHi'); assert.equal(res.tree.children[0].children[1].element.name, 'kwJsleri'); }); it('should set names when a simple object is used', () => { let testGrammar = {}; testGrammar.kwHi = Keyword('Hi'); testGrammar.kwJsleri = Keyword('Jsleri') testGrammar.START = Sequence(testGrammar.kwHi, testGrammar.kwJsleri); testGrammar = new Grammar(testGrammar); let res = testGrammar.parse('Hi Jsleri'); assert.equal(res.tree.children[0].element.name, 'START'); assert.equal(res.tree.children[0].children[0].element.name, 'kwHi'); assert.equal(res.tree.children[0].children[1].element.name, 'kwJsleri'); }); });