diff --git a/src/slimit/tests/test_ecmavisitor.py b/src/slimit/tests/test_ecmavisitor.py index 65dfce2..be85178 100644 --- a/src/slimit/tests/test_ecmavisitor.py +++ b/src/slimit/tests/test_ecmavisitor.py @@ -500,6 +500,15 @@ def setUp(self): } }; """, + # function call on immediate number + '(0x25).toString();', + '(1e3).toString();', + '(25).toString();', + + # attribute access on immediate number + '(25).attr;', + '25["attr"];', + '0["attr"];', ] diff --git a/src/slimit/tests/test_minifier.py b/src/slimit/tests/test_minifier.py index e999335..95536d4 100644 --- a/src/slimit/tests/test_minifier.py +++ b/src/slimit/tests/test_minifier.py @@ -398,6 +398,17 @@ def assertMinified(self, source, expected): """, "(function($){$.hello='world';}(jQuery));"), + # function call on immediate number + ('(0x25).toString()', '0x25.toString();'), + ('(1e3).toString()', '1e3.toString();'), + ('((25)).toString()', '(25).toString();'), + ('((25))["toString"]()', '(25).toString();'), + + # attribute access on immediate number + ('((25)).attr', '(25).attr;'), + ('((25))["attr"]', '(25).attr;'), + ('((0))["attr"]', '(0).attr;'), + # function call in FOR init ('for(o(); i < 3; i++) {}', 'for(o();i<3;i++){}'), diff --git a/src/slimit/visitors/ecmavisitor.py b/src/slimit/visitors/ecmavisitor.py index 1c98598..cc52ce2 100644 --- a/src/slimit/visitors/ecmavisitor.py +++ b/src/slimit/visitors/ecmavisitor.py @@ -352,6 +352,8 @@ def visit_NewExpr(self, node): def visit_DotAccessor(self, node): if getattr(node, '_parens', False): template = '(%s.%s)' + elif isinstance(node.node, ast.Number): + template = '(%s).%s' else: template = '%s.%s' s = template % (self.visit(node.node), self.visit(node.identifier)) diff --git a/src/slimit/visitors/minvisitor.py b/src/slimit/visitors/minvisitor.py index 1c6fd15..b7250d0 100644 --- a/src/slimit/visitors/minvisitor.py +++ b/src/slimit/visitors/minvisitor.py @@ -30,6 +30,9 @@ from slimit.lexer import Lexer _HAS_ID_MATCH = re.compile('^%s$' % Lexer.identifier).match +# Matches all immediate numbers, which are dot accessable (expects a number as input) +_DOT_ACCESSABLE_NUMBER = re.compile('^(0.+|.+[eE].+|.+\..+)$') + def _is_identifier(value): return _HAS_ID_MATCH(value) and value not in Lexer.keywords_dict @@ -386,6 +389,8 @@ def visit_NewExpr(self, node): def visit_DotAccessor(self, node): if getattr(node, '_parens', False): template = '(%s.%s)' + elif isinstance(node.node, ast.Number) and not _DOT_ACCESSABLE_NUMBER.match(node.node.value): + template = '(%s).%s' else: template = '%s.%s' s = template % (self.visit(node.node), self.visit(node.identifier)) @@ -400,7 +405,10 @@ def visit_BracketAccessor(self, node): elif value.startswith('"'): value = value.strip('"') if _is_identifier(value): - s = '%s.%s' % (self.visit(node.node), value) + left = self.visit(node.node) + if isinstance(node.node, ast.Number) and not _DOT_ACCESSABLE_NUMBER.match(node.node.value): + left = '(%s)' % left + s = '%s.%s' % (left, value) return s s = '%s[%s]' % (self.visit(node.node), self.visit(node.expr)) @@ -434,4 +442,3 @@ def visit_Array(self, node): def visit_This(self, node): return 'this' -