neuron-lang 1.0.0__tar.gz
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 neuron-lang might be problematic. Click here for more details.
- neuron_lang-1.0.0/PKG-INFO +11 -0
- neuron_lang-1.0.0/neuron/__init__.py +18 -0
- neuron_lang-1.0.0/neuron/ast_nodes.py +414 -0
- neuron_lang-1.0.0/neuron/compiler.py +191 -0
- neuron_lang-1.0.0/neuron/environment.py +179 -0
- neuron_lang-1.0.0/neuron/errors.py +178 -0
- neuron_lang-1.0.0/neuron/interpreter.py +640 -0
- neuron_lang-1.0.0/neuron/lexer.py +417 -0
- neuron_lang-1.0.0/neuron/main.py +176 -0
- neuron_lang-1.0.0/neuron/package_manager.py +122 -0
- neuron_lang-1.0.0/neuron/parser.py +599 -0
- neuron_lang-1.0.0/neuron/repl.py +121 -0
- neuron_lang-1.0.0/neuron/stdlib/__init__.py +164 -0
- neuron_lang-1.0.0/neuron/stdlib/data.py +72 -0
- neuron_lang-1.0.0/neuron/stdlib/io_lib.py +30 -0
- neuron_lang-1.0.0/neuron/stdlib/math_lib.py +35 -0
- neuron_lang-1.0.0/neuron/stdlib/metrics.py +79 -0
- neuron_lang-1.0.0/neuron/stdlib/neural.py +220 -0
- neuron_lang-1.0.0/neuron/stdlib/nlp.py +72 -0
- neuron_lang-1.0.0/neuron/stdlib/optim.py +102 -0
- neuron_lang-1.0.0/neuron/stdlib/plot.py +40 -0
- neuron_lang-1.0.0/neuron/stdlib/preprocess.py +67 -0
- neuron_lang-1.0.0/neuron/stdlib/tensor.py +205 -0
- neuron_lang-1.0.0/neuron/stdlib/vision.py +67 -0
- neuron_lang-1.0.0/neuron/tokens.py +165 -0
- neuron_lang-1.0.0/neuron/utils/__init__.py +1 -0
- neuron_lang-1.0.0/neuron/utils/colors.py +117 -0
- neuron_lang-1.0.0/neuron_lang.egg-info/PKG-INFO +11 -0
- neuron_lang-1.0.0/neuron_lang.egg-info/SOURCES.txt +33 -0
- neuron_lang-1.0.0/neuron_lang.egg-info/dependency_links.txt +1 -0
- neuron_lang-1.0.0/neuron_lang.egg-info/entry_points.txt +2 -0
- neuron_lang-1.0.0/neuron_lang.egg-info/requires.txt +5 -0
- neuron_lang-1.0.0/neuron_lang.egg-info/top_level.txt +1 -0
- neuron_lang-1.0.0/pyproject.toml +21 -0
- neuron_lang-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: neuron-lang
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: AI-First Programming Language
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: numpy>=1.21.0
|
|
9
|
+
Provides-Extra: full
|
|
10
|
+
Requires-Dist: matplotlib>=3.5.0; extra == "full"
|
|
11
|
+
Requires-Dist: Pillow>=9.0.0; extra == "full"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Neuron Programming Language
|
|
3
|
+
===========================
|
|
4
|
+
A Python-like, OOP-based programming language purpose-built for
|
|
5
|
+
Artificial Intelligence development.
|
|
6
|
+
|
|
7
|
+
File extension: .nl
|
|
8
|
+
Website: https://neuron-lang.org (coming soon)
|
|
9
|
+
|
|
10
|
+
Keywords: do, give, show, ask, when, orwhen, otherwise, each,
|
|
11
|
+
repeat, grab, entity, brain, me, create, yes, no,
|
|
12
|
+
nothing, also, either, nah, safe, rescue, stop, skip,
|
|
13
|
+
quick, within, drop, ensure, emit, shared, from, upto
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
__version__ = "1.0.0"
|
|
17
|
+
__author__ = "Neuron Language Team"
|
|
18
|
+
__license__ = "MIT"
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Neuron AST Node Definitions
|
|
3
|
+
============================
|
|
4
|
+
All Abstract Syntax Tree node types for the Neuron language.
|
|
5
|
+
Each node carries source location info for error reporting.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ASTNode:
|
|
10
|
+
"""Base class for all AST nodes."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, line=None, column=None):
|
|
13
|
+
self.line = line
|
|
14
|
+
self.column = column
|
|
15
|
+
|
|
16
|
+
def accept(self, visitor):
|
|
17
|
+
method_name = f"visit_{type(self).__name__}"
|
|
18
|
+
visitor_method = getattr(visitor, method_name, None)
|
|
19
|
+
if visitor_method:
|
|
20
|
+
return visitor_method(self)
|
|
21
|
+
return visitor.generic_visit(self)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# ===== PROGRAM =====
|
|
25
|
+
|
|
26
|
+
class Program(ASTNode):
|
|
27
|
+
"""Root node: a list of statements."""
|
|
28
|
+
|
|
29
|
+
def __init__(self, statements, line=None, column=None):
|
|
30
|
+
super().__init__(line, column)
|
|
31
|
+
self.statements = statements
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# ===== STATEMENTS =====
|
|
35
|
+
|
|
36
|
+
class ExpressionStatement(ASTNode):
|
|
37
|
+
"""A standalone expression used as a statement."""
|
|
38
|
+
|
|
39
|
+
def __init__(self, expression, line=None, column=None):
|
|
40
|
+
super().__init__(line, column)
|
|
41
|
+
self.expression = expression
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class Assignment(ASTNode):
|
|
45
|
+
"""Variable assignment: x = expr"""
|
|
46
|
+
|
|
47
|
+
def __init__(self, target, value, line=None, column=None):
|
|
48
|
+
super().__init__(line, column)
|
|
49
|
+
self.target = target
|
|
50
|
+
self.value = value
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class AugmentedAssignment(ASTNode):
|
|
54
|
+
"""Augmented assignment: x += expr, x -= expr, etc."""
|
|
55
|
+
|
|
56
|
+
def __init__(self, target, op, value, line=None, column=None):
|
|
57
|
+
super().__init__(line, column)
|
|
58
|
+
self.target = target
|
|
59
|
+
self.op = op # '+', '-', '*', '/'
|
|
60
|
+
self.value = value
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class MultiAssignment(ASTNode):
|
|
64
|
+
"""Multiple assignment: a, b = expr1, expr2"""
|
|
65
|
+
|
|
66
|
+
def __init__(self, targets, values, line=None, column=None):
|
|
67
|
+
super().__init__(line, column)
|
|
68
|
+
self.targets = targets
|
|
69
|
+
self.values = values
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class FunctionDef(ASTNode):
|
|
73
|
+
"""Function definition: do name(params): body"""
|
|
74
|
+
|
|
75
|
+
def __init__(self, name, params, defaults, body, line=None, column=None):
|
|
76
|
+
super().__init__(line, column)
|
|
77
|
+
self.name = name
|
|
78
|
+
self.params = params # List of parameter names
|
|
79
|
+
self.defaults = defaults # Dict of param_name -> default_value_expr
|
|
80
|
+
self.body = body # List of statements
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class EntityDef(ASTNode):
|
|
84
|
+
"""Entity (class) definition: entity Name [from Parent]: body"""
|
|
85
|
+
|
|
86
|
+
def __init__(self, name, parent, body, line=None, column=None):
|
|
87
|
+
super().__init__(line, column)
|
|
88
|
+
self.name = name
|
|
89
|
+
self.parent = parent # Parent class name (string) or None
|
|
90
|
+
self.body = body # List of statements (methods, assignments)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class BrainDef(ASTNode):
|
|
94
|
+
"""Brain (AI model) definition: brain Name [from Parent]: body"""
|
|
95
|
+
|
|
96
|
+
def __init__(self, name, parent, body, line=None, column=None):
|
|
97
|
+
super().__init__(line, column)
|
|
98
|
+
self.name = name
|
|
99
|
+
self.parent = parent
|
|
100
|
+
self.body = body
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class ReturnStatement(ASTNode):
|
|
104
|
+
"""Return statement: give expr"""
|
|
105
|
+
|
|
106
|
+
def __init__(self, value=None, line=None, column=None):
|
|
107
|
+
super().__init__(line, column)
|
|
108
|
+
self.value = value
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class IfStatement(ASTNode):
|
|
112
|
+
"""If statement: when condition: body [orwhen: ...] [otherwise: ...]"""
|
|
113
|
+
|
|
114
|
+
def __init__(self, condition, body, elif_clauses=None, else_body=None, line=None, column=None):
|
|
115
|
+
super().__init__(line, column)
|
|
116
|
+
self.condition = condition
|
|
117
|
+
self.body = body
|
|
118
|
+
self.elif_clauses = elif_clauses or [] # List of (condition, body) tuples
|
|
119
|
+
self.else_body = else_body # List of statements or None
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class WhileLoop(ASTNode):
|
|
123
|
+
"""While loop: repeat condition: body"""
|
|
124
|
+
|
|
125
|
+
def __init__(self, condition, body, line=None, column=None):
|
|
126
|
+
super().__init__(line, column)
|
|
127
|
+
self.condition = condition
|
|
128
|
+
self.body = body
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class ForLoop(ASTNode):
|
|
132
|
+
"""For loop: each var within iterable: body"""
|
|
133
|
+
|
|
134
|
+
def __init__(self, variable, iterable, body, line=None, column=None):
|
|
135
|
+
super().__init__(line, column)
|
|
136
|
+
self.variable = variable # Variable name (string)
|
|
137
|
+
self.iterable = iterable # Expression
|
|
138
|
+
self.body = body
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class BreakStatement(ASTNode):
|
|
142
|
+
"""Break: stop"""
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class ContinueStatement(ASTNode):
|
|
147
|
+
"""Continue: skip"""
|
|
148
|
+
pass
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class PassStatement(ASTNode):
|
|
152
|
+
"""Pass/no-op: ..."""
|
|
153
|
+
pass
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class TryCatch(ASTNode):
|
|
157
|
+
"""Try/catch: safe: body rescue ErrorType as name: handler"""
|
|
158
|
+
|
|
159
|
+
def __init__(self, body, rescue_clauses=None, line=None, column=None):
|
|
160
|
+
super().__init__(line, column)
|
|
161
|
+
self.body = body
|
|
162
|
+
self.rescue_clauses = rescue_clauses or []
|
|
163
|
+
# Each clause: (error_type_name, alias_name, handler_body)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class GrabStatement(ASTNode):
|
|
167
|
+
"""Import: grab module_name"""
|
|
168
|
+
|
|
169
|
+
def __init__(self, module_name, alias=None, items=None, line=None, column=None):
|
|
170
|
+
super().__init__(line, column)
|
|
171
|
+
self.module_name = module_name
|
|
172
|
+
self.alias = alias # grab module as alias
|
|
173
|
+
self.items = items # grab item from module
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class DropStatement(ASTNode):
|
|
177
|
+
"""Delete: drop variable"""
|
|
178
|
+
|
|
179
|
+
def __init__(self, target, line=None, column=None):
|
|
180
|
+
super().__init__(line, column)
|
|
181
|
+
self.target = target
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class EnsureStatement(ASTNode):
|
|
185
|
+
"""Assert: ensure condition, message"""
|
|
186
|
+
|
|
187
|
+
def __init__(self, condition, message=None, line=None, column=None):
|
|
188
|
+
super().__init__(line, column)
|
|
189
|
+
self.condition = condition
|
|
190
|
+
self.message = message
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class EmitStatement(ASTNode):
|
|
194
|
+
"""Yield: emit value"""
|
|
195
|
+
|
|
196
|
+
def __init__(self, value=None, line=None, column=None):
|
|
197
|
+
super().__init__(line, column)
|
|
198
|
+
self.value = value
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class SharedStatement(ASTNode):
|
|
202
|
+
"""Global: shared var_name"""
|
|
203
|
+
|
|
204
|
+
def __init__(self, names, line=None, column=None):
|
|
205
|
+
super().__init__(line, column)
|
|
206
|
+
self.names = names # List of variable names
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# ===== EXPRESSIONS =====
|
|
210
|
+
|
|
211
|
+
class NumberLiteral(ASTNode):
|
|
212
|
+
"""Numeric literal: 42, 3.14"""
|
|
213
|
+
|
|
214
|
+
def __init__(self, value, line=None, column=None):
|
|
215
|
+
super().__init__(line, column)
|
|
216
|
+
self.value = value
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class StringLiteral(ASTNode):
|
|
220
|
+
"""String literal: "hello" """
|
|
221
|
+
|
|
222
|
+
def __init__(self, value, line=None, column=None):
|
|
223
|
+
super().__init__(line, column)
|
|
224
|
+
self.value = value
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class FStringLiteral(ASTNode):
|
|
228
|
+
"""Interpolated string: "hello {name}" """
|
|
229
|
+
|
|
230
|
+
def __init__(self, parts, line=None, column=None):
|
|
231
|
+
super().__init__(line, column)
|
|
232
|
+
self.parts = parts # List of (type, value) where type is 'text' or 'expr'
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class BooleanLiteral(ASTNode):
|
|
236
|
+
"""Boolean literal: yes, no"""
|
|
237
|
+
|
|
238
|
+
def __init__(self, value, line=None, column=None):
|
|
239
|
+
super().__init__(line, column)
|
|
240
|
+
self.value = value
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
class NothingLiteral(ASTNode):
|
|
244
|
+
"""Nothing literal: nothing"""
|
|
245
|
+
|
|
246
|
+
def __init__(self, line=None, column=None):
|
|
247
|
+
super().__init__(line, column)
|
|
248
|
+
self.value = None
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class ListLiteral(ASTNode):
|
|
252
|
+
"""List literal: [1, 2, 3]"""
|
|
253
|
+
|
|
254
|
+
def __init__(self, elements, line=None, column=None):
|
|
255
|
+
super().__init__(line, column)
|
|
256
|
+
self.elements = elements
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class DictLiteral(ASTNode):
|
|
260
|
+
"""Dict literal: {key: value, ...}"""
|
|
261
|
+
|
|
262
|
+
def __init__(self, pairs, line=None, column=None):
|
|
263
|
+
super().__init__(line, column)
|
|
264
|
+
self.pairs = pairs # List of (key_expr, value_expr)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class TupleLiteral(ASTNode):
|
|
268
|
+
"""Tuple literal: (1, 2, 3)"""
|
|
269
|
+
|
|
270
|
+
def __init__(self, elements, line=None, column=None):
|
|
271
|
+
super().__init__(line, column)
|
|
272
|
+
self.elements = elements
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class Identifier(ASTNode):
|
|
276
|
+
"""Variable reference: x"""
|
|
277
|
+
|
|
278
|
+
def __init__(self, name, line=None, column=None):
|
|
279
|
+
super().__init__(line, column)
|
|
280
|
+
self.name = name
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class MeExpression(ASTNode):
|
|
284
|
+
"""Self reference: me"""
|
|
285
|
+
|
|
286
|
+
def __init__(self, line=None, column=None):
|
|
287
|
+
super().__init__(line, column)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
class BinaryOp(ASTNode):
|
|
291
|
+
"""Binary operation: a + b, a * b, etc."""
|
|
292
|
+
|
|
293
|
+
def __init__(self, left, op, right, line=None, column=None):
|
|
294
|
+
super().__init__(line, column)
|
|
295
|
+
self.left = left
|
|
296
|
+
self.op = op # '+', '-', '*', '/', '//', '%', '**'
|
|
297
|
+
self.right = right
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class UnaryOp(ASTNode):
|
|
301
|
+
"""Unary operation: -x, nah x"""
|
|
302
|
+
|
|
303
|
+
def __init__(self, op, operand, line=None, column=None):
|
|
304
|
+
super().__init__(line, column)
|
|
305
|
+
self.op = op # '-', 'nah'
|
|
306
|
+
self.operand = operand
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class ComparisonOp(ASTNode):
|
|
310
|
+
"""Comparison: a == b, a < b, etc."""
|
|
311
|
+
|
|
312
|
+
def __init__(self, left, op, right, line=None, column=None):
|
|
313
|
+
super().__init__(line, column)
|
|
314
|
+
self.left = left
|
|
315
|
+
self.op = op # '==', '!=', '<', '>', '<=', '>='
|
|
316
|
+
self.right = right
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
class LogicalOp(ASTNode):
|
|
320
|
+
"""Logical operation: a also b, a either b"""
|
|
321
|
+
|
|
322
|
+
def __init__(self, left, op, right, line=None, column=None):
|
|
323
|
+
super().__init__(line, column)
|
|
324
|
+
self.left = left
|
|
325
|
+
self.op = op # 'also', 'either'
|
|
326
|
+
self.right = right
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
class FunctionCall(ASTNode):
|
|
330
|
+
"""Function call: name(args)"""
|
|
331
|
+
|
|
332
|
+
def __init__(self, callee, args, kwargs=None, line=None, column=None):
|
|
333
|
+
super().__init__(line, column)
|
|
334
|
+
self.callee = callee # Expression (Identifier, PropertyAccess, etc.)
|
|
335
|
+
self.args = args # List of expressions
|
|
336
|
+
self.kwargs = kwargs or {} # Dict of name -> expression
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
class PropertyAccess(ASTNode):
|
|
340
|
+
"""Property/method access: obj.prop"""
|
|
341
|
+
|
|
342
|
+
def __init__(self, object, property, line=None, column=None):
|
|
343
|
+
super().__init__(line, column)
|
|
344
|
+
self.object = object
|
|
345
|
+
self.property = property # String
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
class IndexAccess(ASTNode):
|
|
349
|
+
"""Index access: obj[index]"""
|
|
350
|
+
|
|
351
|
+
def __init__(self, object, index, line=None, column=None):
|
|
352
|
+
super().__init__(line, column)
|
|
353
|
+
self.object = object
|
|
354
|
+
self.index = index
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
class SliceAccess(ASTNode):
|
|
358
|
+
"""Slice access: obj[start:end:step]"""
|
|
359
|
+
|
|
360
|
+
def __init__(self, object, start, end, step=None, line=None, column=None):
|
|
361
|
+
super().__init__(line, column)
|
|
362
|
+
self.object = object
|
|
363
|
+
self.start = start
|
|
364
|
+
self.end = end
|
|
365
|
+
self.step = step
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
class PipelineOp(ASTNode):
|
|
369
|
+
"""Pipeline: expr |> func"""
|
|
370
|
+
|
|
371
|
+
def __init__(self, left, right, line=None, column=None):
|
|
372
|
+
super().__init__(line, column)
|
|
373
|
+
self.left = left
|
|
374
|
+
self.right = right # Function call or identifier
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
class QuickFunction(ASTNode):
|
|
378
|
+
"""Lambda: quick(params): expr"""
|
|
379
|
+
|
|
380
|
+
def __init__(self, params, body, line=None, column=None):
|
|
381
|
+
super().__init__(line, column)
|
|
382
|
+
self.params = params
|
|
383
|
+
self.body = body # Single expression
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
class ListComprehension(ASTNode):
|
|
387
|
+
"""List comprehension: [expr each var within iterable when condition]"""
|
|
388
|
+
|
|
389
|
+
def __init__(self, expression, variable, iterable, condition=None, line=None, column=None):
|
|
390
|
+
super().__init__(line, column)
|
|
391
|
+
self.expression = expression
|
|
392
|
+
self.variable = variable
|
|
393
|
+
self.iterable = iterable
|
|
394
|
+
self.condition = condition
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
class AttributeAssignment(ASTNode):
|
|
398
|
+
"""Attribute assignment: obj.attr = value"""
|
|
399
|
+
|
|
400
|
+
def __init__(self, object, attribute, value, line=None, column=None):
|
|
401
|
+
super().__init__(line, column)
|
|
402
|
+
self.object = object
|
|
403
|
+
self.attribute = attribute
|
|
404
|
+
self.value = value
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
class IndexAssignment(ASTNode):
|
|
408
|
+
"""Index assignment: obj[idx] = value"""
|
|
409
|
+
|
|
410
|
+
def __init__(self, object, index, value, line=None, column=None):
|
|
411
|
+
super().__init__(line, column)
|
|
412
|
+
self.object = object
|
|
413
|
+
self.index = index
|
|
414
|
+
self.value = value
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Neuron Bytecode Compiler
|
|
3
|
+
========================
|
|
4
|
+
Compiles AST to bytecode and provides a VM for execution.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import struct
|
|
8
|
+
import pickle
|
|
9
|
+
import os
|
|
10
|
+
from enum import IntEnum, auto
|
|
11
|
+
|
|
12
|
+
from neuron import ast_nodes as ast
|
|
13
|
+
from neuron.lexer import Lexer
|
|
14
|
+
from neuron.parser import Parser
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class OpCode(IntEnum):
|
|
18
|
+
LOAD_CONST = 0
|
|
19
|
+
LOAD_VAR = 1
|
|
20
|
+
STORE_VAR = 2
|
|
21
|
+
LOAD_ATTR = 3
|
|
22
|
+
STORE_ATTR = 4
|
|
23
|
+
BINARY_ADD = 10
|
|
24
|
+
BINARY_SUB = 11
|
|
25
|
+
BINARY_MUL = 12
|
|
26
|
+
BINARY_DIV = 13
|
|
27
|
+
BINARY_MOD = 14
|
|
28
|
+
BINARY_POW = 15
|
|
29
|
+
BINARY_FLOORDIV = 16
|
|
30
|
+
COMPARE_EQ = 20
|
|
31
|
+
COMPARE_NE = 21
|
|
32
|
+
COMPARE_LT = 22
|
|
33
|
+
COMPARE_GT = 23
|
|
34
|
+
COMPARE_LE = 24
|
|
35
|
+
COMPARE_GE = 25
|
|
36
|
+
COMPARE_IN = 26
|
|
37
|
+
UNARY_NEG = 30
|
|
38
|
+
UNARY_NOT = 31
|
|
39
|
+
JUMP = 40
|
|
40
|
+
JUMP_IF_FALSE = 41
|
|
41
|
+
JUMP_IF_TRUE = 42
|
|
42
|
+
CALL_FUNCTION = 50
|
|
43
|
+
RETURN_VALUE = 51
|
|
44
|
+
MAKE_FUNCTION = 52
|
|
45
|
+
MAKE_LIST = 53
|
|
46
|
+
MAKE_DICT = 54
|
|
47
|
+
GET_INDEX = 55
|
|
48
|
+
SET_INDEX = 56
|
|
49
|
+
POP_TOP = 60
|
|
50
|
+
DUP_TOP = 61
|
|
51
|
+
BUILD_CLASS = 62
|
|
52
|
+
PIPE = 63
|
|
53
|
+
IMPORT = 64
|
|
54
|
+
PRINT = 65
|
|
55
|
+
NOP = 99
|
|
56
|
+
HALT = 100
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class BytecodeChunk:
|
|
60
|
+
"""A compiled chunk of bytecode."""
|
|
61
|
+
def __init__(self, name="<module>"):
|
|
62
|
+
self.name = name
|
|
63
|
+
self.code = [] # List of (opcode, operand) tuples
|
|
64
|
+
self.constants = [] # Constant pool
|
|
65
|
+
self.names = [] # Variable name pool
|
|
66
|
+
self.line_map = {} # instruction_index -> source_line
|
|
67
|
+
|
|
68
|
+
def emit(self, opcode, operand=0, line=0):
|
|
69
|
+
idx = len(self.code)
|
|
70
|
+
self.code.append((opcode, operand))
|
|
71
|
+
self.line_map[idx] = line
|
|
72
|
+
return idx
|
|
73
|
+
|
|
74
|
+
def add_constant(self, value):
|
|
75
|
+
if value in self.constants:
|
|
76
|
+
return self.constants.index(value)
|
|
77
|
+
self.constants.append(value)
|
|
78
|
+
return len(self.constants) - 1
|
|
79
|
+
|
|
80
|
+
def add_name(self, name):
|
|
81
|
+
if name in self.names:
|
|
82
|
+
return self.names.index(name)
|
|
83
|
+
self.names.append(name)
|
|
84
|
+
return len(self.names) - 1
|
|
85
|
+
|
|
86
|
+
def patch_jump(self, offset, target=None):
|
|
87
|
+
"""Patch a jump instruction's target."""
|
|
88
|
+
if target is None:
|
|
89
|
+
target = len(self.code)
|
|
90
|
+
opcode, _ = self.code[offset]
|
|
91
|
+
self.code[offset] = (opcode, target)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class Compiler:
|
|
95
|
+
"""Compiles Neuron AST to bytecode."""
|
|
96
|
+
|
|
97
|
+
def compile_file(self, input_path, output_path=None):
|
|
98
|
+
with open(input_path, 'r', encoding='utf-8') as f:
|
|
99
|
+
source = f.read()
|
|
100
|
+
|
|
101
|
+
chunk = self.compile_source(source, input_path)
|
|
102
|
+
|
|
103
|
+
if output_path is None:
|
|
104
|
+
output_path = input_path.replace('.nl', '.nlc')
|
|
105
|
+
|
|
106
|
+
with open(output_path, 'wb') as f:
|
|
107
|
+
pickle.dump(chunk, f)
|
|
108
|
+
|
|
109
|
+
return chunk
|
|
110
|
+
|
|
111
|
+
def compile_source(self, source, filename="<stdin>"):
|
|
112
|
+
lexer = Lexer(source, filename)
|
|
113
|
+
tokens = lexer.tokenize()
|
|
114
|
+
parser = Parser(tokens, source, filename)
|
|
115
|
+
program = parser.parse()
|
|
116
|
+
|
|
117
|
+
chunk = BytecodeChunk(filename)
|
|
118
|
+
self._compile_node(program, chunk)
|
|
119
|
+
chunk.emit(OpCode.HALT)
|
|
120
|
+
return chunk
|
|
121
|
+
|
|
122
|
+
def _compile_node(self, node, chunk):
|
|
123
|
+
method = f"_compile_{type(node).__name__}"
|
|
124
|
+
compiler = getattr(self, method, None)
|
|
125
|
+
if compiler:
|
|
126
|
+
return compiler(node, chunk)
|
|
127
|
+
# Fallback: skip unknown nodes
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
def _compile_Program(self, node, chunk):
|
|
131
|
+
for stmt in node.statements:
|
|
132
|
+
self._compile_node(stmt, chunk)
|
|
133
|
+
|
|
134
|
+
def _compile_NumberLiteral(self, node, chunk):
|
|
135
|
+
idx = chunk.add_constant(node.value)
|
|
136
|
+
chunk.emit(OpCode.LOAD_CONST, idx, node.line)
|
|
137
|
+
|
|
138
|
+
def _compile_StringLiteral(self, node, chunk):
|
|
139
|
+
idx = chunk.add_constant(node.value)
|
|
140
|
+
chunk.emit(OpCode.LOAD_CONST, idx, node.line)
|
|
141
|
+
|
|
142
|
+
def _compile_BooleanLiteral(self, node, chunk):
|
|
143
|
+
idx = chunk.add_constant(node.value)
|
|
144
|
+
chunk.emit(OpCode.LOAD_CONST, idx, node.line)
|
|
145
|
+
|
|
146
|
+
def _compile_NothingLiteral(self, node, chunk):
|
|
147
|
+
idx = chunk.add_constant(None)
|
|
148
|
+
chunk.emit(OpCode.LOAD_CONST, idx, node.line)
|
|
149
|
+
|
|
150
|
+
def _compile_Identifier(self, node, chunk):
|
|
151
|
+
idx = chunk.add_name(node.name)
|
|
152
|
+
chunk.emit(OpCode.LOAD_VAR, idx, node.line)
|
|
153
|
+
|
|
154
|
+
def _compile_Assignment(self, node, chunk):
|
|
155
|
+
self._compile_node(node.value, chunk)
|
|
156
|
+
idx = chunk.add_name(node.target)
|
|
157
|
+
chunk.emit(OpCode.STORE_VAR, idx, node.line)
|
|
158
|
+
|
|
159
|
+
def _compile_ExpressionStatement(self, node, chunk):
|
|
160
|
+
self._compile_node(node.expression, chunk)
|
|
161
|
+
chunk.emit(OpCode.POP_TOP)
|
|
162
|
+
|
|
163
|
+
def _compile_BinaryOp(self, node, chunk):
|
|
164
|
+
self._compile_node(node.left, chunk)
|
|
165
|
+
self._compile_node(node.right, chunk)
|
|
166
|
+
op_map = {
|
|
167
|
+
'+': OpCode.BINARY_ADD, '-': OpCode.BINARY_SUB,
|
|
168
|
+
'*': OpCode.BINARY_MUL, '/': OpCode.BINARY_DIV,
|
|
169
|
+
'%': OpCode.BINARY_MOD, '**': OpCode.BINARY_POW,
|
|
170
|
+
'//': OpCode.BINARY_FLOORDIV,
|
|
171
|
+
}
|
|
172
|
+
chunk.emit(op_map[node.op], 0, node.line)
|
|
173
|
+
|
|
174
|
+
def _compile_ComparisonOp(self, node, chunk):
|
|
175
|
+
self._compile_node(node.left, chunk)
|
|
176
|
+
self._compile_node(node.right, chunk)
|
|
177
|
+
op_map = {
|
|
178
|
+
'==': OpCode.COMPARE_EQ, '!=': OpCode.COMPARE_NE,
|
|
179
|
+
'<': OpCode.COMPARE_LT, '>': OpCode.COMPARE_GT,
|
|
180
|
+
'<=': OpCode.COMPARE_LE, '>=': OpCode.COMPARE_GE,
|
|
181
|
+
'within': OpCode.COMPARE_IN,
|
|
182
|
+
}
|
|
183
|
+
chunk.emit(op_map[node.op], 0, node.line)
|
|
184
|
+
|
|
185
|
+
def _compile_ReturnStatement(self, node, chunk):
|
|
186
|
+
if node.value:
|
|
187
|
+
self._compile_node(node.value, chunk)
|
|
188
|
+
else:
|
|
189
|
+
idx = chunk.add_constant(None)
|
|
190
|
+
chunk.emit(OpCode.LOAD_CONST, idx)
|
|
191
|
+
chunk.emit(OpCode.RETURN_VALUE, 0, node.line)
|