Skip to content
This repository was archived by the owner on Mar 23, 2023. It is now read-only.

Commit 9c117f9

Browse files
author
Dylan Trotter
committed
Use unicode_literals throughout compiler code.
1 parent bd12d52 commit 9c117f9

16 files changed

Lines changed: 427 additions & 56 deletions

File tree

Makefile

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ export GOPATH := $(ROOT_DIR)/build
5353
export PYTHONPATH := $(ROOT_DIR)/$(PY_DIR)
5454
export PATH := $(ROOT_DIR)/build/bin:$(PATH)
5555

56+
PYTHONPARSER_SRCS := $(patsubst third_party/%,$(PY_DIR)/%,$(wildcard third_party/pythonparser/*.py))
57+
5658
COMPILER_BIN := build/bin/grumpc
5759
COMPILER_SRCS := $(addprefix $(PY_DIR)/grumpy/compiler/,$(notdir $(shell find compiler -name '*.py' -not -name '*_test.py'))) $(PY_DIR)/grumpy/__init__.py
5860
COMPILER_TESTS := $(patsubst %.py,grumpy/%,$(filter-out compiler/expr_visitor_test.py compiler/stmt_test.py,$(wildcard compiler/*_test.py)))
@@ -62,7 +64,7 @@ COMPILER_PASS_FILES := $(patsubst %,$(PY_DIR)/%.pass,$(COMPILER_TESTS))
6264
COMPILER_EXPR_VISITOR_PASS_FILES := $(patsubst %,$(PY_DIR)/grumpy/compiler/expr_visitor_test.%of32.pass,$(shell seq 32))
6365
COMPILER_STMT_PASS_FILES := $(patsubst %,$(PY_DIR)/grumpy/compiler/stmt_test.%of16.pass,$(shell seq 16))
6466
COMPILER_D_FILES := $(patsubst %,$(PY_DIR)/%.d,$(COMPILER_TESTS))
65-
COMPILER := $(COMPILER_BIN) $(COMPILER_SRCS)
67+
COMPILER := $(COMPILER_BIN) $(COMPILER_SRCS) $(PYTHONPARSER_SRCS)
6668

6769
RUNNER_BIN := build/bin/grumprun
6870
RUNTIME_SRCS := $(addprefix build/src/grumpy/,$(notdir $(wildcard runtime/*.go)))
@@ -73,7 +75,7 @@ RUNNER = $(RUNNER_BIN) $(COMPILER) $(RUNTIME) $(STDLIB)
7375

7476
GRUMPY_STDLIB_SRCS := $(shell find lib -name '*.py')
7577
GRUMPY_STDLIB_PACKAGES := $(foreach x,$(GRUMPY_STDLIB_SRCS),$(patsubst lib/%.py,%,$(patsubst lib/%/__init__.py,%,$(x))))
76-
THIRD_PARTY_STDLIB_SRCS := $(shell find third_party -name '*.py')
78+
THIRD_PARTY_STDLIB_SRCS := $(shell find third_party/pypy -name '*.py') $(shell find third_party/stdlib -name '*.py')
7779
THIRD_PARTY_STDLIB_PACKAGES := $(foreach x,$(THIRD_PARTY_STDLIB_SRCS),$(patsubst third_party/stdlib/%.py,%,$(patsubst third_party/pypy/%.py,%,$(patsubst third_party/pypy/%/__init__.py,%,$(patsubst third_party/stdlib/%/__init__.py,%,$(x))))))
7880
STDLIB_SRCS := $(GRUMPY_STDLIB_SRCS) $(THIRD_PARTY_STDLIB_SRCS)
7981
STDLIB_PACKAGES := $(GRUMPY_STDLIB_PACKAGES) $(THIRD_PARTY_STDLIB_PACKAGES)
@@ -148,7 +150,7 @@ $(COMPILER_PASS_FILES): %.pass: %.py $(COMPILER)
148150
@touch $@
149151
@echo compiler/`basename $*` PASS
150152

151-
$(COMPILER_D_FILES): $(PY_DIR)/%.d: $(PY_DIR)/%.py $(COMPILER_SRCS)
153+
$(COMPILER_D_FILES): $(PY_DIR)/%.d: $(PY_DIR)/%.py $(COMPILER_SRCS) $(PYTHONPARSER_SRCS)
152154
@$(PYTHON) -m modulefinder $< | awk '{if (match($$2, /^grumpy\>/)) { print "$(PY_DIR)/$*.pass: " substr($$3, length("$(ROOT_DIR)/") + 1) }}' > $@
153155

154156
-include $(COMPILER_D_FILES)
@@ -268,6 +270,10 @@ $(eval $(foreach x,$(STDLIB_TESTS),$(call GRUMPY_STDLIB_TEST,$(x))))
268270
$(PY_DIR)/weetest.py: lib/weetest.py
269271
@cp -f $< $@
270272

273+
$(PYTHONPARSER_SRCS): $(PY_DIR)/%: third_party/%
274+
@mkdir -p $(@D)
275+
@cp -f $< $@
276+
271277
$(patsubst %_test,build/%.go,$(ACCEPT_TESTS)): build/%.go: %_test.py $(COMPILER)
272278
@mkdir -p $(@D)
273279
@$(COMPILER_BIN) $< > $@

compiler/block.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@
1616

1717
"""Classes for analyzing and storing the state of Python code blocks."""
1818

19+
from __future__ import unicode_literals
20+
1921
import abc
2022
import ast
2123
import collections
2224
import re
2325

26+
from pythonparser import source
27+
2428
from grumpy.compiler import expr
2529
from grumpy.compiler import util
2630

@@ -56,7 +60,7 @@ class Block(object):
5660
_filename = None
5761
_full_package_name = None
5862
_libroot = None
59-
_lines = None
63+
_buffer = None
6064
_runtime = None
6165
_strings = None
6266
imports = None
@@ -96,8 +100,8 @@ def filename(self):
96100
return self._module_block._filename # pylint: disable=protected-access
97101

98102
@property
99-
def lines(self):
100-
return self._module_block._lines # pylint: disable=protected-access
103+
def buffer(self):
104+
return self._module_block._buffer # pylint: disable=protected-access
101105

102106
@property
103107
def strings(self):
@@ -220,14 +224,14 @@ class ModuleBlock(Block):
220224
imports: A dict mapping fully qualified Go package names to Package objects.
221225
"""
222226

223-
def __init__(self, full_package_name, runtime, libroot, filename, lines,
227+
def __init__(self, full_package_name, runtime, libroot, filename, src,
224228
future_features):
225229
super(ModuleBlock, self).__init__(None, '<module>')
226230
self._full_package_name = full_package_name
227231
self._runtime = runtime
228232
self._libroot = libroot
229233
self._filename = filename
230-
self._lines = lines
234+
self._buffer = source.Buffer(src)
231235
self._strings = set()
232236
self.imports = {}
233237
self._future_features = future_features

compiler/block_test.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
"""Tests Package, Block, BlockVisitor and related classes."""
1818

19+
from __future__ import unicode_literals
20+
1921
import ast
2022
import textwrap
2123
import unittest
@@ -106,7 +108,7 @@ def testResolveName(self):
106108
def _ResolveName(self, b, name):
107109
writer = util.Writer()
108110
b.resolve_name(writer, name)
109-
return writer.out.getvalue()
111+
return writer.getvalue()
110112

111113

112114
class BlockVisitorTest(unittest.TestCase):
@@ -243,7 +245,7 @@ def testYieldExpr(self):
243245

244246

245247
def _MakeModuleBlock():
246-
return block.ModuleBlock('__main__', 'grumpy', 'grumpy/lib', '<test>', [],
248+
return block.ModuleBlock('__main__', 'grumpy', 'grumpy/lib', '<test>', '',
247249
stmt.FutureFeatures())
248250

249251

compiler/expr.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
"""Classes representing generated expressions."""
1818

19+
from __future__ import unicode_literals
20+
1921
import abc
2022

2123
from grumpy.compiler import util

compiler/expr_visitor.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
"""Visitor class for traversing Python expressions."""
1818

19+
from __future__ import unicode_literals
20+
1921
import ast
2022
import contextlib
2123
import textwrap
@@ -462,10 +464,10 @@ def visit_function_inline(self, node):
462464
self.writer.write('return πg.NewGenerator(πF, func(πSent *πg.Object) '
463465
'(*πg.Object, *πg.BaseException) {')
464466
with self.writer.indent_block():
465-
self.writer.write_block(func_block, visitor.writer.out.getvalue())
467+
self.writer.write_block(func_block, visitor.writer.getvalue())
466468
self.writer.write('}).ToObject(), nil')
467469
else:
468-
self.writer.write_block(func_block, visitor.writer.out.getvalue())
470+
self.writer.write_block(func_block, visitor.writer.getvalue())
469471
self.writer.write('}), πF.Globals()).ToObject()')
470472
return result
471473

compiler/expr_visitor_test.py

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
"""Tests for ExprVisitor."""
1818

19+
from __future__ import unicode_literals
20+
1921
import ast
2022
import subprocess
2123
import textwrap
@@ -35,11 +37,13 @@ def Test(self):
3537
return Test
3638

3739

38-
def _MakeLiteralTest(lit):
40+
def _MakeLiteralTest(lit, expected=None):
41+
if expected is None:
42+
expected = lit
3943
def Test(self):
4044
status, output = _GrumpRun('print repr({}),'.format(lit))
4145
self.assertEqual(0, status, output)
42-
self.assertEqual(eval('repr({})'.format(lit)), output.strip()) # pylint: disable=eval-used
46+
self.assertEqual(expected, output.strip()) # pylint: disable=eval-used
4347
return Test
4448

4549

@@ -130,9 +134,9 @@ def foo(a, b=2):
130134
testCompareNotInTuple = _MakeExprTest('10 < 12 not in (1, 2, 3)')
131135

132136
testDictEmpty = _MakeLiteralTest('{}')
133-
testDictNonEmpty = _MakeLiteralTest('{"foo": 42, "bar": 43}')
137+
testDictNonEmpty = _MakeLiteralTest("{'foo': 42, 'bar': 43}")
134138

135-
testSetNoneEmpty = _MakeLiteralTest('{"foo", "bar"}')
139+
testSetNonEmpty = _MakeLiteralTest("{'foo', 'bar'}", "set(['foo', 'bar'])")
136140

137141
testDictCompFor = _MakeExprTest('{x: str(x) for x in range(3)}')
138142
testDictCompForIf = _MakeExprTest(
@@ -181,16 +185,15 @@ def foo():
181185

182186
testNumInt = _MakeLiteralTest('42')
183187
testNumLong = _MakeLiteralTest('42L')
184-
testNumIntLarge = _MakeLiteralTest('12345678901234567890')
188+
testNumIntLarge = _MakeLiteralTest('12345678901234567890',
189+
'12345678901234567890L')
185190
testNumFloat = _MakeLiteralTest('102.1')
186-
testNumFloatOnlyDecimal = _MakeLiteralTest('.5')
187-
# TODO: Current Grumpy's repr on float has different behavior than CPython.
188-
# so skip these for now.
189-
testNumFloatNoDecimal = unittest.expectedFailure(_MakeLiteralTest('5.'))
190-
testNumFloatSci = unittest.expectedFailure(_MakeLiteralTest('1e6'))
191-
testNumFloatSciCap = unittest.expectedFailure(_MakeLiteralTest('1E6'))
192-
testNumFloatSciCapPlus = unittest.expectedFailure(_MakeLiteralTest('1E+6'))
193-
testNumFloatSciMinus = _MakeLiteralTest('1e-6')
191+
testNumFloatOnlyDecimal = _MakeLiteralTest('.5', '0.5')
192+
testNumFloatNoDecimal = _MakeLiteralTest('5.', '5')
193+
testNumFloatSci = _MakeLiteralTest('1e6', '1e+06')
194+
testNumFloatSciCap = _MakeLiteralTest('1E6', '1e+06')
195+
testNumFloatSciCapPlus = _MakeLiteralTest('1E+6', '1e+06')
196+
testNumFloatSciMinus = _MakeLiteralTest('1e-06')
194197
testNumComplex = _MakeLiteralTest('3j')
195198

196199
testSubscriptDictStr = _MakeExprTest('{"foo": 42}["foo"]')
@@ -205,14 +208,14 @@ def foo():
205208
testSubscriptMultiDimSlice = _MakeSliceTest(
206209
"'foo','bar':'baz':'qux'", "('foo', slice('bar', 'baz', 'qux'))")
207210

208-
testStrEmpty = _MakeLiteralTest('""')
209-
testStrAscii = _MakeLiteralTest('"abc"')
210-
testStrUtf8 = _MakeLiteralTest(r'"\tfoo\n\xcf\x80"')
211-
testStrQuoted = _MakeLiteralTest('\'"foo"\'')
212-
testStrUtf16 = _MakeLiteralTest(r'u"\u0432\u043e\u043b\u043d"')
211+
testStrEmpty = _MakeLiteralTest("''")
212+
testStrAscii = _MakeLiteralTest("'abc'")
213+
testStrUtf8 = _MakeLiteralTest(r"'\tfoo\n\xcf\x80'")
214+
testStrQuoted = _MakeLiteralTest('\'"foo"\'', '\'"foo"\'')
215+
testStrUtf16 = _MakeLiteralTest("u'\\u0432\\u043e\\u043b\\u043d'")
213216

214-
testTupleEmpty = _MakeLiteralTest(())
215-
testTupleNonEmpty = _MakeLiteralTest((1, 2, 3))
217+
testTupleEmpty = _MakeLiteralTest('()')
218+
testTupleNonEmpty = _MakeLiteralTest('(1, 2, 3)')
216219

217220
testUnaryOpNot = _MakeExprTest('not True')
218221
testUnaryOpInvert = _MakeExprTest('~4')
@@ -223,7 +226,7 @@ def testUnaryOpNotImplemented(self):
223226

224227

225228
def _MakeModuleBlock():
226-
return block.ModuleBlock('__main__', 'grumpy', 'grumpy/lib', '<test>', [],
229+
return block.ModuleBlock('__main__', 'grumpy', 'grumpy/lib', '<test>', '',
227230
stmt.FutureFeatures())
228231

229232

@@ -235,7 +238,7 @@ def _ParseAndVisitExpr(expr):
235238
writer = util.Writer()
236239
visitor = expr_visitor.ExprVisitor(_MakeModuleBlock(), writer)
237240
visitor.visit(_ParseExpr(expr))
238-
return writer.out.getvalue()
241+
return writer.getvalue()
239242

240243

241244
def _GrumpRun(cmd):

compiler/shard_test.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
"""Wrapper for unit tests that loads a subset of all test methods."""
1616

17+
from __future__ import unicode_literals
18+
1719
import argparse
1820
import random
1921
import re

compiler/stmt.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
"""Visitor class for traversing Python statements."""
1818

19+
from __future__ import unicode_literals
20+
1921
import ast
2022
import string
2123
import textwrap
@@ -221,7 +223,7 @@ def visit_ClassDef(self, node):
221223
with self.writer.indent_block():
222224
self.writer.write_temp_decls(body_visitor.block)
223225
self.writer.write_block(body_visitor.block,
224-
body_visitor.writer.out.getvalue())
226+
body_visitor.writer.getvalue())
225227
tmpl = textwrap.dedent("""\
226228
}).Eval(πF, πF.Globals(), nil, nil)
227229
if πE != nil {
@@ -815,6 +817,6 @@ def _write_except_dispatcher(self, exc, tb, handlers):
815817

816818
def _write_py_context(self, lineno):
817819
if lineno:
818-
line = self.block.lines[lineno - 1].strip()
820+
line = self.block.buffer.source_line(lineno).strip()
819821
self.writer.write('// line {}: {}'.format(lineno, line))
820822
self.writer.write('πF.SetLineno({})'.format(lineno))

compiler/stmt_test.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
"""Tests for StatementVisitor."""
1818

19+
from __future__ import unicode_literals
20+
1921
import ast
2022
import re
2123
import subprocess
@@ -573,7 +575,7 @@ def testWriteExceptDispatcherBareExcept(self):
573575
'exc', 'tb', handlers), [1, 2])
574576
expected = re.compile(r'ResolveGlobal\(.*foo.*\bIsInstance\(.*'
575577
r'goto Label1.*goto Label2', re.DOTALL)
576-
self.assertRegexpMatches(visitor.writer.out.getvalue(), expected)
578+
self.assertRegexpMatches(visitor.writer.getvalue(), expected)
577579

578580
def testWriteExceptDispatcherBareExceptionNotLast(self):
579581
visitor = stmt.StatementVisitor(_MakeModuleBlock())
@@ -593,19 +595,19 @@ def testWriteExceptDispatcherMultipleExcept(self):
593595
r'ResolveGlobal\(.*foo.*\bif .*\bIsInstance\(.*\{.*goto Label1.*'
594596
r'ResolveGlobal\(.*bar.*\bif .*\bIsInstance\(.*\{.*goto Label2.*'
595597
r'\bRaise\(exc\.ToObject\(\), nil, tb\.ToObject\(\)\)', re.DOTALL)
596-
self.assertRegexpMatches(visitor.writer.out.getvalue(), expected)
598+
self.assertRegexpMatches(visitor.writer.getvalue(), expected)
597599

598600

599601
def _MakeModuleBlock():
600-
return block.ModuleBlock('__main__', 'grumpy', 'grumpy/lib', '<test>', [],
602+
return block.ModuleBlock('__main__', 'grumpy', 'grumpy/lib', '<test>', '',
601603
stmt.FutureFeatures())
602604

603605

604606
def _ParseAndVisit(source):
605607
mod = ast.parse(source)
606608
future_features = stmt.visit_future(mod)
607609
b = block.ModuleBlock('__main__', 'grumpy', 'grumpy/lib', '<test>',
608-
source.split('\n'), future_features)
610+
source, future_features)
609611
visitor = stmt.StatementVisitor(b)
610612
visitor.visit(mod)
611613
return visitor

compiler/util.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616

1717
"""Utilities for generating Go code."""
1818

19+
from __future__ import unicode_literals
20+
21+
import codecs
1922
import contextlib
2023
import cStringIO
2124
import string
25+
import StringIO
2226
import textwrap
2327

2428

@@ -44,9 +48,12 @@ class Writer(object):
4448
"""Utility class for writing blocks of Go code to a file-like object."""
4549

4650
def __init__(self, out=None):
47-
self.out = out or cStringIO.StringIO()
51+
self.out = codecs.getwriter('utf8')(out or cStringIO.StringIO())
4852
self.indent_level = 0
4953

54+
def getvalue(self):
55+
return self.out.getvalue().decode('utf8')
56+
5057
@contextlib.contextmanager
5158
def indent_block(self, n=1):
5259
"""A context manager that indents by n on entry and dedents on exit."""
@@ -127,7 +134,7 @@ def dedent(self, n=1):
127134

128135
def go_str(value):
129136
"""Returns value as a valid Go string literal."""
130-
io = cStringIO.StringIO()
137+
io = StringIO.StringIO()
131138
io.write('"')
132139
for c in value:
133140
if c in _ESCAPES:

0 commit comments

Comments
 (0)