/
expr_eval.py
116 lines (90 loc) · 2.81 KB
/
expr_eval.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env python2
"""
expr_eval.py
"""
from __future__ import print_function
from _devbuild.gen.id_kind_asdl import Id
from _devbuild.gen.syntax_asdl import (
expr_e, oil_word_part_e
)
from _devbuild.gen.runtime_asdl import (
lvalue, value_e
)
class OilEvaluator(object):
"""Shared between arith and bool evaluators.
They both:
1. Convert strings to integers, respecting shopt -s strict_arith.
2. Look up variables and evaluate words.
"""
def __init__(self, mem, errfmt):
self.mem = mem
self.errfmt = errfmt
def ToAny(self, val):
"""Convert to a Python object so we can calculate on it natively."""
if val.tag == value_e.Undef:
# TODO: e_die with token
raise NameError('undefined')
if val.tag == value_e.Str:
return val.s
if val.tag == value_e.StrArray:
return val.strs # node: has None
if val.tag == value_e.AssocArray:
return val.d
if val.tag == value_e.Obj:
return val.obj
def EvalLHS(self, node):
if 0:
print('EvalLHS()')
node.PrettyPrint()
print('')
if node.tag == expr_e.Var:
return lvalue.LhsName(node.name.val)
else:
# TODO:
# subscripts, tuple unpacking, starred expressions, etc.
raise NotImplementedError(node.__class__.__name__)
def EvalWordPart(self, part):
"""
TODO: We might not want oil_word_part_e? Just use OSH word_part?
"""
if part.tag == oil_word_part_e.Literal:
return part.token.val
raise NotImplementedError(part.__class__.__name__)
def EvalRHS(self, node):
"""
This is a naive PyObject evaluator! It uses the type dispatch of the host
Python interpreter.
Returns:
A Python object of ANY type. Should be wrapped in value.Obj() for
storing in Mem.
"""
if 0:
print('EvalRHS()')
node.PrettyPrint()
print('')
if node.tag == expr_e.Const:
return int(node.c.val)
if node.tag == expr_e.Var:
val = self.mem.GetVar(node.name.val)
return self.ToAny(val)
if node.tag == expr_e.DoubleQuoted:
s = ''.join(self.EvalWordPart(part) for part in node.parts)
return s
if node.tag == expr_e.Binary:
left = self.EvalRHS(node.left)
right = self.EvalRHS(node.right)
if node.op.id == Id.Arith_Plus:
return left + right
if node.op.id == Id.Arith_Minus:
return left - right
if node.op.id == Id.Arith_Star:
return left * right
raise NotImplementedError(node.op.id)
if node.tag == expr_e.List:
return [self.EvalRHS(e) for e in node.elts]
if node.tag == expr_e.Subscript:
collection = self.EvalRHS(node.collection)
# TODO: handle multiple indices like a[i, j]
index = self.EvalRHS(node.indices[0])
return collection[index]
raise NotImplementedError(node.__class__.__name__)