Last active
August 29, 2015 14:25
-
-
Save mbildner/9a069acfb59cf99f3076 to your computer and use it in GitHub Desktop.
a super simple parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var ACCESS_REGEX = /[\[\]\.]/; | |
var BOOLEAN_REGEX = /^(true|false)$/; | |
var NUMBER_REGEX = /^[+-]?(\d*\.)?\d+$/; | |
var DOUBLE_QUOTE_REGEX = /^".*"$/; | |
var SINGLE_QUOTE_REGEX = /^'.*'$/; | |
var NULL_REGEX = /^null$/; | |
function getType (str) { | |
if (BOOLEAN_REGEX.test(str)) { | |
return 'boolean'; | |
} | |
if (NUMBER_REGEX.test(str)) { | |
return 'number'; | |
} | |
if (DOUBLE_QUOTE_REGEX.test(str) || SINGLE_QUOTE_REGEX.test(str)) { | |
return 'string'; | |
} | |
if (NULL_REGEX.test(str)) { | |
return 'null'; | |
} | |
return 'variable'; | |
} | |
function extractVal (token) { | |
switch (token.type) { | |
case 'boolean': | |
return { | |
'true': true, | |
'false': false | |
}[token.val]; | |
case 'number': | |
return +token.val; | |
case 'null': | |
return null; | |
case 'string': | |
return token.val.slice(1, -1); | |
} | |
} | |
function Tokenizer (){ | |
this.accessors = []; | |
var collector = []; | |
this.consumeToken = function(){ | |
var token = {}; | |
var str = collector.splice(0, collector.length).join(''); | |
token.val = str; | |
token.repr = str; | |
token.type = getType(token.val); | |
token.finished = !ACCESS_REGEX.test(token.val); | |
if (token.val.length) { | |
this.accessors.push(token); | |
} | |
}; | |
this.finish = function(){ | |
if (collector.length) { | |
this.consumeToken(); | |
} | |
}; | |
this.addChar = function(c){ | |
collector.push(c); | |
}; | |
} | |
function Parser (scope){ | |
this.parse = function (str){ | |
return normalizeAccess(str); | |
}; | |
this.eval = function(str){ | |
var accessors = normalizeAccess(str); | |
return evaluate(accessors, scope); | |
}; | |
this.log = function(str){ | |
console.log(this.eval(str)); | |
}; | |
function normalizeAccess (str) { | |
var tokenizer = new Tokenizer(); | |
function insideBrackets (){ | |
return openBracketCount > closeBracketCount; | |
} | |
var i, | |
c, | |
accessors = [], | |
openBracketCount = 0, | |
closeBracketCount = 0; | |
for (i=0; i<str.length; i++) { | |
c = str.charAt(i); | |
switch(c) { | |
case '.': | |
insideBrackets() ? tokenizer.addChar(c) : tokenizer.finish(); | |
break; | |
case '[': | |
insideBrackets() ? tokenizer.addChar(c) : tokenizer.finish(); | |
openBracketCount++; | |
break; | |
case ']': | |
closeBracketCount++; | |
insideBrackets() ? tokenizer.addChar(c) : tokenizer.finish(); | |
break; | |
default: | |
tokenizer.addChar(c); | |
break; | |
} | |
if (openBracketCount === closeBracketCount) { | |
openBracketCount = closeBracketCount = 0; | |
} | |
} | |
tokenizer.finish(); | |
return tokenizer.accessors.map(function(token){ | |
if (!token.finished) { | |
token.val = normalizeAccess(token.val); | |
} | |
return token; | |
}); | |
} | |
function isPrimitive (token) { | |
return token.type !== 'variable'; | |
} | |
function evaluate (tree, scope) { | |
if (isPrimitive(tree[0])) { | |
return extractVal(tree[0]); | |
} | |
return tree.reduce(function(accum, current){ | |
return Array.isArray(current.val) | |
? accum[evaluate(current.val, scope)] | |
: accum[current.val]; | |
}, scope); | |
} | |
} | |
var companies = { | |
41: { | |
name: 'pivotal labs' | |
} | |
}; | |
var users = [{ | |
first: 'moshe', | |
last: 'bildner', | |
company_id: 41 | |
}]; | |
var scope = { | |
users: users, | |
companies: companies, | |
}; | |
var demo = companies[users[0].company_id].name; | |
var demoString = 'companies[users[0].company_id].name'; | |
var parser = new Parser(scope); | |
console.log(parser.eval(demoString) === 'pivotal labs'); | |
console.log(parser.eval('"moshe bildner"') === 'moshe bildner'); | |
console.log(parser.eval("'moshe bildner'") === 'moshe bildner'); | |
console.log(parser.eval('true') === true); | |
console.log(parser.eval('null') === null); | |
console.log(parser.parse(demoString)); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment