2016-12-15 17:28:24 -08:00
|
|
|
"""
|
|
|
|
Simple JavaScript/ECMAScript object literal reader
|
2014-06-07 20:04:16 -07:00
|
|
|
Only supports object literals wrapped in `var x = ...;` statements, so you
|
|
|
|
might want to do read_js_object('var x = %s;' % literal) if it's in another format.
|
2013-04-29 23:56:32 -07:00
|
|
|
|
2014-06-07 20:04:16 -07:00
|
|
|
Requires the slimit <https://github.com/rspivak/slimit> library for parsing.
|
2013-04-29 23:56:32 -07:00
|
|
|
|
2014-06-07 20:04:16 -07:00
|
|
|
Basic constand folding on strings and numbers is done, e.g. "hi " + "there!" reduces to "hi there!",
|
|
|
|
and 1+1 reduces to 2.
|
2013-04-29 23:56:32 -07:00
|
|
|
|
2014-06-07 20:04:16 -07:00
|
|
|
Copyright (c) 2013 darkf
|
|
|
|
Licensed under the terms of the WTFPL:
|
2013-04-29 23:56:32 -07:00
|
|
|
|
2014-06-07 20:04:16 -07:00
|
|
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
|
|
Version 2, December 2004
|
2016-12-15 17:28:24 -08:00
|
|
|
|
2014-06-07 20:04:16 -07:00
|
|
|
Everyone is permitted to copy and distribute verbatim or modified
|
|
|
|
copies of this license document, and changing it is allowed as long
|
|
|
|
as the name is changed.
|
2016-12-15 17:28:24 -08:00
|
|
|
|
2014-06-07 20:04:16 -07:00
|
|
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
|
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
2016-12-15 17:28:24 -08:00
|
|
|
|
2014-06-07 20:04:16 -07:00
|
|
|
0. You just DO WHAT THE FUCK YOU WANT TO.
|
2013-04-29 23:56:32 -07:00
|
|
|
"""
|
|
|
|
|
|
|
|
from slimit.parser import Parser
|
|
|
|
import slimit.ast as ast
|
|
|
|
|
2014-06-07 20:04:16 -07:00
|
|
|
|
2013-04-29 23:56:32 -07:00
|
|
|
def read_js_object(code):
|
2016-12-15 17:28:24 -08:00
|
|
|
parser = Parser()
|
|
|
|
|
2014-06-07 20:04:16 -07:00
|
|
|
def visit(node):
|
|
|
|
if isinstance(node, ast.Program):
|
|
|
|
d = {}
|
|
|
|
for child in node:
|
|
|
|
if not isinstance(child, ast.VarStatement):
|
|
|
|
raise ValueError("All statements should be var statements")
|
|
|
|
key, val = visit(child)
|
|
|
|
d[key] = val
|
|
|
|
return d
|
|
|
|
elif isinstance(node, ast.VarStatement):
|
|
|
|
return visit(node.children()[0])
|
|
|
|
elif isinstance(node, ast.VarDecl):
|
2016-12-15 17:28:24 -08:00
|
|
|
return visit(node.identifier), visit(node.initializer)
|
2014-06-07 20:04:16 -07:00
|
|
|
elif isinstance(node, ast.Object):
|
|
|
|
d = {}
|
|
|
|
for property in node:
|
|
|
|
key = visit(property.left)
|
|
|
|
value = visit(property.right)
|
|
|
|
d[key] = value
|
|
|
|
return d
|
|
|
|
elif isinstance(node, ast.BinOp):
|
|
|
|
# simple constant folding
|
|
|
|
if node.op == '+':
|
|
|
|
if isinstance(node.left, ast.String) and isinstance(node.right, ast.String):
|
|
|
|
return visit(node.left) + visit(node.right)
|
|
|
|
elif isinstance(node.left, ast.Number) and isinstance(node.right, ast.Number):
|
|
|
|
return visit(node.left) + visit(node.right)
|
|
|
|
else:
|
|
|
|
raise ValueError("Cannot + on anything other than two literals")
|
|
|
|
else:
|
2016-12-15 17:28:24 -08:00
|
|
|
raise ValueError("Cannot do operator '{}'".format(node.op))
|
2013-04-29 23:56:32 -07:00
|
|
|
|
2014-06-07 20:04:16 -07:00
|
|
|
elif isinstance(node, ast.String):
|
|
|
|
return node.value.strip('"').strip("'")
|
|
|
|
elif isinstance(node, ast.Array):
|
|
|
|
return [visit(x) for x in node]
|
2016-12-15 17:28:24 -08:00
|
|
|
elif isinstance(node, ast.Number) or isinstance(node, ast.Identifier)\
|
|
|
|
or isinstance(node, ast.Boolean) or isinstance(node, ast.Null):
|
2014-06-07 20:04:16 -07:00
|
|
|
return node.value
|
|
|
|
else:
|
2016-12-15 17:28:24 -08:00
|
|
|
raise Exception("Unhandled node: {}".format(node))
|
|
|
|
|
|
|
|
return visit(parser.parse(code))
|
|
|
|
|
2013-04-29 23:56:32 -07:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2016-12-15 17:28:24 -08:00
|
|
|
print(read_js_object("""var foo = {x: 10, y: "hi " + "there!"};
|
|
|
|
var bar = {derp: ["herp", "it", "up", "forever"]};"""))
|