brasa-lang 0.1.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.
Files changed (31) hide show
  1. brasa_lang-0.1.0/PKG-INFO +6 -0
  2. brasa_lang-0.1.0/README.md +3 -0
  3. brasa_lang-0.1.0/brasa/__init__.py +1 -0
  4. brasa_lang-0.1.0/brasa/cli.py +14 -0
  5. brasa_lang-0.1.0/brasa/core/__init__.py +0 -0
  6. brasa_lang-0.1.0/brasa/core/nodes/__init__.py +0 -0
  7. brasa_lang-0.1.0/brasa/core/nodes/basics.py +13 -0
  8. brasa_lang-0.1.0/brasa/core/nodes/operators.py +14 -0
  9. brasa_lang-0.1.0/brasa/core/nodes/statements.py +85 -0
  10. brasa_lang-0.1.0/brasa/core/nodes/types.py +39 -0
  11. brasa_lang-0.1.0/brasa/core/nodes/values.py +36 -0
  12. brasa_lang-0.1.0/brasa/core/types/__init__.py +0 -0
  13. brasa_lang-0.1.0/brasa/core/types/lvalues.py +33 -0
  14. brasa_lang-0.1.0/brasa/core/types/operators.py +21 -0
  15. brasa_lang-0.1.0/brasa/interpreter/__init__.py +0 -0
  16. brasa_lang-0.1.0/brasa/interpreter/interpreter.py +301 -0
  17. brasa_lang-0.1.0/brasa/interpreter/signals.py +13 -0
  18. brasa_lang-0.1.0/brasa/parser/__init__.py +0 -0
  19. brasa_lang-0.1.0/brasa/parser/ast_builder.py +300 -0
  20. brasa_lang-0.1.0/brasa/repl.py +52 -0
  21. brasa_lang-0.1.0/brasa/runner.py +48 -0
  22. brasa_lang-0.1.0/brasa/runtime/__init__.py +0 -0
  23. brasa_lang-0.1.0/brasa/runtime/scope.py +21 -0
  24. brasa_lang-0.1.0/brasa/runtime/world.py +35 -0
  25. brasa_lang-0.1.0/brasa_lang.egg-info/PKG-INFO +6 -0
  26. brasa_lang-0.1.0/brasa_lang.egg-info/SOURCES.txt +29 -0
  27. brasa_lang-0.1.0/brasa_lang.egg-info/dependency_links.txt +1 -0
  28. brasa_lang-0.1.0/brasa_lang.egg-info/entry_points.txt +2 -0
  29. brasa_lang-0.1.0/brasa_lang.egg-info/top_level.txt +1 -0
  30. brasa_lang-0.1.0/pyproject.toml +12 -0
  31. brasa_lang-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: brasa-lang
3
+ Version: 0.1.0
4
+ Summary: Brasa programming language
5
+ Author: Adriano
6
+ Requires-Python: >=3.10
@@ -0,0 +1,3 @@
1
+ # Brasa
2
+
3
+ This is a high-level programming language which provides an more robust alternative to VisuAlg and Portugol.
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,14 @@
1
+ # brasa/cli.py
2
+
3
+ import sys
4
+ from brasa.runner import run_file
5
+ from brasa.repl import repl
6
+
7
+ def main():
8
+ if len(sys.argv) > 1:
9
+ run_file(sys.argv[1])
10
+ else:
11
+ repl()
12
+
13
+ if __name__=='__main__':
14
+ main()
File without changes
File without changes
@@ -0,0 +1,13 @@
1
+ from dataclasses import dataclass
2
+
3
+ @dataclass
4
+ class Program:
5
+ statements:list[any]
6
+
7
+ @dataclass
8
+ class Identifier:
9
+ name:str
10
+
11
+ @dataclass
12
+ class Block:
13
+ statements:any
@@ -0,0 +1,14 @@
1
+ from dataclasses import dataclass
2
+
3
+ from brasa.core.types.operators import BinaryOperationEnum,UnaryOperationEnum
4
+
5
+ @dataclass
6
+ class BinaryOperation:
7
+ left:any
8
+ op:BinaryOperationEnum
9
+ right:any
10
+
11
+ @dataclass
12
+ class UnaryOperation:
13
+ op:UnaryOperationEnum
14
+ expr:any
@@ -0,0 +1,85 @@
1
+ from dataclasses import dataclass
2
+
3
+ from brasa.core.nodes.types import Type
4
+ from brasa.core.nodes.values import Value
5
+
6
+ # ---------------- VARIABLES ----------------
7
+
8
+ @dataclass
9
+ class VariableDeclarationStatement:
10
+ id:str
11
+ type:Type
12
+ expr:Value
13
+ is_const:bool
14
+
15
+ @dataclass
16
+ class AssignmentStatement:
17
+ target:str
18
+ expr:Value
19
+
20
+ @dataclass
21
+ class CompoundAssignmentStatement:
22
+ target:any
23
+ op:any
24
+ expr:any
25
+
26
+ @dataclass
27
+ class PostfixStatement:
28
+ target:any
29
+ op:any
30
+
31
+ @dataclass
32
+ class IndexExpression:
33
+ base:any
34
+ index:any
35
+
36
+ # ---------------- CONTROL FLOW ----------------
37
+
38
+ @dataclass
39
+ class IfStatement:
40
+ condition:any
41
+ then_block:any
42
+ else_branch:any
43
+
44
+ @dataclass
45
+ class WhileStatement:
46
+ condition:any
47
+ body:any
48
+
49
+ @dataclass
50
+ class BreakStatement:
51
+ pass
52
+
53
+ @dataclass
54
+ class ContinueStatement:
55
+ pass
56
+
57
+ # ---------------- FUNCTIONS ----------------
58
+
59
+ @dataclass
60
+ class FunctionDeclaration:
61
+ name:str
62
+ params:any
63
+ return_type:any
64
+ body:any
65
+
66
+ @dataclass
67
+ class LambdaExpression:
68
+ params:any
69
+ return_type:any
70
+ body:any
71
+
72
+ @dataclass
73
+ class CallExpression:
74
+ callee:any
75
+ args:any
76
+
77
+ @dataclass
78
+ class ReturnStatement:
79
+ expr:any
80
+
81
+ # ---------------- REMOVE LATER ----------------
82
+
83
+ @dataclass
84
+ class PrintStatement:
85
+ expr:Value
@@ -0,0 +1,39 @@
1
+ from dataclasses import dataclass
2
+
3
+ @dataclass
4
+ class Type:
5
+ pass
6
+
7
+ @dataclass
8
+ class IntegerType(Type):
9
+ pass
10
+
11
+ @dataclass
12
+ class FloatType(Type):
13
+ pass
14
+
15
+ @dataclass
16
+ class StringType:
17
+ pass
18
+
19
+ @dataclass
20
+ class NullableType(Type):
21
+ base_type:Type
22
+
23
+ @dataclass
24
+ class BooleanType(Type):
25
+ pass
26
+
27
+ @dataclass
28
+ class ArrayType(Type):
29
+ element_type:Type
30
+ size:int
31
+
32
+ @dataclass
33
+ class VoidType(Type):
34
+ pass
35
+
36
+ @dataclass
37
+ class FunctionType(Type):
38
+ param_types:list[Type]
39
+ return_type:Type
@@ -0,0 +1,36 @@
1
+ from dataclasses import dataclass
2
+
3
+ @dataclass
4
+ class Value:
5
+ pass
6
+
7
+ @dataclass
8
+ class IntegerValue(Value):
9
+ value:int
10
+
11
+ @dataclass
12
+ class FloatValue(Value):
13
+ value:float
14
+
15
+ @dataclass
16
+ class StringLiteral:
17
+ value:str
18
+
19
+ @dataclass
20
+ class NullValue(Value):
21
+ pass
22
+
23
+ @dataclass
24
+ class BooleanValue(Value):
25
+ value:bool
26
+
27
+ @dataclass
28
+ class ArrayValue(Value):
29
+ elements:list[Value]
30
+
31
+ @dataclass
32
+ class FunctionValue:
33
+ params:any
34
+ body:any
35
+ return_type:any
36
+ closure_scope:any
File without changes
@@ -0,0 +1,33 @@
1
+ class LValue:
2
+ def get(self,interpreter):
3
+ raise NotImplementedError
4
+
5
+ def set(self,interpreter,value):
6
+ raise NotImplementedError
7
+
8
+ class VarLValue(LValue):
9
+ def __init__(self,name):
10
+ self.name = name
11
+
12
+ def get(self,interpreter):
13
+ var_id = interpreter.current_scope.lookup(self.name)
14
+ return interpreter.world.get_value(var_id)
15
+
16
+ def set(self,interpreter,value):
17
+ var_id = interpreter.current_scope.lookup(self.name)
18
+ interpreter.world.set_value(var_id,value)
19
+
20
+ class IndexLValue(LValue):
21
+ def __init__(self,base,index_expr):
22
+ self.base=base
23
+ self.index_expr=index_expr
24
+
25
+ def get(self,interpreter):
26
+ arr=self.base.get(interpreter)
27
+ index=interpreter.visit(self.index_expr)
28
+ return arr[index]
29
+
30
+ def set(self,interpreter,value):
31
+ arr=self.base.get(interpreter)
32
+ index=interpreter.visit(self.index_expr)
33
+ arr[index]=value
@@ -0,0 +1,21 @@
1
+ from enum import Enum, auto
2
+
3
+ class BinaryOperationEnum(Enum):
4
+ ADD = auto()
5
+ SUB = auto()
6
+ MUL = auto()
7
+ DIV = auto()
8
+
9
+ GT = auto()
10
+ LT = auto()
11
+ GE = auto()
12
+ LE = auto()
13
+ EQ = auto()
14
+ NE = auto()
15
+
16
+ AND = auto()
17
+ OR = auto()
18
+
19
+ class UnaryOperationEnum(Enum):
20
+ NEG = auto()
21
+ NOT = auto()
File without changes
@@ -0,0 +1,301 @@
1
+ from brasa.runtime.scope import Scope
2
+ from brasa.runtime.world import World
3
+
4
+ from brasa.core.nodes.values import FunctionValue
5
+ from brasa.core.types.operators import BinaryOperationEnum,UnaryOperationEnum
6
+
7
+ from brasa.interpreter.signals import BreakSignal,ContinueSignal,ReturnSignal
8
+
9
+ class Interpreter:
10
+ def __init__(self):
11
+ self.current_scope=Scope()
12
+ self.world=World()
13
+
14
+ def visit(self,node):
15
+ method_name=f'visit_{type(node).__name__}'
16
+ visitor=getattr(
17
+ self,
18
+ method_name,
19
+ self.generic_visit
20
+ )
21
+
22
+ return visitor(node)
23
+
24
+ def generic_visit(self, node):
25
+ raise Exception(f'Method visit_{type(node).__name__} does not exist.')
26
+
27
+ # ---------------- BASICS ----------------
28
+
29
+ def visit_Program(self,node):
30
+ for statement in node.statements:
31
+ self.visit(statement)
32
+
33
+ def visit_Block(self, node):
34
+ old_scope = self.current_scope
35
+ self.current_scope = Scope(parent=old_scope)
36
+
37
+ for stmt in node.statements:
38
+ self.visit(stmt)
39
+
40
+ self.current_scope = old_scope
41
+
42
+ # ---------------- VARIABLES ----------------
43
+
44
+ def visit_Identifier(self, node):
45
+ var_id = self.current_scope.lookup(node.name)
46
+ return self.world.get_value(var_id)
47
+
48
+ def visit_VariableDeclarationStatement(self,node):
49
+ value = self.visit(node.expr) if node.expr is not None else None
50
+
51
+ var_id=self.world.create(
52
+ type_=node.type,
53
+ value=value,
54
+ is_const=node.is_const
55
+ )
56
+
57
+ self.current_scope.declare(node.id.name,var_id)
58
+
59
+ def visit_AssignmentStatement(self,node):
60
+ # var_id = self.current_scope.lookup(node.id.name)
61
+
62
+ # if self.world.is_const(var_id):
63
+ # raise Exception(f"Cannot assign to const '{node.id.name}'")
64
+
65
+ # value = self.visit(node.expr)
66
+ # self.world.set_value(var_id, value)
67
+ value = self.visit(node.expr)
68
+ node.target.set(self, value)
69
+
70
+ def visit_CompoundAssignmentStatement(self, node):
71
+ # var_id = self.current_scope.lookup(node.id.name)
72
+ # current=self.world.get_value(var_id)
73
+ # value = self.visit(node.expr)
74
+
75
+ # if node.op == BinaryOperationEnum.ADD:
76
+ # result = current + value
77
+ # elif node.op == BinaryOperationEnum.SUB:
78
+ # result = current - value
79
+ # elif node.op == BinaryOperationEnum.MUL:
80
+ # result = current * value
81
+ # elif node.op == BinaryOperationEnum.DIV:
82
+ # result = current / value
83
+
84
+ # self.world.set_value(var_id,result)
85
+ current = node.target.get(self)
86
+ value = self.visit(node.expr)
87
+
88
+ if node.op==BinaryOperationEnum.ADD:
89
+ result=current+value
90
+ elif node.op==BinaryOperationEnum.SUB:
91
+ result=current-value
92
+ elif node.op==BinaryOperationEnum.MUL:
93
+ result= current*value
94
+ elif node.op==BinaryOperationEnum.DIV:
95
+ result=current/value
96
+
97
+ node.target.set(self,result)
98
+
99
+ def visit_PostfixStatement(self,node):
100
+ # var_id = self.current_scope.lookup(node.id.name)
101
+ # current=self.world.get_value(var_id)
102
+
103
+ # if node.op==BinaryOperationEnum.ADD:
104
+ # self.world.set_value(var_id,current+1)
105
+ # else:
106
+ # self.world.set_value(var_id,current-1)
107
+ current=node.target.get(self)
108
+
109
+ if node.op==BinaryOperationEnum.ADD:
110
+ new_value=current+1
111
+ else:
112
+ new_value=current-1
113
+
114
+ node.target.set(self,new_value)
115
+
116
+ return current
117
+
118
+ # ---------------- VALUES ----------------
119
+
120
+ def visit_IntegerValue(self,node):
121
+ return node.value
122
+
123
+ def visit_FloatValue(self,node):
124
+ return node.value
125
+
126
+ def visit_StringLiteral(self,node):
127
+ return node.value
128
+
129
+ def visit_NullValue(self,node):
130
+ return None
131
+
132
+ def visit_BooleanValue(self,node):
133
+ return node.value
134
+
135
+ def visit_ArrayValue(self,node):
136
+ return [self.visit(elem) for elem in node.elements]
137
+
138
+ def visit_IndexExpression(self, node):
139
+ arr = self.visit(node.base)
140
+ index = self.visit(node.index)
141
+ return arr[index]
142
+
143
+ # ---------------- OPERATORS ----------------
144
+
145
+ def visit_BinaryOperation(self, node):
146
+ op = node.op
147
+
148
+ if op == BinaryOperationEnum.AND:
149
+ left=self.visit(node.left)
150
+
151
+ if not left:
152
+ return False
153
+
154
+ right=self.visit(node.right)
155
+ return bool(right)
156
+
157
+ if node.op == BinaryOperationEnum.OR:
158
+ left = self.visit(node.left)
159
+
160
+ if left:
161
+ return True
162
+
163
+ right = self.visit(node.right)
164
+ return bool(right)
165
+
166
+ left = self.visit(node.left)
167
+ right = self.visit(node.right)
168
+
169
+ if op == BinaryOperationEnum.ADD:
170
+ return left + right
171
+ if op == BinaryOperationEnum.SUB:
172
+ return left - right
173
+ if op == BinaryOperationEnum.MUL:
174
+ return left * right
175
+ if op == BinaryOperationEnum.DIV:
176
+ return left / right
177
+
178
+ if op == BinaryOperationEnum.GT:
179
+ return left > right
180
+ if op == BinaryOperationEnum.LT:
181
+ return left < right
182
+ if op == BinaryOperationEnum.GE:
183
+ return left >= right
184
+ if op == BinaryOperationEnum.LE:
185
+ return left <= right
186
+ if op == BinaryOperationEnum.EQ:
187
+ return left == right
188
+ if op == BinaryOperationEnum.NE:
189
+ return left != right
190
+
191
+ raise Exception(f"Unknown operator: {op}")
192
+
193
+ def visit_UnaryOperation(self, node):
194
+ value = self.visit(node.expr)
195
+
196
+ if node.op == UnaryOperationEnum.NEG:
197
+ return -value
198
+
199
+ if node.op == UnaryOperationEnum.NOT:
200
+ return not value
201
+
202
+ raise Exception(f"Unknown unary operator: {node.op}")
203
+
204
+ # ---------------- CONTROL FLOW ----------------
205
+
206
+ def visit_IfStatement(self, node):
207
+ condition = self.visit(node.condition)
208
+
209
+ if condition:
210
+ return self.visit(node.then_block)
211
+
212
+ if node.else_branch:
213
+ return self.visit(node.else_branch)
214
+
215
+ def visit_WhileStatement(self, node):
216
+ while self.visit(node.condition):
217
+ try:
218
+ self.visit(node.body)
219
+
220
+ except ContinueSignal:
221
+ continue
222
+
223
+ except BreakSignal:
224
+ break
225
+
226
+ def visit_BreakStatement(self, node):
227
+ raise BreakSignal()
228
+
229
+ def visit_ContinueStatement(self, node):
230
+ raise ContinueSignal()
231
+
232
+ # ---------------- FUNCTIONS ----------------
233
+
234
+ def visit_FunctionDeclaration(self, node):
235
+ func=FunctionValue(
236
+ params=node.params,
237
+ body=node.body,
238
+ return_type=node.return_type,
239
+ closure_scope=self.current_scope
240
+ )
241
+
242
+ var_id=self.world.create(
243
+ type_=None,
244
+ value=func,
245
+ is_const=True
246
+ )
247
+
248
+ self.current_scope.declare(node.name.name, var_id)
249
+
250
+ def visit_LambdaExpression(self, node):
251
+ return FunctionValue(
252
+ params=node.params,
253
+ body=node.body,
254
+ return_type=node.return_type,
255
+ closure_scope=self.current_scope,
256
+ )
257
+
258
+ def visit_CallExpression(self, node):
259
+ func=self.visit(node.callee)
260
+ args=[self.visit(arg) for arg in node.args]
261
+
262
+ new_scope=Scope(parent=func.closure_scope)
263
+
264
+ for param, arg in zip(func.params, args):
265
+ var_id = self.world.create(type_=param[0], value=arg)
266
+ new_scope.declare(param[1].name, var_id)
267
+
268
+ old_scope=self.current_scope
269
+ self.current_scope=new_scope
270
+
271
+ try:
272
+ self.visit(func.body)
273
+ result=None
274
+ except ReturnSignal as r:
275
+ result=r.value
276
+
277
+ self.current_scope=old_scope
278
+
279
+ return result
280
+
281
+ def visit_ReturnStatement(self, node):
282
+ value=None
283
+
284
+ if node.expr:
285
+ value=self.visit(node.expr)
286
+
287
+ raise ReturnSignal(value)
288
+
289
+ # ---------------- REMOVE LATER ----------------
290
+
291
+ def visit_PrintStatement(self, node):
292
+ value = self.visit(node.expr)
293
+
294
+ if value is None:
295
+ print('nulo')
296
+ elif value is True:
297
+ print('verdadeiro')
298
+ elif value is False:
299
+ print('falso')
300
+ else:
301
+ print(value)
@@ -0,0 +1,13 @@
1
+ from dataclasses import dataclass
2
+
3
+ @dataclass
4
+ class BreakSignal(Exception):
5
+ pass
6
+
7
+ @dataclass
8
+ class ContinueSignal(Exception):
9
+ pass
10
+
11
+ @dataclass
12
+ class ReturnSignal(Exception):
13
+ value:any
File without changes
@@ -0,0 +1,300 @@
1
+ from lark import Transformer,v_args
2
+
3
+ from brasa.core.nodes.basics import *
4
+ from brasa.core.nodes.statements import *
5
+ from brasa.core.nodes.types import *
6
+ from brasa.core.nodes.values import *
7
+ from brasa.core.types.lvalues import *
8
+
9
+ from brasa.core.nodes.operators import BinaryOperation,UnaryOperation
10
+ from brasa.core.types.operators import BinaryOperationEnum,UnaryOperationEnum
11
+
12
+ class ASTBuilder(Transformer):
13
+ # ---------------- PROGRAM ----------------
14
+
15
+ def program(self,statements):
16
+ return Program(statements=statements)
17
+
18
+ @v_args(inline=True)
19
+ def statement(self, item):
20
+ return item
21
+
22
+ def block(self,statements):
23
+ return Block(list(statements))
24
+
25
+ # ---------------- VARIABLES ----------------
26
+
27
+ def ID(self,name):
28
+ return Identifier(name=str(name))
29
+
30
+ @v_args(inline=True)
31
+ def var_declaration(self,const,type_,id,expr):
32
+ return VariableDeclarationStatement(
33
+ id=id,
34
+ type=type_,
35
+ expr=expr,
36
+ is_const=const is not None
37
+ )
38
+
39
+ @v_args(inline=True)
40
+ def var_declaration_null(self,const,type_,id):
41
+ return VariableDeclarationStatement(
42
+ id=id,
43
+ type=type_,
44
+ expr=NullValue(),
45
+ is_const=const is not None
46
+ )
47
+
48
+ @v_args(inline=True)
49
+ def assigment(self,id,expr):
50
+ return AssignmentStatement(
51
+ target=id,
52
+ expr=expr
53
+ )
54
+
55
+ @v_args(inline=True)
56
+ def compound_assignment(self,id,op,expr):
57
+ return CompoundAssignmentStatement(
58
+ target=id,
59
+ op=op,
60
+ expr=expr
61
+ )
62
+
63
+ @v_args(inline=True)
64
+ def postfix(self,id,op):
65
+ return PostfixStatement(
66
+ target=id,
67
+ op=op
68
+ )
69
+
70
+ def OP_POSTFIX(self, token):
71
+ return token.value
72
+
73
+ @v_args(inline=True)
74
+ def var_lvalue(self, id_):
75
+ return VarLValue(id_.name)
76
+
77
+
78
+ @v_args(inline=True)
79
+ def index_lvalue(self, base, index):
80
+ return IndexLValue(base, index)
81
+
82
+ # ---------------- TYPES ----------------
83
+
84
+ def int_type(self,_):
85
+ return IntegerType()
86
+
87
+ def float_type(self,_):
88
+ return FloatType()
89
+
90
+ @v_args(inline=True)
91
+ def nullable_type(self,type_):
92
+ return NullableType(base_type=type_)
93
+
94
+ def string_type(self,_):
95
+ return StringType()
96
+
97
+ def bool_type(self, _):
98
+ return BooleanType()
99
+
100
+ def void_type(self, _):
101
+ return VoidType()
102
+
103
+ @v_args(inline=True)
104
+ def array_type(self,element_type,size):
105
+ return ArrayType(
106
+ element_type=element_type,
107
+ size=size
108
+ )
109
+
110
+ # ---------------- LITERALS ----------------
111
+
112
+ @v_args(inline=True)
113
+ def integer_literal(self,value):
114
+ return IntegerValue(value=int(value))
115
+
116
+ @v_args(inline=True)
117
+ def float_literal(self,value):
118
+ return FloatValue(value=float(value))
119
+
120
+ @v_args(inline=True)
121
+ def string_literal(self, token):
122
+ return StringLiteral(value=token[1:-1])
123
+
124
+ def null_literal(self,_):
125
+ return NullValue()
126
+
127
+ def true_literal(self, _):
128
+ return BooleanValue(True)
129
+
130
+ def false_literal(self, _):
131
+ return BooleanValue(False)
132
+
133
+ @v_args(inline=True)
134
+ def array_literal(self,*elements):
135
+ if len(elements)==1 and elements[0] is None:
136
+ elements=[]
137
+
138
+ return ArrayValue(elements=elements)
139
+
140
+ @v_args(inline=True)
141
+ def index_expr(self, base, index):
142
+ return IndexExpression(base, index)
143
+
144
+ # ---------------- CONTROL FLOW ----------------
145
+
146
+ @v_args(inline=True)
147
+ def if_statement(self, cond, then_block, else_branch=None):
148
+ return IfStatement(cond, then_block, else_branch)
149
+
150
+ @v_args(inline=True)
151
+ def while_statement(self, condition, body):
152
+ return WhileStatement(condition, body)
153
+
154
+ def break_statement(self, _):
155
+ return BreakStatement()
156
+
157
+ def continue_statement(self, _):
158
+ return ContinueStatement()
159
+
160
+ # ---------------- OPERATORS ----------------
161
+
162
+ # ---------------- MATH ----------------
163
+
164
+ @v_args(inline=True)
165
+ def add(self, left, right):
166
+ return BinaryOperation(left, BinaryOperationEnum.ADD, right)
167
+
168
+ @v_args(inline=True)
169
+ def sub(self, left, right):
170
+ return BinaryOperation(left, BinaryOperationEnum.SUB, right)
171
+
172
+ @v_args(inline=True)
173
+ def mul(self, left, right):
174
+ return BinaryOperation(left, BinaryOperationEnum.MUL, right)
175
+
176
+ @v_args(inline=True)
177
+ def div(self, left, right):
178
+ return BinaryOperation(left, BinaryOperationEnum.DIV, right)
179
+
180
+ @v_args(inline=True)
181
+ def neg(self, value):
182
+ return UnaryOperation(UnaryOperationEnum.NEG, value)
183
+
184
+ @v_args(inline=True)
185
+ def OP_ASSIGN(self, token):
186
+ return {
187
+ '+=': BinaryOperationEnum.ADD,
188
+ '-=': BinaryOperationEnum.SUB,
189
+ '*=': BinaryOperationEnum.MUL,
190
+ '/=': BinaryOperationEnum.DIV,
191
+ }[token]
192
+
193
+ @v_args(inline=True)
194
+ def OP_POSTFIX(self, token):
195
+ if token=='++':
196
+ return BinaryOperationEnum.ADD
197
+
198
+ return BinaryOperationEnum.SUB
199
+
200
+ # ---------------- COMPARISONS ----------------
201
+
202
+ @v_args(inline=True)
203
+ def gt(self, left, right):
204
+ return BinaryOperation(left, BinaryOperationEnum.GT, right)
205
+
206
+ @v_args(inline=True)
207
+ def lt(self, left, right):
208
+ return BinaryOperation(left, BinaryOperationEnum.LT, right)
209
+
210
+ @v_args(inline=True)
211
+ def ge(self, left, right):
212
+ return BinaryOperation(left, BinaryOperationEnum.GE, right)
213
+
214
+ @v_args(inline=True)
215
+ def le(self, left, right):
216
+ return BinaryOperation(left, BinaryOperationEnum.LE, right)
217
+
218
+ @v_args(inline=True)
219
+ def eq(self, left, right):
220
+ return BinaryOperation(left, BinaryOperationEnum.EQ, right)
221
+
222
+ @v_args(inline=True)
223
+ def ne(self, left, right):
224
+ return BinaryOperation(left, BinaryOperationEnum.NE, right)
225
+
226
+ # ---------------- LOGICAL ----------------
227
+
228
+ @v_args(inline=True)
229
+ def and_op(self, left, right):
230
+ return BinaryOperation(left, BinaryOperationEnum.AND, right)
231
+
232
+ @v_args(inline=True)
233
+ def or_op(self, left, right):
234
+ return BinaryOperation(left, BinaryOperationEnum.OR, right)
235
+
236
+ @v_args(inline=True)
237
+ def not_op(self, value):
238
+ return UnaryOperation(UnaryOperationEnum.NOT, value)
239
+
240
+ # ---------------- FUNCTION ----------------
241
+
242
+ @v_args(inline=True)
243
+ def func_declaration(self,func_name,parameters,return_type,block):
244
+ return FunctionDeclaration(
245
+ name=func_name,
246
+ params=[] if parameters is None else parameters,
247
+ return_type=VoidType() if return_type is None else return_type,
248
+ body=block
249
+ )
250
+
251
+ @v_args(inline=True)
252
+ def func_type(self, params=None, return_type=None):
253
+ if params is None:
254
+ params = []
255
+ return FunctionType(params, return_type)
256
+
257
+ @v_args(inline=True)
258
+ def call_func(self,id,parameters):
259
+ return CallExpression(
260
+ callee=id,
261
+ args=[] if parameters is None else parameters
262
+ )
263
+
264
+ @v_args(inline=True)
265
+ def return_type(self, type_):
266
+ return type_
267
+
268
+ def args_list(self, params):
269
+ return params
270
+
271
+ def param_list(self, params):
272
+ return params
273
+
274
+ @v_args(inline=True)
275
+ def param(self, type_, name):
276
+ return (type_, name)
277
+
278
+ @v_args(inline=True)
279
+ def return_statement(self, expr=None):
280
+ return ReturnStatement(expr)
281
+
282
+ @v_args(inline=True)
283
+ def lambda_expr(self, params=None, return_type=None, body=None):
284
+ if params is None:
285
+ params = []
286
+
287
+ if return_type is None:
288
+ return_type = VoidType()
289
+
290
+ return LambdaExpression(
291
+ params=params,
292
+ return_type=return_type,
293
+ body=body
294
+ )
295
+
296
+ # ---------------- REMOVE LATER ----------------
297
+
298
+ @v_args(inline=True)
299
+ def print_variable(self,expr):
300
+ return PrintStatement(expr)
@@ -0,0 +1,52 @@
1
+ from brasa.runner import Interpreter
2
+ from brasa.runner import run_code
3
+
4
+ import readline
5
+
6
+ readline.read_history_file('.brasa_history')
7
+ readline.write_history_file('.brasa_history')
8
+
9
+ def repl():
10
+ interpreter=Interpreter()
11
+ buffer=''
12
+
13
+ print(r'''
14
+ ==========================================================
15
+ _______ _______ __ ________ __
16
+ | _ "\ /" \ /""\ /" ) /""\
17
+ (. |_) :)|: | / \ (: \___/ / \
18
+ |: \/ |_____/ ) /' /\ \ \___ \ /' /\ \
19
+ (| _ \\ // / // __' \ __/ \\ // __' \
20
+ |: |_) :)|: __ \ / / \\ \ /" \ :)/ / \\ \
21
+ (_______/ |__| \___)(___/ \___)(_______/(___/ \___)
22
+
23
+ ==========================================================
24
+
25
+ Type "exit" or "quit" to leave Brasa Interactive Environment
26
+ ''')
27
+
28
+ while True:
29
+ try:
30
+ prompt='>>> ' if not buffer else '... '
31
+ line=input(prompt)
32
+
33
+ if line.strip() in {'exit','quit'}:
34
+ break
35
+
36
+ buffer+=line+'\n'
37
+
38
+ try:
39
+ result=run_code(
40
+ buffer,
41
+ interpreter=interpreter
42
+ )
43
+
44
+ buffer=''
45
+
46
+ if result is not None:
47
+ print(result)
48
+ except Exception:
49
+ continue
50
+ except KeyboardInterrupt:
51
+ print('\nKeyboardInterrupt')
52
+ buffer=''
@@ -0,0 +1,48 @@
1
+ from pathlib import Path
2
+
3
+ from lark import Lark
4
+
5
+ from brasa.parser.ast_builder import ASTBuilder
6
+ from brasa.interpreter.interpreter import Interpreter
7
+
8
+ def load_grammar(grammar_path):
9
+ with open(
10
+ grammar_path,
11
+ 'r',
12
+ encoding='utf-8'
13
+ ) as g:
14
+ parser=Lark(
15
+ g.read(),
16
+ start='start',
17
+ maybe_placeholders=True
18
+ )
19
+
20
+ return parser
21
+
22
+ def run_code(
23
+ code:str,
24
+ interpreter=None
25
+ ):
26
+ parser=load_grammar(
27
+ Path(__file__).parent/'parser'/'grammar.lark'
28
+ )
29
+
30
+ raw_tree=parser.parse(code)
31
+ ast=ASTBuilder().transform(raw_tree)
32
+
33
+ if interpreter is None:
34
+ interpreter = Interpreter()
35
+
36
+ return interpreter.visit(ast)
37
+
38
+ def run_file(file_path:str):
39
+ file_path=Path(file_path).resolve()
40
+
41
+ if not file_path.exists():
42
+ print(f'Error: File "{file_path}" does not exist.')
43
+ return
44
+
45
+ with open(file_path,'r') as f:
46
+ code=f.read()
47
+
48
+ run_code(code)
File without changes
@@ -0,0 +1,21 @@
1
+ class Scope:
2
+ def __init__(self, parent=None):
3
+ self.parent = parent
4
+ self.symbols = {} # variable name -> entity id
5
+
6
+ # ---------------- DECLARE ----------------
7
+ def declare(self, name, var_id):
8
+ if name in self.symbols:
9
+ raise Exception(f'Error: Variable "{name}" has already been declared in this scope')
10
+
11
+ self.symbols[name] = var_id
12
+
13
+ # ---------------- LOOKUP ----------------
14
+ def lookup(self, name):
15
+ if name in self.symbols:
16
+ return self.symbols[name]
17
+
18
+ if self.parent:
19
+ return self.parent.lookup(name)
20
+
21
+ raise Exception(f'Variable "{name}" has not been found')
@@ -0,0 +1,35 @@
1
+ class World:
2
+ def __init__(self):
3
+ self.next_id = 0
4
+
5
+ self.types = {} # entity id -> Type
6
+ self.values = {} # entity id -> Value
7
+ self.const = set() # (entity id)[]
8
+
9
+ # ---------------- CREATE VARIABLE ----------------
10
+ def create(self, type_, value, is_const=False):
11
+ var_id = self.next_id
12
+ self.next_id += 1
13
+ self.types[var_id] = type_
14
+ self.values[var_id] = value
15
+
16
+ if is_const:
17
+ self.const.add(var_id)
18
+
19
+ return var_id
20
+
21
+ # ---------------- GETTERS ----------------
22
+ def get_type(self, var_id):
23
+ return self.types[var_id]
24
+
25
+ def get_value(self, var_id):
26
+ return self.values[var_id]
27
+
28
+ def set_value(self, var_id, value):
29
+ if var_id in self.const:
30
+ raise Exception('Cannot modify const variable')
31
+
32
+ self.values[var_id] = value
33
+
34
+ def is_const(self, var_id):
35
+ return var_id in self.const
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: brasa-lang
3
+ Version: 0.1.0
4
+ Summary: Brasa programming language
5
+ Author: Adriano
6
+ Requires-Python: >=3.10
@@ -0,0 +1,29 @@
1
+ README.md
2
+ pyproject.toml
3
+ brasa/__init__.py
4
+ brasa/cli.py
5
+ brasa/repl.py
6
+ brasa/runner.py
7
+ brasa/core/__init__.py
8
+ brasa/core/nodes/__init__.py
9
+ brasa/core/nodes/basics.py
10
+ brasa/core/nodes/operators.py
11
+ brasa/core/nodes/statements.py
12
+ brasa/core/nodes/types.py
13
+ brasa/core/nodes/values.py
14
+ brasa/core/types/__init__.py
15
+ brasa/core/types/lvalues.py
16
+ brasa/core/types/operators.py
17
+ brasa/interpreter/__init__.py
18
+ brasa/interpreter/interpreter.py
19
+ brasa/interpreter/signals.py
20
+ brasa/parser/__init__.py
21
+ brasa/parser/ast_builder.py
22
+ brasa/runtime/__init__.py
23
+ brasa/runtime/scope.py
24
+ brasa/runtime/world.py
25
+ brasa_lang.egg-info/PKG-INFO
26
+ brasa_lang.egg-info/SOURCES.txt
27
+ brasa_lang.egg-info/dependency_links.txt
28
+ brasa_lang.egg-info/entry_points.txt
29
+ brasa_lang.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ brasa = brasa.cli:main
@@ -0,0 +1 @@
1
+ brasa
@@ -0,0 +1,12 @@
1
+ [project]
2
+ name = "brasa-lang"
3
+ version = "0.1.0"
4
+ description = "Brasa programming language"
5
+ authors = [{name="Adriano"}]
6
+ requires-python = ">=3.10"
7
+
8
+ [project.scripts]
9
+ brasa = "brasa.cli:main"
10
+
11
+ [tool.setuptools.packages.find]
12
+ include = ["brasa*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+