astreum 0.1.9__py3-none-any.whl → 0.1.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of astreum might be problematic. Click here for more details.
- astreum/machine/__init__.py +352 -254
- {astreum-0.1.9.dist-info → astreum-0.1.10.dist-info}/METADATA +3 -3
- {astreum-0.1.9.dist-info → astreum-0.1.10.dist-info}/RECORD +6 -6
- {astreum-0.1.9.dist-info → astreum-0.1.10.dist-info}/LICENSE +0 -0
- {astreum-0.1.9.dist-info → astreum-0.1.10.dist-info}/WHEEL +0 -0
- {astreum-0.1.9.dist-info → astreum-0.1.10.dist-info}/top_level.txt +0 -0
astreum/machine/__init__.py
CHANGED
|
@@ -1,254 +1,352 @@
|
|
|
1
|
-
import threading
|
|
2
|
-
from typing import Dict, Optional
|
|
3
|
-
import uuid
|
|
4
|
-
|
|
5
|
-
from astreum.lispeum.special.definition import handle_definition
|
|
6
|
-
from astreum.lispeum.special.list.all import handle_list_all
|
|
7
|
-
from astreum.lispeum.special.list.any import handle_list_any
|
|
8
|
-
from astreum.lispeum.special.list.fold import handle_list_fold
|
|
9
|
-
from astreum.lispeum.special.list.get import handle_list_get
|
|
10
|
-
from astreum.lispeum.special.list.insert import handle_list_insert
|
|
11
|
-
from astreum.lispeum.special.list.map import handle_list_map
|
|
12
|
-
from astreum.lispeum.special.list.position import handle_list_position
|
|
13
|
-
from astreum.lispeum.special.list.remove import handle_list_remove
|
|
14
|
-
from astreum.machine.environment import Environment
|
|
15
|
-
from astreum.lispeum.expression import Expr
|
|
16
|
-
from astreum.lispeum.tokenizer import tokenize
|
|
17
|
-
from astreum.lispeum.parser import parse
|
|
18
|
-
|
|
19
|
-
class AstreumMachine:
|
|
20
|
-
def __init__(self, node: 'Node' = None):
|
|
21
|
-
self.global_env = Environment(node=node)
|
|
22
|
-
self.sessions: Dict[str, Environment] = {}
|
|
23
|
-
self.lock = threading.Lock()
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def create_session(self) -> str:
|
|
27
|
-
session_id = str(uuid.uuid4())
|
|
28
|
-
with self.lock:
|
|
29
|
-
self.sessions[session_id] = Environment(parent=self.global_env)
|
|
30
|
-
return session_id
|
|
31
|
-
|
|
32
|
-
def terminate_session(self, session_id: str) -> bool:
|
|
33
|
-
with self.lock:
|
|
34
|
-
if session_id in self.sessions:
|
|
35
|
-
del self.sessions[session_id]
|
|
36
|
-
return True
|
|
37
|
-
else:
|
|
38
|
-
return False
|
|
39
|
-
|
|
40
|
-
def get_session_env(self, session_id: str) -> Optional[Environment]:
|
|
41
|
-
with self.lock:
|
|
42
|
-
return self.sessions.get(session_id, None)
|
|
43
|
-
|
|
44
|
-
def evaluate_code(self, code: str, session_id: str) -> Expr:
|
|
45
|
-
session_env = self.get_session_env(session_id)
|
|
46
|
-
if session_env is None:
|
|
47
|
-
raise ValueError(f"Session ID {session_id} not found.")
|
|
48
|
-
|
|
49
|
-
try:
|
|
50
|
-
tkns = tokenize(input=code)
|
|
51
|
-
expr, _ = parse(tokens=tkns)
|
|
52
|
-
result = self.evaluate_expression(expr, session_env)
|
|
53
|
-
return result
|
|
54
|
-
|
|
55
|
-
except Exception as e:
|
|
56
|
-
raise ValueError(e)
|
|
57
|
-
|
|
58
|
-
def evaluate_expression(self, expr: Expr, env: Environment) -> Expr:
|
|
59
|
-
if isinstance(expr, Expr.Boolean) or isinstance(expr, Expr.Integer) or isinstance(expr, Expr.String) or isinstance(expr, Expr.Error):
|
|
60
|
-
return expr
|
|
61
|
-
|
|
62
|
-
elif isinstance(expr, Expr.Symbol):
|
|
63
|
-
value = env.get(expr.value)
|
|
64
|
-
|
|
65
|
-
if value:
|
|
66
|
-
return value
|
|
67
|
-
else:
|
|
68
|
-
return Expr.Error(
|
|
69
|
-
category="NameError",
|
|
70
|
-
message=f"Variable '{expr.value}' not found in environments."
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
elif isinstance(expr, Expr.ListExpr):
|
|
74
|
-
|
|
75
|
-
if len(expr.elements) == 0:
|
|
76
|
-
return expr
|
|
77
|
-
|
|
78
|
-
if len(expr.elements) == 1:
|
|
79
|
-
return self.evaluate_expression(expr=expr.elements[0], env=env)
|
|
80
|
-
|
|
81
|
-
first = expr.elements[0]
|
|
82
|
-
|
|
83
|
-
if isinstance(first, Expr.Symbol):
|
|
84
|
-
|
|
85
|
-
first_symbol_value = env.get(first.value)
|
|
86
|
-
|
|
87
|
-
if first_symbol_value and not isinstance(first_symbol_value, Expr.Function):
|
|
88
|
-
evaluated_elements = [self.evaluate_expression(e, env) for e in expr.elements]
|
|
89
|
-
return Expr.ListExpr(evaluated_elements)
|
|
90
|
-
|
|
91
|
-
elif first.value == "def":
|
|
92
|
-
return handle_definition(
|
|
93
|
-
machine=self,
|
|
94
|
-
args=expr.elements[1:],
|
|
95
|
-
env=env
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
# List
|
|
99
|
-
elif first.value == "list.new":
|
|
100
|
-
return Expr.ListExpr([self.evaluate_expression(arg, env) for arg in expr.elements[1:]])
|
|
101
|
-
|
|
102
|
-
elif first.value == "list.get":
|
|
103
|
-
args = expr.elements[1:]
|
|
104
|
-
if len(args) != 2:
|
|
105
|
-
return Expr.Error(
|
|
106
|
-
category="SyntaxError",
|
|
107
|
-
message="list.get expects exactly two arguments: a list and an index"
|
|
108
|
-
)
|
|
109
|
-
list_obj = self.evaluate_expression(args[0], env)
|
|
110
|
-
index = self.evaluate_expression(args[1], env)
|
|
111
|
-
return handle_list_get(self, list_obj, index, env)
|
|
112
|
-
|
|
113
|
-
elif first.value == "list.insert":
|
|
114
|
-
args = expr.elements[1:]
|
|
115
|
-
if len(args) != 3:
|
|
116
|
-
return Expr.ListExpr([
|
|
117
|
-
Expr.ListExpr([]),
|
|
118
|
-
Expr.String("list.insert expects exactly three arguments: a list, an index, and a value")
|
|
119
|
-
])
|
|
120
|
-
|
|
121
|
-
return handle_list_insert(
|
|
122
|
-
list=self.evaluate_expression(args[0], env),
|
|
123
|
-
index=self.evaluate_expression(args[1], env),
|
|
124
|
-
value=self.evaluate_expression(args[2], env),
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
elif first.value == "list.remove":
|
|
128
|
-
args = expr.elements[1:]
|
|
129
|
-
if len(args) != 2:
|
|
130
|
-
return Expr.ListExpr([
|
|
131
|
-
Expr.ListExpr([]),
|
|
132
|
-
Expr.String("list.remove expects exactly two arguments: a list and an index")
|
|
133
|
-
])
|
|
134
|
-
|
|
135
|
-
return handle_list_remove(
|
|
136
|
-
list=self.evaluate_expression(args[0], env),
|
|
137
|
-
index=self.evaluate_expression(args[1], env),
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
elif first.value == "list.length":
|
|
141
|
-
args = expr.elements[1:]
|
|
142
|
-
if len(args) != 1:
|
|
143
|
-
return Expr.ListExpr([
|
|
144
|
-
Expr.ListExpr([]),
|
|
145
|
-
Expr.String("list.length expects exactly one argument: a list")
|
|
146
|
-
])
|
|
147
|
-
|
|
148
|
-
list_obj = self.evaluate_expression(args[0], env)
|
|
149
|
-
if not isinstance(list_obj, Expr.ListExpr):
|
|
150
|
-
return Expr.ListExpr([
|
|
151
|
-
Expr.ListExpr([]),
|
|
152
|
-
Expr.String("Argument must be a list")
|
|
153
|
-
])
|
|
154
|
-
|
|
155
|
-
return Expr.ListExpr([
|
|
156
|
-
Expr.Integer(len(list_obj.elements)),
|
|
157
|
-
Expr.ListExpr([])
|
|
158
|
-
])
|
|
159
|
-
|
|
160
|
-
elif first.value == "list.fold":
|
|
161
|
-
if len(args) != 3:
|
|
162
|
-
return Expr.ListExpr([
|
|
163
|
-
Expr.ListExpr([]),
|
|
164
|
-
Expr.String("list.fold expects exactly three arguments: a list, an initial value, and a function")
|
|
165
|
-
])
|
|
166
|
-
|
|
167
|
-
return handle_list_fold(
|
|
168
|
-
machine=self,
|
|
169
|
-
list=self.evaluate_expression(args[0], env),
|
|
170
|
-
initial=self.evaluate_expression(args[1], env),
|
|
171
|
-
func=self.evaluate_expression(args[2], env),
|
|
172
|
-
env=env,
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
elif first.value == "list.map":
|
|
176
|
-
if len(args) != 2:
|
|
177
|
-
return Expr.ListExpr([
|
|
178
|
-
Expr.ListExpr([]),
|
|
179
|
-
Expr.String("list.map expects exactly two arguments: a list and a function")
|
|
180
|
-
])
|
|
181
|
-
|
|
182
|
-
return handle_list_map(
|
|
183
|
-
machine=self,
|
|
184
|
-
list=self.evaluate_expression(args[0], env),
|
|
185
|
-
func=self.evaluate_expression(args[1], env),
|
|
186
|
-
env=env,
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
elif first.value == "list.position":
|
|
190
|
-
if len(args) != 2:
|
|
191
|
-
return Expr.ListExpr([
|
|
192
|
-
Expr.ListExpr([]),
|
|
193
|
-
Expr.String("list.position expects exactly two arguments: a list and a function")
|
|
194
|
-
])
|
|
195
|
-
|
|
196
|
-
return handle_list_position(
|
|
197
|
-
machine=self,
|
|
198
|
-
list=self.evaluate_expression(args[0], env),
|
|
199
|
-
predicate=self.evaluate_expression(args[1], env),
|
|
200
|
-
env=env,
|
|
201
|
-
)
|
|
202
|
-
|
|
203
|
-
elif first.value == "list.any":
|
|
204
|
-
if len(args) != 2:
|
|
205
|
-
return Expr.ListExpr([
|
|
206
|
-
Expr.ListExpr([]),
|
|
207
|
-
Expr.String("list.any expects exactly two arguments: a list and a function")
|
|
208
|
-
])
|
|
209
|
-
|
|
210
|
-
return handle_list_any(
|
|
211
|
-
machine=self,
|
|
212
|
-
list=self.evaluate_expression(args[0], env),
|
|
213
|
-
predicate=self.evaluate_expression(args[1], env),
|
|
214
|
-
env=env,
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
elif first.value == "list.all":
|
|
218
|
-
if len(args) != 2:
|
|
219
|
-
return Expr.ListExpr([
|
|
220
|
-
Expr.ListExpr([]),
|
|
221
|
-
Expr.String("list.all expects exactly two arguments: a list and a function")
|
|
222
|
-
])
|
|
223
|
-
|
|
224
|
-
return handle_list_all(
|
|
225
|
-
machine=self,
|
|
226
|
-
list=self.evaluate_expression(args[0], env),
|
|
227
|
-
predicate=self.evaluate_expression(args[1], env),
|
|
228
|
-
env=env,
|
|
229
|
-
)
|
|
230
|
-
|
|
231
|
-
# Number
|
|
232
|
-
elif first.value == "+":
|
|
233
|
-
evaluated_args = [self.evaluate_expression(arg, env) for arg in expr.elements[1:]]
|
|
234
|
-
|
|
235
|
-
# Check for non-integer arguments
|
|
236
|
-
if not all(isinstance(arg, Expr.Integer) for arg in evaluated_args):
|
|
237
|
-
return Expr.Error(
|
|
238
|
-
category="TypeError",
|
|
239
|
-
message="All arguments to + must be integers"
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
# Sum up the integer values
|
|
243
|
-
result = sum(arg.value for arg in evaluated_args)
|
|
244
|
-
return Expr.Integer(result)
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
1
|
+
import threading
|
|
2
|
+
from typing import Dict, Optional
|
|
3
|
+
import uuid
|
|
4
|
+
|
|
5
|
+
from astreum.lispeum.special.definition import handle_definition
|
|
6
|
+
from astreum.lispeum.special.list.all import handle_list_all
|
|
7
|
+
from astreum.lispeum.special.list.any import handle_list_any
|
|
8
|
+
from astreum.lispeum.special.list.fold import handle_list_fold
|
|
9
|
+
from astreum.lispeum.special.list.get import handle_list_get
|
|
10
|
+
from astreum.lispeum.special.list.insert import handle_list_insert
|
|
11
|
+
from astreum.lispeum.special.list.map import handle_list_map
|
|
12
|
+
from astreum.lispeum.special.list.position import handle_list_position
|
|
13
|
+
from astreum.lispeum.special.list.remove import handle_list_remove
|
|
14
|
+
from astreum.machine.environment import Environment
|
|
15
|
+
from astreum.lispeum.expression import Expr
|
|
16
|
+
from astreum.lispeum.tokenizer import tokenize
|
|
17
|
+
from astreum.lispeum.parser import parse
|
|
18
|
+
|
|
19
|
+
class AstreumMachine:
|
|
20
|
+
def __init__(self, node: 'Node' = None):
|
|
21
|
+
self.global_env = Environment(node=node)
|
|
22
|
+
self.sessions: Dict[str, Environment] = {}
|
|
23
|
+
self.lock = threading.Lock()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def create_session(self) -> str:
|
|
27
|
+
session_id = str(uuid.uuid4())
|
|
28
|
+
with self.lock:
|
|
29
|
+
self.sessions[session_id] = Environment(parent=self.global_env)
|
|
30
|
+
return session_id
|
|
31
|
+
|
|
32
|
+
def terminate_session(self, session_id: str) -> bool:
|
|
33
|
+
with self.lock:
|
|
34
|
+
if session_id in self.sessions:
|
|
35
|
+
del self.sessions[session_id]
|
|
36
|
+
return True
|
|
37
|
+
else:
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
def get_session_env(self, session_id: str) -> Optional[Environment]:
|
|
41
|
+
with self.lock:
|
|
42
|
+
return self.sessions.get(session_id, None)
|
|
43
|
+
|
|
44
|
+
def evaluate_code(self, code: str, session_id: str) -> Expr:
|
|
45
|
+
session_env = self.get_session_env(session_id)
|
|
46
|
+
if session_env is None:
|
|
47
|
+
raise ValueError(f"Session ID {session_id} not found.")
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
tkns = tokenize(input=code)
|
|
51
|
+
expr, _ = parse(tokens=tkns)
|
|
52
|
+
result = self.evaluate_expression(expr, session_env)
|
|
53
|
+
return result
|
|
54
|
+
|
|
55
|
+
except Exception as e:
|
|
56
|
+
raise ValueError(e)
|
|
57
|
+
|
|
58
|
+
def evaluate_expression(self, expr: Expr, env: Environment) -> Expr:
|
|
59
|
+
if isinstance(expr, Expr.Boolean) or isinstance(expr, Expr.Integer) or isinstance(expr, Expr.String) or isinstance(expr, Expr.Error):
|
|
60
|
+
return expr
|
|
61
|
+
|
|
62
|
+
elif isinstance(expr, Expr.Symbol):
|
|
63
|
+
value = env.get(expr.value)
|
|
64
|
+
|
|
65
|
+
if value:
|
|
66
|
+
return value
|
|
67
|
+
else:
|
|
68
|
+
return Expr.Error(
|
|
69
|
+
category="NameError",
|
|
70
|
+
message=f"Variable '{expr.value}' not found in environments."
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
elif isinstance(expr, Expr.ListExpr):
|
|
74
|
+
|
|
75
|
+
if len(expr.elements) == 0:
|
|
76
|
+
return expr
|
|
77
|
+
|
|
78
|
+
if len(expr.elements) == 1:
|
|
79
|
+
return self.evaluate_expression(expr=expr.elements[0], env=env)
|
|
80
|
+
|
|
81
|
+
first = expr.elements[0]
|
|
82
|
+
|
|
83
|
+
if isinstance(first, Expr.Symbol):
|
|
84
|
+
|
|
85
|
+
first_symbol_value = env.get(first.value)
|
|
86
|
+
|
|
87
|
+
if first_symbol_value and not isinstance(first_symbol_value, Expr.Function):
|
|
88
|
+
evaluated_elements = [self.evaluate_expression(e, env) for e in expr.elements]
|
|
89
|
+
return Expr.ListExpr(evaluated_elements)
|
|
90
|
+
|
|
91
|
+
elif first.value == "def":
|
|
92
|
+
return handle_definition(
|
|
93
|
+
machine=self,
|
|
94
|
+
args=expr.elements[1:],
|
|
95
|
+
env=env
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# List
|
|
99
|
+
elif first.value == "list.new":
|
|
100
|
+
return Expr.ListExpr([self.evaluate_expression(arg, env) for arg in expr.elements[1:]])
|
|
101
|
+
|
|
102
|
+
elif first.value == "list.get":
|
|
103
|
+
args = expr.elements[1:]
|
|
104
|
+
if len(args) != 2:
|
|
105
|
+
return Expr.Error(
|
|
106
|
+
category="SyntaxError",
|
|
107
|
+
message="list.get expects exactly two arguments: a list and an index"
|
|
108
|
+
)
|
|
109
|
+
list_obj = self.evaluate_expression(args[0], env)
|
|
110
|
+
index = self.evaluate_expression(args[1], env)
|
|
111
|
+
return handle_list_get(self, list_obj, index, env)
|
|
112
|
+
|
|
113
|
+
elif first.value == "list.insert":
|
|
114
|
+
args = expr.elements[1:]
|
|
115
|
+
if len(args) != 3:
|
|
116
|
+
return Expr.ListExpr([
|
|
117
|
+
Expr.ListExpr([]),
|
|
118
|
+
Expr.String("list.insert expects exactly three arguments: a list, an index, and a value")
|
|
119
|
+
])
|
|
120
|
+
|
|
121
|
+
return handle_list_insert(
|
|
122
|
+
list=self.evaluate_expression(args[0], env),
|
|
123
|
+
index=self.evaluate_expression(args[1], env),
|
|
124
|
+
value=self.evaluate_expression(args[2], env),
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
elif first.value == "list.remove":
|
|
128
|
+
args = expr.elements[1:]
|
|
129
|
+
if len(args) != 2:
|
|
130
|
+
return Expr.ListExpr([
|
|
131
|
+
Expr.ListExpr([]),
|
|
132
|
+
Expr.String("list.remove expects exactly two arguments: a list and an index")
|
|
133
|
+
])
|
|
134
|
+
|
|
135
|
+
return handle_list_remove(
|
|
136
|
+
list=self.evaluate_expression(args[0], env),
|
|
137
|
+
index=self.evaluate_expression(args[1], env),
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
elif first.value == "list.length":
|
|
141
|
+
args = expr.elements[1:]
|
|
142
|
+
if len(args) != 1:
|
|
143
|
+
return Expr.ListExpr([
|
|
144
|
+
Expr.ListExpr([]),
|
|
145
|
+
Expr.String("list.length expects exactly one argument: a list")
|
|
146
|
+
])
|
|
147
|
+
|
|
148
|
+
list_obj = self.evaluate_expression(args[0], env)
|
|
149
|
+
if not isinstance(list_obj, Expr.ListExpr):
|
|
150
|
+
return Expr.ListExpr([
|
|
151
|
+
Expr.ListExpr([]),
|
|
152
|
+
Expr.String("Argument must be a list")
|
|
153
|
+
])
|
|
154
|
+
|
|
155
|
+
return Expr.ListExpr([
|
|
156
|
+
Expr.Integer(len(list_obj.elements)),
|
|
157
|
+
Expr.ListExpr([])
|
|
158
|
+
])
|
|
159
|
+
|
|
160
|
+
elif first.value == "list.fold":
|
|
161
|
+
if len(args) != 3:
|
|
162
|
+
return Expr.ListExpr([
|
|
163
|
+
Expr.ListExpr([]),
|
|
164
|
+
Expr.String("list.fold expects exactly three arguments: a list, an initial value, and a function")
|
|
165
|
+
])
|
|
166
|
+
|
|
167
|
+
return handle_list_fold(
|
|
168
|
+
machine=self,
|
|
169
|
+
list=self.evaluate_expression(args[0], env),
|
|
170
|
+
initial=self.evaluate_expression(args[1], env),
|
|
171
|
+
func=self.evaluate_expression(args[2], env),
|
|
172
|
+
env=env,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
elif first.value == "list.map":
|
|
176
|
+
if len(args) != 2:
|
|
177
|
+
return Expr.ListExpr([
|
|
178
|
+
Expr.ListExpr([]),
|
|
179
|
+
Expr.String("list.map expects exactly two arguments: a list and a function")
|
|
180
|
+
])
|
|
181
|
+
|
|
182
|
+
return handle_list_map(
|
|
183
|
+
machine=self,
|
|
184
|
+
list=self.evaluate_expression(args[0], env),
|
|
185
|
+
func=self.evaluate_expression(args[1], env),
|
|
186
|
+
env=env,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
elif first.value == "list.position":
|
|
190
|
+
if len(args) != 2:
|
|
191
|
+
return Expr.ListExpr([
|
|
192
|
+
Expr.ListExpr([]),
|
|
193
|
+
Expr.String("list.position expects exactly two arguments: a list and a function")
|
|
194
|
+
])
|
|
195
|
+
|
|
196
|
+
return handle_list_position(
|
|
197
|
+
machine=self,
|
|
198
|
+
list=self.evaluate_expression(args[0], env),
|
|
199
|
+
predicate=self.evaluate_expression(args[1], env),
|
|
200
|
+
env=env,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
elif first.value == "list.any":
|
|
204
|
+
if len(args) != 2:
|
|
205
|
+
return Expr.ListExpr([
|
|
206
|
+
Expr.ListExpr([]),
|
|
207
|
+
Expr.String("list.any expects exactly two arguments: a list and a function")
|
|
208
|
+
])
|
|
209
|
+
|
|
210
|
+
return handle_list_any(
|
|
211
|
+
machine=self,
|
|
212
|
+
list=self.evaluate_expression(args[0], env),
|
|
213
|
+
predicate=self.evaluate_expression(args[1], env),
|
|
214
|
+
env=env,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
elif first.value == "list.all":
|
|
218
|
+
if len(args) != 2:
|
|
219
|
+
return Expr.ListExpr([
|
|
220
|
+
Expr.ListExpr([]),
|
|
221
|
+
Expr.String("list.all expects exactly two arguments: a list and a function")
|
|
222
|
+
])
|
|
223
|
+
|
|
224
|
+
return handle_list_all(
|
|
225
|
+
machine=self,
|
|
226
|
+
list=self.evaluate_expression(args[0], env),
|
|
227
|
+
predicate=self.evaluate_expression(args[1], env),
|
|
228
|
+
env=env,
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
# Number
|
|
232
|
+
elif first.value == "+":
|
|
233
|
+
evaluated_args = [self.evaluate_expression(arg, env) for arg in expr.elements[1:]]
|
|
234
|
+
|
|
235
|
+
# Check for non-integer arguments
|
|
236
|
+
if not all(isinstance(arg, Expr.Integer) for arg in evaluated_args):
|
|
237
|
+
return Expr.Error(
|
|
238
|
+
category="TypeError",
|
|
239
|
+
message="All arguments to + must be integers"
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
# Sum up the integer values
|
|
243
|
+
result = sum(arg.value for arg in evaluated_args)
|
|
244
|
+
return Expr.Integer(result)
|
|
245
|
+
|
|
246
|
+
# Subtraction
|
|
247
|
+
elif first.value == "-":
|
|
248
|
+
evaluated_args = [self.evaluate_expression(arg, env) for arg in expr.elements[1:]]
|
|
249
|
+
|
|
250
|
+
# Check for non-integer arguments
|
|
251
|
+
if not all(isinstance(arg, Expr.Integer) for arg in evaluated_args):
|
|
252
|
+
return Expr.Error(
|
|
253
|
+
category="TypeError",
|
|
254
|
+
message="All arguments to - must be integers"
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# With only one argument, negate it
|
|
258
|
+
if len(evaluated_args) == 1:
|
|
259
|
+
return Expr.Integer(-evaluated_args[0].value)
|
|
260
|
+
|
|
261
|
+
# With multiple arguments, subtract all from the first
|
|
262
|
+
result = evaluated_args[0].value
|
|
263
|
+
for arg in evaluated_args[1:]:
|
|
264
|
+
result -= arg.value
|
|
265
|
+
|
|
266
|
+
return Expr.Integer(result)
|
|
267
|
+
|
|
268
|
+
# Multiplication
|
|
269
|
+
elif first.value == "*":
|
|
270
|
+
evaluated_args = [self.evaluate_expression(arg, env) for arg in expr.elements[1:]]
|
|
271
|
+
|
|
272
|
+
# Check for non-integer arguments
|
|
273
|
+
if not all(isinstance(arg, Expr.Integer) for arg in evaluated_args):
|
|
274
|
+
return Expr.Error(
|
|
275
|
+
category="TypeError",
|
|
276
|
+
message="All arguments to * must be integers"
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
# Multiply all values
|
|
280
|
+
result = 1
|
|
281
|
+
for arg in evaluated_args:
|
|
282
|
+
result *= arg.value
|
|
283
|
+
|
|
284
|
+
return Expr.Integer(result)
|
|
285
|
+
|
|
286
|
+
# Division (integer division)
|
|
287
|
+
elif first.value == "/":
|
|
288
|
+
evaluated_args = [self.evaluate_expression(arg, env) for arg in expr.elements[1:]]
|
|
289
|
+
|
|
290
|
+
# Check for non-integer arguments
|
|
291
|
+
if not all(isinstance(arg, Expr.Integer) for arg in evaluated_args):
|
|
292
|
+
return Expr.Error(
|
|
293
|
+
category="TypeError",
|
|
294
|
+
message="All arguments to / must be integers"
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
# Need exactly two arguments
|
|
298
|
+
if len(evaluated_args) != 2:
|
|
299
|
+
return Expr.Error(
|
|
300
|
+
category="ArgumentError",
|
|
301
|
+
message="The / operation requires exactly two arguments"
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
dividend = evaluated_args[0].value
|
|
305
|
+
divisor = evaluated_args[1].value
|
|
306
|
+
|
|
307
|
+
if divisor == 0:
|
|
308
|
+
return Expr.Error(
|
|
309
|
+
category="DivisionError",
|
|
310
|
+
message="Division by zero"
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
return Expr.Integer(dividend // divisor) # Integer division
|
|
314
|
+
|
|
315
|
+
# Remainder (modulo)
|
|
316
|
+
elif first.value == "%":
|
|
317
|
+
evaluated_args = [self.evaluate_expression(arg, env) for arg in expr.elements[1:]]
|
|
318
|
+
|
|
319
|
+
# Check for non-integer arguments
|
|
320
|
+
if not all(isinstance(arg, Expr.Integer) for arg in evaluated_args):
|
|
321
|
+
return Expr.Error(
|
|
322
|
+
category="TypeError",
|
|
323
|
+
message="All arguments to % must be integers"
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
# Need exactly two arguments
|
|
327
|
+
if len(evaluated_args) != 2:
|
|
328
|
+
return Expr.Error(
|
|
329
|
+
category="ArgumentError",
|
|
330
|
+
message="The % operation requires exactly two arguments"
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
dividend = evaluated_args[0].value
|
|
334
|
+
divisor = evaluated_args[1].value
|
|
335
|
+
|
|
336
|
+
if divisor == 0:
|
|
337
|
+
return Expr.Error(
|
|
338
|
+
category="DivisionError",
|
|
339
|
+
message="Modulo by zero"
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
return Expr.Integer(dividend % divisor)
|
|
343
|
+
|
|
344
|
+
else:
|
|
345
|
+
evaluated_elements = [self.evaluate_expression(e, env) for e in expr.elements]
|
|
346
|
+
return Expr.ListExpr(evaluated_elements)
|
|
347
|
+
|
|
348
|
+
elif isinstance(expr, Expr.Function):
|
|
349
|
+
return expr
|
|
350
|
+
|
|
351
|
+
else:
|
|
352
|
+
raise ValueError(f"Unknown expression type: {type(expr)}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: astreum
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.10
|
|
4
4
|
Summary: Python library to interact with the Astreum blockchain and its Lispeum virtual machine.
|
|
5
5
|
Author-email: "Roy R. O. Okello" <roy@stelar.xyz>
|
|
6
6
|
Project-URL: Homepage, https://github.com/astreum/lib
|
|
@@ -11,8 +11,8 @@ Classifier: Operating System :: OS Independent
|
|
|
11
11
|
Requires-Python: >=3.8
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist: pycryptodomex
|
|
15
|
-
Requires-Dist: cryptography
|
|
14
|
+
Requires-Dist: pycryptodomex==3.21.0
|
|
15
|
+
Requires-Dist: cryptography==44.0.2
|
|
16
16
|
|
|
17
17
|
# lib
|
|
18
18
|
|
|
@@ -17,7 +17,7 @@ astreum/lispeum/special/list/position.py,sha256=1EcD5fzfjUCUhHCk8iotFoWdeE9Z2Rjj
|
|
|
17
17
|
astreum/lispeum/special/list/remove.py,sha256=EPhkWFwyKG8HyWPheVvtxCvMaEGvODFUbx7h1fli_hg,690
|
|
18
18
|
astreum/lispeum/special/number/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
19
|
astreum/lispeum/special/number/addition.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
-
astreum/machine/__init__.py,sha256=
|
|
20
|
+
astreum/machine/__init__.py,sha256=GOdZl1tS9uIJHbq5WVcplifMDPDLQroX7CVew-K2YbA,15262
|
|
21
21
|
astreum/machine/environment.py,sha256=K0084U6B7wwjrDZ9b2_7cEcbBzsB7UOy_Zpbrr7B3GY,834
|
|
22
22
|
astreum/machine/error.py,sha256=MvqBaZZt33rNELNhUJ2lER3TE3aS8WVqsWF2hz2AwoA,38
|
|
23
23
|
astreum/node/__init__.py,sha256=wvmMMACicwhJ-ipSLpR1rsEUXWuHaZ8fnsBCkUA_RA8,22387
|
|
@@ -30,8 +30,8 @@ astreum/node/relay/peer.py,sha256=DlvTR9j0BZQ1dW-p_9UGgfLvQqwNdpNLMSCYEW4FhyI,58
|
|
|
30
30
|
astreum/node/relay/route.py,sha256=fyOSsAe1mfsCVeN6LtQ_OEUEb1FiC5dobZBEJKNGU9U,5814
|
|
31
31
|
astreum/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
32
32
|
astreum/utils/bytes_format.py,sha256=X4tG5GGPweNCE54bHYkLFiuLTbmpy5upO_s1Cef-MGA,2711
|
|
33
|
-
astreum-0.1.
|
|
34
|
-
astreum-0.1.
|
|
35
|
-
astreum-0.1.
|
|
36
|
-
astreum-0.1.
|
|
37
|
-
astreum-0.1.
|
|
33
|
+
astreum-0.1.10.dist-info/LICENSE,sha256=gYBvRDP-cPLmTyJhvZ346QkrYW_eleke4Z2Yyyu43eQ,1089
|
|
34
|
+
astreum-0.1.10.dist-info/METADATA,sha256=50hGAAYObIlHpnh2ikWSAALUtOIwmw9O_U6c1qLCre8,2942
|
|
35
|
+
astreum-0.1.10.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
|
36
|
+
astreum-0.1.10.dist-info/top_level.txt,sha256=1EG1GmkOk3NPmUA98FZNdKouhRyget-KiFiMk0i2Uz0,8
|
|
37
|
+
astreum-0.1.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|