-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProject.py
More file actions
195 lines (174 loc) · 7.02 KB
/
Copy pathProject.py
File metadata and controls
195 lines (174 loc) · 7.02 KB
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
from SnapBlocks import *
from Block import Script
from typing import Any
import random
import math
class Project:
def __init__(self):
self.globalVariables = {}
self.executor = Executor(self)
self.scripts = []
def addGlobalVariable(self, variableName):
if variableName not in self.globalVariables:
self.globalVariables[variableName] = None
else:
raise ValueError(f'{variableName} already exists as a global variable!')
def setGlobalVariable(self, variableName, value):
if variableName not in self.globalVariables:
raise ValueError(f'{variableName} is not a global variable')
else:
self.globalVariables[variableName] = value
def getGlobalVariable(self, variableName : str):
if variableName not in self.globalVariables:
raise ValueError(f'{variableName} is not defined!')
else:
return self.globalVariables[variableName]
def evaluate(self, block : Block):
return self.executor.evaluate(block)
class Executor:
'''
Class that handles the execution of scripts
in Snap. The 'how' so to speak.
'''
def __init__(self, project):
self.project = project
def execute(self, block : Block, scope : {} = None):
self.handleVariables(block, scope)
def evaluate(self, value : Block, scope : {} = None):
if scope == None:
scope = self.project.globalVariables
if type(value) == Option:
return value.text
if type(value) == Variable:
variableName = value.name
# Check local scope first
if variableName in scope:
return scope[variableName]
else:
return self.project.getGlobalVariable(variableName)
elif type(value) == Block:
# and this one too.
if isOperator(value):
return self.handleOperator(value)
else:
return value
def handleOperator(self, block : Block):
signature = block.signature
inputs = [self.evaluate(inp) for inp in block.inputs]
if signature == 'reportSum':
return inputs[0] + inputs[1]
elif signature == 'reportDiff':
return inputs[0] - inputs[1]
elif signature == 'reportProduct':
return inputs[0] * inputs[1]
elif signature == 'reportQuotient':
return inputs[0] / inputs[1]
elif signature == 'reportPower':
return inputs[0] ** inputs[1]
elif signature == 'reportModulus':
return inputs[0] % inputs[1]
elif signature == 'reportRound':
return round(inputs[0])
elif signature == 'reportMonadic':
return self.handleMonadic(block)
elif signature == 'reportRandom':
start = inputs[0]
stop = inputs[1]
if type(start) == int and type(stop) == int:
return random.randint(start, stop)
else:
return random.uniform(start, stop)
elif signature == 'reportLessThan':
return inputs[0] < inputs[1]
elif signature == 'reportEquals':
return inputs[0] == inputs[1]
elif signature == 'reportGreaterThan':
return inputs[0] > inputs[1]
elif signature == 'reportAnd':
return inputs[0] and inputs[1]
elif signature == 'reportOr':
return inputs[0] or inputs[1]
elif signature == 'reportNot':
return not inputs[0]
elif signature == 'reportBoolean':
return bool(inputs[0])
elif signature == 'reportJoinWords':
return ''.join(inputs)
elif signature == 'reportTextSplit':
return inputs[0].split(inputs[1])
else:
raise ValueError(f'{signature} is not an operator!')
def handleMonadic(self, block : Block):
operatorType = block.inputs[0].text
operand = block.inputs[1]
if operatorType == 'abs':
return abs(operand)
elif operatorType == 'neg':
return -1 * operand
elif operatorType == 'ceiling':
return math.ceil(operand)
elif operatorType == 'floor':
return math.floor(operand)
elif operatorType == 'sqrt':
return math.sqrt(operand)
elif operatorType == 'sin':
return math.sin(operand)
elif operatorType == 'cos':
return math.cos(operand)
elif operatorType == 'tan':
return math.tan(operand)
elif operatorType == 'asin':
return math.asin(operand)
elif operatorType == 'acos':
return math.acos(operand)
elif operatorType == 'atan':
return math.atan(operand)
elif operatorType == 'ln':
return math.log(operand)
elif operatorType == 'log':
return math.log10(operand)
elif operatorType == 'lg':
return math.log(operand, 2)
elif operatorType == 'e^':
return math.e ** operand
elif operatorType == '10^':
return 10 ** operand
elif operatorType == '2^':
return 2 ** operand
elif operatorType == 'id':
return operand
else:
raise ValueError(f'Error! {operatorType} is not a monadic function.')
def handleVariables(self, block : Block, scope : {}):
if block.signature == 'doSetVar':
# get the var name and value; evaluate both
variableName = self.evaluate(block.inputs[0])
value = self.evaluate(block.inputs[1], scope)
if self.varExistsLocally(variableName, scope):
scope[variableName] = value
else:
self.project.setGlobalVariable(variableName, value)
if block.signature == 'doDeclareVariables':
variableNames = [self.evaluate(name) for name in block.inputs]
for name in variableNames:
scope[name] = None
if block.signature == 'doChangeVar':
variableName = self.evaluate(block.inputs[0])
increment = self.evaluate(block.inputs[1])
if type(increment) in [float, int]:
if self.varExistsLocally(variableName, scope):
# Snap has a quirk where if the variable isn't a number, change var does nothing
if type(scope[variableName]) in [float, int]:
try:
scope[variableName] += increment
except TypeError:
scope[variableName] = 'NaN'
else:
scope = self.project.globalVariables
if type(scope[variableName]) in [float, int]:
try:
scope[variableName] += increment
except TypeError:
scope[variableName] = 'NaN'
def varExistsLocally(self, name : str, scope : {}):
return scope != None and name in scope