indonesian_script 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.
- indonesian_script/Interpreter/AST_node/__init__.py +2 -0
- indonesian_script/Interpreter/AST_node/ast_nodes.py +267 -0
- indonesian_script/Interpreter/Builtins/KEYWORD.py +96 -0
- indonesian_script/Interpreter/Builtins/TYPES.py +28 -0
- indonesian_script/Interpreter/Builtins/__init__.py +2 -0
- indonesian_script/Interpreter/Builtins/builtins.py +140 -0
- indonesian_script/Interpreter/__init__.py +4 -0
- indonesian_script/Interpreter/interpreter.py +988 -0
- indonesian_script/Interpreter/transformer.py +560 -0
- indonesian_script/__init__.py +12 -0
- indonesian_script/__main__.py +11 -0
- indonesian_script/cli/__init__.py +2 -0
- indonesian_script/cli/main.py +196 -0
- indonesian_script/main.py +143 -0
- indonesian_script-0.1.10.dist-info/METADATA +117 -0
- indonesian_script-0.1.10.dist-info/RECORD +19 -0
- indonesian_script-0.1.10.dist-info/WHEEL +5 -0
- indonesian_script-0.1.10.dist-info/entry_points.txt +2 -0
- indonesian_script-0.1.10.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# ast_nodes.py
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import Any, Dict, Tuple, List, Optional, Union
|
|
4
|
+
|
|
5
|
+
class Node:
|
|
6
|
+
"""Base class for all AST nodes."""
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
# --- Program & Blocks ---
|
|
10
|
+
@dataclass
|
|
11
|
+
class Program(Node):
|
|
12
|
+
statements: Optional[List['Statement']]
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class Block(Node):
|
|
16
|
+
statements: Optional[List['Statement']]
|
|
17
|
+
|
|
18
|
+
# --- Statements ---
|
|
19
|
+
class Statement(Node):
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class VarDecl(Statement):
|
|
24
|
+
type_ann: 'Type'
|
|
25
|
+
name: str
|
|
26
|
+
value: Optional['Expression']
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class FinalDecl(Statement):
|
|
30
|
+
type_ann: 'Type'
|
|
31
|
+
name: str
|
|
32
|
+
value: 'Expression'
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class DefDecl(Statement):
|
|
36
|
+
type_ann: 'Type'
|
|
37
|
+
name: str
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class AliasDecl(Statement):
|
|
41
|
+
alias: str
|
|
42
|
+
target: str
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class Redecl(Statement):
|
|
46
|
+
name: str
|
|
47
|
+
value: 'Expression'
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class PointerDecl(Statement):
|
|
51
|
+
name: str
|
|
52
|
+
target: str
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
55
|
+
class UnpointerDecl(Statement):
|
|
56
|
+
name: str
|
|
57
|
+
target: str
|
|
58
|
+
|
|
59
|
+
@dataclass
|
|
60
|
+
class WriteStmt(Statement):
|
|
61
|
+
target: str
|
|
62
|
+
|
|
63
|
+
@dataclass
|
|
64
|
+
class ReadStmt(Statement):
|
|
65
|
+
expr: 'Expression'
|
|
66
|
+
|
|
67
|
+
@dataclass
|
|
68
|
+
class CtrlFlow(Statement):
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
@dataclass
|
|
72
|
+
class IfCtrl(CtrlFlow):
|
|
73
|
+
if_stmt: 'IfStmt'
|
|
74
|
+
elif_stmt: Optional[List['ElifStmt']]
|
|
75
|
+
else_stmt: Optional['ElseStmt']
|
|
76
|
+
|
|
77
|
+
@dataclass
|
|
78
|
+
class IfStmt(CtrlFlow):
|
|
79
|
+
condition: 'Expression'
|
|
80
|
+
body: Block
|
|
81
|
+
|
|
82
|
+
@dataclass
|
|
83
|
+
class ElifStmt(CtrlFlow):
|
|
84
|
+
condition: 'Expression'
|
|
85
|
+
body: Block
|
|
86
|
+
|
|
87
|
+
@dataclass
|
|
88
|
+
class ElseStmt(CtrlFlow):
|
|
89
|
+
body: Block
|
|
90
|
+
|
|
91
|
+
@dataclass
|
|
92
|
+
class WhileStmt(CtrlFlow):
|
|
93
|
+
condition: 'Expression'
|
|
94
|
+
body: Block
|
|
95
|
+
|
|
96
|
+
@dataclass
|
|
97
|
+
class ForStmt(CtrlFlow):
|
|
98
|
+
expr: 'ForExpr'
|
|
99
|
+
body: Block
|
|
100
|
+
|
|
101
|
+
@dataclass
|
|
102
|
+
class ForExpr(CtrlFlow):
|
|
103
|
+
name: str
|
|
104
|
+
target: List[Any]
|
|
105
|
+
|
|
106
|
+
@dataclass
|
|
107
|
+
class TryCtrl(CtrlFlow):
|
|
108
|
+
try_stmt: 'TryStmt'
|
|
109
|
+
catch_stmt: 'CatchStmt'
|
|
110
|
+
finnaly_stmt: Optional['FinnalyStmt']
|
|
111
|
+
|
|
112
|
+
@dataclass
|
|
113
|
+
class TryStmt(CtrlFlow):
|
|
114
|
+
body: Block
|
|
115
|
+
|
|
116
|
+
@dataclass
|
|
117
|
+
class CatchStmt(CtrlFlow):
|
|
118
|
+
name: str
|
|
119
|
+
body: Block
|
|
120
|
+
|
|
121
|
+
@dataclass
|
|
122
|
+
class FinallyStmt(CtrlFlow):
|
|
123
|
+
body: Block
|
|
124
|
+
|
|
125
|
+
# --- Expressions ---
|
|
126
|
+
class Expression(Node):
|
|
127
|
+
pass
|
|
128
|
+
|
|
129
|
+
@dataclass
|
|
130
|
+
class BinaryOp(Expression):
|
|
131
|
+
op: str # '+', '-', '*', '/', '%', '==', '!=', '>=', '>', '<=', '<', 'dan', 'atau', 'dalam', 'tidak dalam'
|
|
132
|
+
left: Expression
|
|
133
|
+
right: Expression
|
|
134
|
+
|
|
135
|
+
@dataclass
|
|
136
|
+
class UnaryOp(Expression):
|
|
137
|
+
op: str # 'tidak'
|
|
138
|
+
expr: Expression
|
|
139
|
+
|
|
140
|
+
@dataclass
|
|
141
|
+
class Literal(Expression):
|
|
142
|
+
value: Any
|
|
143
|
+
|
|
144
|
+
@dataclass
|
|
145
|
+
class Variable(Expression):
|
|
146
|
+
name: str
|
|
147
|
+
value: Any = None
|
|
148
|
+
|
|
149
|
+
@dataclass
|
|
150
|
+
class GetAttr(Expression):
|
|
151
|
+
obj: Expression
|
|
152
|
+
attr: str
|
|
153
|
+
|
|
154
|
+
@dataclass
|
|
155
|
+
class GetIndex(Expression):
|
|
156
|
+
obj: Expression
|
|
157
|
+
index: Expression
|
|
158
|
+
|
|
159
|
+
@dataclass
|
|
160
|
+
class CallFunc(Expression):
|
|
161
|
+
func: Expression
|
|
162
|
+
params: 'CallParameter'
|
|
163
|
+
|
|
164
|
+
@dataclass
|
|
165
|
+
class CallParameter(Expression):
|
|
166
|
+
args: List['CallArgument']
|
|
167
|
+
|
|
168
|
+
@dataclass
|
|
169
|
+
class CallArgument(Expression):
|
|
170
|
+
name: Optional[str]
|
|
171
|
+
value: Expression
|
|
172
|
+
|
|
173
|
+
@dataclass
|
|
174
|
+
class LambdaFunc(Expression):
|
|
175
|
+
params: 'Parameter'
|
|
176
|
+
expr: Expression
|
|
177
|
+
|
|
178
|
+
@dataclass
|
|
179
|
+
class TypeOf(Expression):
|
|
180
|
+
var: Variable
|
|
181
|
+
|
|
182
|
+
@dataclass
|
|
183
|
+
class IsStmt(Expression): # sebenarnya ini expression boolean
|
|
184
|
+
left: str
|
|
185
|
+
right: str
|
|
186
|
+
negated: bool = False
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# --- Functions ---
|
|
190
|
+
class FunctionNode(Node):
|
|
191
|
+
"Untuk attribute dan kerangka function"
|
|
192
|
+
pass
|
|
193
|
+
|
|
194
|
+
@dataclass
|
|
195
|
+
class Function(FunctionNode):
|
|
196
|
+
type_ann: 'Type'
|
|
197
|
+
name: str
|
|
198
|
+
params: 'Parameter'
|
|
199
|
+
inner: 'Block'
|
|
200
|
+
|
|
201
|
+
@dataclass
|
|
202
|
+
class Parameter(FunctionNode):
|
|
203
|
+
args: List['Argument']
|
|
204
|
+
|
|
205
|
+
@dataclass
|
|
206
|
+
class Generic(FunctionNode):
|
|
207
|
+
args: Optional[List['Argument']]
|
|
208
|
+
|
|
209
|
+
@dataclass
|
|
210
|
+
class Argument(FunctionNode):
|
|
211
|
+
type_ann: 'Type'
|
|
212
|
+
name: str
|
|
213
|
+
value: Optional[Expression] = None
|
|
214
|
+
|
|
215
|
+
@dataclass
|
|
216
|
+
class Return(Expression):
|
|
217
|
+
expr: Expression
|
|
218
|
+
|
|
219
|
+
@dataclass
|
|
220
|
+
class Throw(Expression):
|
|
221
|
+
name: str
|
|
222
|
+
expr: Expression
|
|
223
|
+
|
|
224
|
+
# --- Module ---
|
|
225
|
+
class Module(Node):
|
|
226
|
+
"""Dataclass terkait module"""
|
|
227
|
+
pass
|
|
228
|
+
|
|
229
|
+
@dataclass
|
|
230
|
+
class Export(Module):
|
|
231
|
+
exports: List['ExportArgument']
|
|
232
|
+
|
|
233
|
+
@dataclass
|
|
234
|
+
class ExportArgument(Module):
|
|
235
|
+
name: Variable
|
|
236
|
+
alias: Optional[str]
|
|
237
|
+
|
|
238
|
+
@dataclass
|
|
239
|
+
class Import(Module):
|
|
240
|
+
imports: List['ImportArgument']
|
|
241
|
+
from_path: 'PathID'
|
|
242
|
+
|
|
243
|
+
@dataclass
|
|
244
|
+
class ImportArgument(Module):
|
|
245
|
+
name: str
|
|
246
|
+
alias: Optional[str]
|
|
247
|
+
|
|
248
|
+
@dataclass
|
|
249
|
+
class PathID(Module):
|
|
250
|
+
path: List['PathArg']
|
|
251
|
+
|
|
252
|
+
@dataclass
|
|
253
|
+
class PathArg(Module):
|
|
254
|
+
arg: str
|
|
255
|
+
|
|
256
|
+
# --- Types ---
|
|
257
|
+
class Type(Node):
|
|
258
|
+
pass
|
|
259
|
+
|
|
260
|
+
@dataclass
|
|
261
|
+
class BasicType(Type):
|
|
262
|
+
name: str # 'teks', 'angka', dll.
|
|
263
|
+
|
|
264
|
+
@dataclass
|
|
265
|
+
class ArrayType(Type):
|
|
266
|
+
length: int # 0 untuk dinamis
|
|
267
|
+
element_type: Type
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
2
|
+
|
|
3
|
+
class kekosongan(object):
|
|
4
|
+
def __call__(cls, isi=''):
|
|
5
|
+
return not bool(isi)
|
|
6
|
+
def __repr__(self):
|
|
7
|
+
return '<tipe \'kekosongan\'>'
|
|
8
|
+
|
|
9
|
+
@staticmethod
|
|
10
|
+
def __instancecheck__(instance, /):
|
|
11
|
+
return isinstance(instance, kekosongan)
|
|
12
|
+
|
|
13
|
+
class kosong(kekosongan):
|
|
14
|
+
def __init__(self):
|
|
15
|
+
pass
|
|
16
|
+
def __repr__(self):
|
|
17
|
+
return 'kosong'
|
|
18
|
+
def __str__(self):
|
|
19
|
+
return ''
|
|
20
|
+
def __int__(self):
|
|
21
|
+
return 0
|
|
22
|
+
def __float__(self):
|
|
23
|
+
return 0.0
|
|
24
|
+
def __bool__(self):
|
|
25
|
+
return False
|
|
26
|
+
def __eq__(self, value, /):
|
|
27
|
+
return bool(kosong == value) or bool(None == value)
|
|
28
|
+
def __ne__(self, value, /):
|
|
29
|
+
return not self.__eq__(value)
|
|
30
|
+
|
|
31
|
+
class tipe(type):
|
|
32
|
+
"tipe utama"
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
class teks(tipe, str):
|
|
36
|
+
"string"
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
class desimal(tipe, Decimal):
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
class angka(tipe, int):
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
class kondisi(tipe):
|
|
46
|
+
"boolean"
|
|
47
|
+
__value__ = benar
|
|
48
|
+
def __call__(cls, value=benar):
|
|
49
|
+
if value:
|
|
50
|
+
return benar
|
|
51
|
+
else:
|
|
52
|
+
return salah
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
def __instancecheck__(instance, /):
|
|
56
|
+
return isinstance(kondisi, instance)
|
|
57
|
+
|
|
58
|
+
def __repr__(self):
|
|
59
|
+
return "<tipe 'kondisi'>"
|
|
60
|
+
|
|
61
|
+
class salah:
|
|
62
|
+
def __init__(self):
|
|
63
|
+
pass
|
|
64
|
+
def __repr__(self):
|
|
65
|
+
return 'salah'
|
|
66
|
+
def __str__(self):
|
|
67
|
+
return 'benar'
|
|
68
|
+
def __int__(self):
|
|
69
|
+
return 0
|
|
70
|
+
def __float__(self):
|
|
71
|
+
return 0.0
|
|
72
|
+
def __bool__(self):
|
|
73
|
+
return False
|
|
74
|
+
def __eq__(self, value, /):
|
|
75
|
+
return bool(salah == value) or bool(False == value)
|
|
76
|
+
def __ne__(self, value, /):
|
|
77
|
+
return not self.__eq__(value)
|
|
78
|
+
|
|
79
|
+
class benar:
|
|
80
|
+
def __init__(self):
|
|
81
|
+
pass
|
|
82
|
+
def __repr__(self):
|
|
83
|
+
return 'benar'
|
|
84
|
+
def __str__(self):
|
|
85
|
+
return 'benar'
|
|
86
|
+
def __int__(self):
|
|
87
|
+
return 1
|
|
88
|
+
def __float__(self):
|
|
89
|
+
return 1.0
|
|
90
|
+
def __bool__(self):
|
|
91
|
+
return True
|
|
92
|
+
def __eq__(self, value, /):
|
|
93
|
+
return bool(benar == value) or bool(True == value)
|
|
94
|
+
def __ne__(self, value, /):
|
|
95
|
+
return not self.__eq__(value)
|
|
96
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
class teks(str):
|
|
3
|
+
def __init__(self, chrs='', /):
|
|
4
|
+
self._chrs = str(chrs)
|
|
5
|
+
|
|
6
|
+
def kapitalkan(self, /):
|
|
7
|
+
return self._chrs.capitalize()
|
|
8
|
+
|
|
9
|
+
def simpul(self, /):
|
|
10
|
+
return self._chrs.casefold()
|
|
11
|
+
|
|
12
|
+
def ditengah(self, panjang, pengisi=' ', /):
|
|
13
|
+
return self._chrs.center(panjang, pengisi)
|
|
14
|
+
|
|
15
|
+
def hitung(self, args, /):
|
|
16
|
+
if isinstance(args, str):
|
|
17
|
+
return self._chrs.count(args)
|
|
18
|
+
elif isinstance(args, (list, set, tuple)):
|
|
19
|
+
result = []
|
|
20
|
+
for arg in args:
|
|
21
|
+
if not isinstance(arg, str):
|
|
22
|
+
raise TypeError(f"must be str, not {type(arg).__name__}")
|
|
23
|
+
result.append(self._chrs(arg))
|
|
24
|
+
return result
|
|
25
|
+
else:
|
|
26
|
+
raise TypeError(f"must be str, not {type(arg).__name__}")
|
|
27
|
+
|
|
28
|
+
def diakhiri(self, )
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# builtins.py
|
|
2
|
+
from ..Exceptions.Exceptions import VariabelGalat, FinalGalat, TipeGalat
|
|
3
|
+
from ..AST_node.ast_nodes import BasicType
|
|
4
|
+
from decimal import Decimal
|
|
5
|
+
TYPES = {
|
|
6
|
+
'teks': str,
|
|
7
|
+
'angka': int,
|
|
8
|
+
'desimal': Decimal,
|
|
9
|
+
'boolean': bool,
|
|
10
|
+
'kekosongan': type(None),
|
|
11
|
+
'apapun': object,
|
|
12
|
+
'daftar': list,
|
|
13
|
+
'kamus': dict,
|
|
14
|
+
'fungsi': callable,
|
|
15
|
+
'pointer': str,
|
|
16
|
+
'tipe': type,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
BUILTINS = {
|
|
20
|
+
'benar': True,
|
|
21
|
+
'salah': False,
|
|
22
|
+
'kosong': None,
|
|
23
|
+
'enter': '\n',
|
|
24
|
+
'tab': '\t',
|
|
25
|
+
'format': lambda val, **kwargs: str(val).format(**kwargs),
|
|
26
|
+
'tampilkan': print,
|
|
27
|
+
**TYPES
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
def get_builtin_type(name):
|
|
31
|
+
return TYPES.get(name, object)
|
|
32
|
+
|
|
33
|
+
def builtins_fungsi(self, function_name=None, /, *, type_ann=None, body=None):
|
|
34
|
+
"""
|
|
35
|
+
builtins_fungsi: untuk manipulasi fungsi
|
|
36
|
+
- Jika hanya function_name: return apakah itu fungsi
|
|
37
|
+
- Jika dengan type_ann dan body: buat fungsi baru
|
|
38
|
+
"""
|
|
39
|
+
if function_name is None:
|
|
40
|
+
# Return semua fungsi yang ada
|
|
41
|
+
return {name: info for name, info in self.current_scope.vars.items()
|
|
42
|
+
if info['type'].name == 'fungsi'}
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
obj = self.current_scope.get(function_name)
|
|
46
|
+
is_func = callable(obj['value'])
|
|
47
|
+
|
|
48
|
+
if type_ann is not None and body is not None:
|
|
49
|
+
# Buat fungsi baru
|
|
50
|
+
def new_func(*args, **kwargs):
|
|
51
|
+
result = body(*args, **kwargs)
|
|
52
|
+
if type_ann != 'apapun':
|
|
53
|
+
expected = TYPES.get(type_ann, object)
|
|
54
|
+
if not isinstance(result, expected):
|
|
55
|
+
raise TipeGalat(f"Fungsi harus mengembalikan tipe {type_ann}")
|
|
56
|
+
return result
|
|
57
|
+
|
|
58
|
+
self.current_scope.declare(
|
|
59
|
+
function_name,
|
|
60
|
+
new_func,
|
|
61
|
+
BasicType('fungsi'),
|
|
62
|
+
hex(id(new_func)),
|
|
63
|
+
True
|
|
64
|
+
)
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
return is_func
|
|
68
|
+
|
|
69
|
+
except VariabelGalat:
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
def builtins_vars(self, name=None, /, *, value=None, type_ann=None, constant=False):
|
|
73
|
+
"""
|
|
74
|
+
builtins_vars: untuk manipulasi variabel
|
|
75
|
+
- Tanpa argumen: return semua variabel
|
|
76
|
+
- Dengan name saja: return apakah variabel ada
|
|
77
|
+
- Dengan name dan value: buat/ubah variabel
|
|
78
|
+
"""
|
|
79
|
+
if name is None:
|
|
80
|
+
# Return semua variabel
|
|
81
|
+
return {n: {
|
|
82
|
+
'value': info['value'],
|
|
83
|
+
'type': info['type'].name if isinstance(info['type'], BasicType) else str(info['type']),
|
|
84
|
+
'constant': info['constant']
|
|
85
|
+
} for n, info in self.current_scope.vars.items()}
|
|
86
|
+
|
|
87
|
+
if value is None:
|
|
88
|
+
# Cek apakah variabel ada
|
|
89
|
+
ada = self.current_scope.has(name)
|
|
90
|
+
return ada
|
|
91
|
+
|
|
92
|
+
# Buat atau ubah variabel
|
|
93
|
+
try:
|
|
94
|
+
# Cek apakah sudah ada
|
|
95
|
+
obj = self.current_scope.get(name)
|
|
96
|
+
|
|
97
|
+
# Validasi konstanta
|
|
98
|
+
if obj['constant'] and not constant:
|
|
99
|
+
raise FinalGalat(f"Variabel '{name}' adalah final")
|
|
100
|
+
|
|
101
|
+
# Validasi tipe
|
|
102
|
+
if type_ann:
|
|
103
|
+
expected = TYPES.get(type_ann, object)
|
|
104
|
+
if not isinstance(value, expected):
|
|
105
|
+
raise TipeGalat(f"Nilai tidak sesuai tipe {type_ann}")
|
|
106
|
+
else:
|
|
107
|
+
type_ann = obj['type'].name if isinstance(obj['type'], BasicType) else 'apapun'
|
|
108
|
+
|
|
109
|
+
# Update
|
|
110
|
+
self.current_scope.set(
|
|
111
|
+
name,
|
|
112
|
+
value,
|
|
113
|
+
BasicType(type_ann),
|
|
114
|
+
hex(id(value)),
|
|
115
|
+
constant or obj['constant']
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
except VariabelGalat:
|
|
119
|
+
# Buat baru
|
|
120
|
+
if type_ann is None:
|
|
121
|
+
type_ann = 'apapun'
|
|
122
|
+
else:
|
|
123
|
+
expected = TYPES.get(type_ann, object)
|
|
124
|
+
if not isinstance(value, expected):
|
|
125
|
+
raise TipeGalat(f"Nilai tidak sesuai tipe {type_ann}")
|
|
126
|
+
|
|
127
|
+
self.current_scope.declare(
|
|
128
|
+
name,
|
|
129
|
+
value,
|
|
130
|
+
BasicType(type_ann),
|
|
131
|
+
hex(id(value)),
|
|
132
|
+
constant
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
return True
|
|
136
|
+
|
|
137
|
+
BUILTINS_FUNCTIONS = {
|
|
138
|
+
'Fungsi': builtins_fungsi,
|
|
139
|
+
'Variabel': builtins_vars
|
|
140
|
+
}
|