Skip to content

Commit f2a45d5

Browse files
committed
Add support for filter and map, fix #3
1 parent 418fe12 commit f2a45d5

File tree

6 files changed

+96
-16
lines changed

6 files changed

+96
-16
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ A restricted Python to idiomatic JavaScript / Ruby / Go / C# translator
77

88
[Pseudo](https://github.com/alehander42/pseudo) is a framework for high level code generation: it is used by this compiler to translate a subset of Python to all Pseudo-supported languages
99

10-
**If you are using Python3.5 and you experience problems with an already installed version of pseudo-python, please upgrade it to `0.2.16` (`pip3 install pseudo-python --upgrade`)**
10+
**If you are using Python3.5 and you experience problems with an already installed version of pseudo-python, please upgrade it to `0.2.18` (`pip3 install pseudo-python --upgrade`)**
1111

1212

1313

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.2.16
1+
0.2.18

pseudo_python/api_translator.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ def len_expander(type, message, args):
134134
2: StandardMethodCall('List', 'insert_at')
135135
},
136136
'remove': StandardMethodCall('List', 'remove'),
137-
'extend': StandardMethodCall('List', 'push_many')
137+
'extend': StandardMethodCall('List', 'push_many'),
138+
'map': StandardMethodCall('List', 'map'),
139+
'filter': StandardMethodCall('List', 'filter')
138140
},
139141

140142
'Dictionary': {

pseudo_python/ast_translator.py

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434

3535
BUILTIN_FUNCTIONS = {'print', 'input', 'str', 'int', 'len', 'any', 'all', 'sum'}
3636

37+
FORBIDDEN_TOP_LEVEL_FUNCTIONS = {'map', 'filter'}
38+
3739
ITERABLE_TYPES = {'String', 'List', 'Dictionary', 'Set', 'Array'}
3840

3941
TESTABLE_TYPE = 'Boolean'
@@ -353,7 +355,62 @@ def _translate_call(self, func, args, keywords, starargs=None, kwargs=None, loca
353355
args.append(arg)
354356

355357

356-
if isinstance(func, ast.Name) and func.id in BUILTIN_FUNCTIONS:
358+
359+
if isinstance(func, ast.Name) and func.id in FORBIDDEN_TOP_LEVEL_FUNCTIONS:
360+
raise translation_error('%s supported only as list(%s)' % (func.id, func.id),
361+
location, self.lines[location[0]])
362+
elif isinstance(func, ast.Name) and func.id == 'list':
363+
if len(args) != 1 or not isinstance(args[0], ast.Call) or not isinstance(args[0].func, ast.Name) or args[0].func.id not in FORBIDDEN_TOP_LEVEL_FUNCTIONS:
364+
raise translation_error('list currently not supported',
365+
location, self.lines[location[0]],
366+
suggestions='list is currently only supported for list(filter)')
367+
if len(args[0].args) != 2:
368+
raise type_check_error('%s expects 2 arg, received %d args' % (args[0].func.id, len(args[0].args)),
369+
location, self.lines[location[0]])
370+
receiver_node = self._translate_node(args[0].args[1])
371+
if self._general_type(receiver_node['pseudo_type']) != 'List':
372+
raise type_check_error('#%s currently works only' % args[0].func.id,
373+
location, self.lines[location[0]],
374+
wrong_type=receiver_node['pseudo_type'])
375+
376+
377+
if isinstance(args[0].args[0], ast.Lambda):
378+
if len(args[0].args[0].args.args) != 1:
379+
raise translation_error('lambda expected 1 arg, received %d' % len(args[0].args[0].args.args),
380+
location, self.lines[location[0]])
381+
382+
arg_nodes = [self._translate_functional_lambda(args[0].args[0], receiver_node['pseudo_type'][1])]
383+
else:
384+
arg_nodes = [self._translate_node(args[0].args.args[0], in_call=True)]
385+
386+
if args[0].func.id == 'map':
387+
return_type = ['List', arg_nodes[0]['pseudo_type'][-1]]
388+
else:
389+
if arg_nodes[0]['pseudo_type'][-1] != 'Boolean':
390+
l = {'type': 'local', 'name': args[0].args[0].args.args[0].arg, 'pseudo_type': arg_nodes['pseudo_type'][-1]}
391+
arg_nodes[0] = {
392+
'type': 'anonymous_function',
393+
'pseudo_type': ['Function', arg_nodes['pseudo_type'][-1], 'Boolean'],
394+
'return_type': 'Boolean',
395+
'params': [l],
396+
'block': [self._testable({
397+
'type': 'call',
398+
'function': arg_nodes[0],
399+
'args': [l],
400+
'pseudo_type': arg_nodes[0]['pseudo_type'][-1]
401+
})]
402+
}
403+
404+
return_type = ['List', 'Boolean']
405+
return {
406+
'type': 'standard_method_call',
407+
'receiver': receiver_node,
408+
'message': args[0].func.id,
409+
'args': arg_nodes,
410+
'pseudo_type': return_type
411+
}
412+
413+
elif isinstance(func, ast.Name) and func.id in BUILTIN_FUNCTIONS:
357414
if func.id in ['any', 'all', 'sum']:
358415
if len(args) != 1:
359416
raise translation_error('%s expected 1 arg, not %d' % (func.id, len(args)),
@@ -527,13 +584,8 @@ def _translate_builtin_call(self, namespace, function, args, location):
527584
'pseudo-python doesn\'t support %s %s' % (namespace, function),
528585
location, self.lines[location[0]],
529586
suggestions='pseudo-python supports those %s functions\n %s' % (
530-
namespace, '\n'.join(
531-
' %s %s -> %s' % (
532-
name,
533-
' '.join(serialize_type(arg) for arg in t[:-1]),
534-
serialize_type(t[-1]))
535-
for name, t in TYPED_API['_%s' % namespace].items()).strip()))
536-
587+
namespace,
588+
prepare_table(TYPED_API[namespace], ORIGINAL_METHODS.get(namespace)).strip()))
537589

538590

539591
if not isinstance(api, dict):
@@ -1405,6 +1457,30 @@ def _translate_nameconstant(self, value, location):
14051457
elif value is None:
14061458
return {'type': 'null', 'pseudo_type': 'Void'}
14071459

1460+
def _translate_functional_lambda(self, l, arg_type):
1461+
1462+
params = [{'type': 'local', 'name': l.args.args[0].arg, 'pseudo_type': arg_type}]
1463+
self.type_env = self.type_env.child_env({l.args.args[0].arg: arg_type})
1464+
old_f, self.function_name = self.function_name, 'lambda'
1465+
node = self._translate_node(l.body)
1466+
nodes = [{
1467+
'type': 'implicit_return',
1468+
'pseudo_type': node['pseudo_type'],
1469+
'value': node
1470+
}]
1471+
self.function_name = old_f
1472+
self.type_env = self.type_env.parent
1473+
return {
1474+
'type': 'anonymous_function',
1475+
'params': params,
1476+
'block': nodes,
1477+
'pseudo_type': ['Function', arg_type, node['pseudo_type']],
1478+
'return_type': node['pseudo_type']
1479+
}
1480+
1481+
def _translate_lambda(self, body, args, location):
1482+
raise
1483+
14081484
def _translate_listcomp(self, generators, elt, location):
14091485
if isinstance(generators[0].target, ast.Name):
14101486
sketchup, env = self._translate_iter(generators[0].target, generators[0].iter)
@@ -1427,7 +1503,7 @@ def _translate_listcomp(self, generators, elt, location):
14271503
'args': [{
14281504
'type': 'anonymous_function',
14291505
'params': [sketchup['iterators']['iterator']],
1430-
'pseudo_type': ['Function', sketchup['iterators']['iterator']['pseudo_type'],
1506+
'pseudo_type': ['Function', sketchup['iterators']['iterator']['pseudo_type'],
14311507
elt['pseudo_type']],
14321508
'return_type': elt['pseudo_type'],
14331509
'block': [{

pseudo_python/builtin_typed_api.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ def xor_(l, r):
160160
# methods
161161
'global': {
162162
'exit': ['Int', 'Void'],
163-
'wat': ['Int'],
164163
'to_string': ['Any', 'String']
165164
},
166165

@@ -211,7 +210,9 @@ def xor_(l, r):
211210
'push_many': [['List', '@t'], 'Void'],
212211
'remove': ['@t', 'Void'],
213212
'length': ['Int'],
214-
'join': [['List', 'String'], 'String']
213+
'join': [['List', 'String'], 'String'],
214+
'map': [['Function', '@t', '@y'], ['List', '@y']],
215+
'filter': [['Function', '@t', 'Boolean'], ['List', '@t']]
215216
},
216217

217218
'Dictionary': {
@@ -293,7 +294,8 @@ def xor_(l, r):
293294
'push_many': 'extend(other)',
294295
'remove': 'remove',
295296
'length': 'len',
296-
'map': 'list comprehension / map'
297+
'map': 'list comprehension / map',
298+
'filter': 'list comprehension / filter'
297299
},
298300

299301
'Dictionary': {

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
setup(
44
name='pseudo-python',
5-
version='0.2.16',
5+
version='0.2.18',
66
description='a python3 to pseudo compiler',
77
author='Alexander Ivanov',
88
author_email='alehander42@gmail.com',

0 commit comments

Comments
 (0)