diff --git a/src/jasinta.py b/src/jasinta.py --- a/src/jasinta.py +++ b/src/jasinta.py @@ -1,4 +1,4 @@ -from std import lib as stdlib, Number +from std import lib as stdlib, Number, String class Undefined: @@ -12,6 +12,9 @@ def evaluate(node, context): node_type = node["type"] # retrieve an already existing object from the context if node_type == "Identifier": + if hasattr(context[-1], node["name"]): + return getattr(context[-1], node["name"]) + for ctx in reversed(context): if node["name"] in ctx: return ctx[node["name"]] @@ -68,7 +71,10 @@ class AssignmentExpression: def eval(self, context): left = evaluate(self.node["left"], context) right = evaluate(self.node["right"], context) - if self.node["operator"] == "+=": + op = self.node["operator"] + if op == "=": + left.val = right.val + elif op == "+=": left.val += right.val else: raise NotImplementedError @@ -84,7 +90,7 @@ class BinaryExpression: # in fact this doesn't follow JavaScript "+" semantics if self.node["operator"] == "+": - return Number(left.val+right.val) + return left+right else: raise NotImplementedError @@ -133,7 +139,7 @@ class Literal: else: return Number(val) else: - raise NotImplementedError + return String(val) node_index = {cls.__name__: cls for cls in [ diff --git a/src/std.py b/src/std.py --- a/src/std.py +++ b/src/std.py @@ -2,7 +2,45 @@ class Number: def __init__(self, x): self.val = x + def __add__(self, other): + return Number(self.val+other.val) + + +class String: + def __init__(self, s): + self.val = s + + @staticmethod + def fromCharCode(x): + return String(chr(x.val)) + + def __add__(self, other): + return String(self.val+other.val) + + def charAt(self, i=None): + i = (i or Number(0)).val + + if 0 <= i < len(self.val): + return String(self.val[i]) + else: + return String("") + + def substr(self, start=None, length=None): + start = (start or Number(0)).val + length = length.val if length is not None else len(self.val) + + if length < 0: + return String("") + + return String(self.val[start:start+length]) + + def slice(self, start=None, end=None): + start = (start or Number(0)).val + end = end.val if end is not None else None + return String(self.val[start:end]) + lib = { + "String": String, "document": {"write": lambda x: print(x.val)} } diff --git a/tests/test_jasinta.py b/tests/test_jasinta.py --- a/tests/test_jasinta.py +++ b/tests/test_jasinta.py @@ -6,9 +6,9 @@ from pyjsparser import parse from jasinta import interpret -class TestBasicAddition(TestCase): +class TestBasics(TestCase): @patch("builtins.print") - def test_interpret(self, mock_print): + def test_addition(self, mock_print): s = """var a=3; var b=1; var c=a+b; @@ -17,10 +17,8 @@ document.write(c);""" interpret(parse(s)) mock_print.assert_called_with(4) - -class TestAssignment(TestCase): @patch("builtins.print") - def test_interpret(self, mock_print): + def test_assignment(self, mock_print): s = """var a=1; var b=1; a+=b; @@ -29,3 +27,18 @@ document.write(b);""" interpret(parse(s)) mock_print.assert_called_with(3) + + +class TestString(TestCase): + @patch("builtins.print") + def test_assignment(self, mock_print): + s = """var s = "abcdefgh"; +var a = s.charAt(0); +var bcd = s.slice(1, 4); +var efg = s.substr(4, 3); +var h = String.fromCharCode(104); +document.cookie = a+bcd+efg+h; +document.write(document.cookie);""" + + interpret(parse(s)) + mock_print.assert_called_with("abcdefgh")