bahasa-simpl 1.0.12 → 1.0.13
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.
- package/dist/simpl.d.ts +8 -0
- package/dist/{simpl-interpreter.js → simpl.js} +392 -398
- package/dist/simpl.min.js +1 -0
- package/package.json +15 -3
- package/rollup.config.js +0 -8
package/dist/simpl.d.ts
ADDED
|
@@ -84,7 +84,7 @@ class Stipe extends Variable {
|
|
|
84
84
|
super(stipeSymbol, true, data);
|
|
85
85
|
this.symbol = type;
|
|
86
86
|
this.member = new Environment();
|
|
87
|
-
this.member.define("buat", new
|
|
87
|
+
this.member.define("buat", new Variable(mesinSymbol, true, data));
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
}
|
|
@@ -93,9 +93,9 @@ function kePetik(v, thing) {
|
|
|
93
93
|
if (thing.type === logisSymbol) {
|
|
94
94
|
return thing.data ? "benar" : "salah";
|
|
95
95
|
} else if (thing.type === barisSymbol) {
|
|
96
|
-
return '[' + thing.data.reduce((str, val) => str+", "+kePetik(v, val), "").slice(1) + ' ]';
|
|
96
|
+
return '[' + thing.data.reduce((str, val) => str + ", " + kePetik(v, val), "").slice(1) + ' ]';
|
|
97
97
|
} else if (thing.type === stipeSymbol) {
|
|
98
|
-
return `Model<${thing.symbol.description}>`;
|
|
98
|
+
return `Model<${thing.symbol?.description ? thing.symbol.description : ""}>`;
|
|
99
99
|
} else if (thing.type === mesinSymbol) {
|
|
100
100
|
let underlying = thing.data.returnType?.description;
|
|
101
101
|
return `Mesin<${underlying ? underlying : 'datum'}>`;
|
|
@@ -113,304 +113,6 @@ function kePetik(v, thing) {
|
|
|
113
113
|
return `${thing.type.description}<>`;
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
-
|
|
117
|
-
class PetikTipe extends Stipe {
|
|
118
|
-
constructor() {
|
|
119
|
-
super(petikSymbol, new Callable(null, (v, args) => new Value(petikSymbol, kePetik(v, args[0])),
|
|
120
|
-
[[null]], petikSymbol, true));
|
|
121
|
-
this.init();
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
init() {
|
|
125
|
-
// BINARY / UNARY OPERATORS
|
|
126
|
-
this.member.define("PLUS",
|
|
127
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], petikSymbol, (_, [r, l]) => new Value(petikSymbol, l.data + r.data)));
|
|
128
|
-
this.member.define("LEBIH",
|
|
129
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data > r.data)));
|
|
130
|
-
this.member.define("KURANG",
|
|
131
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data < r.data)));
|
|
132
|
-
this.member.define("SAMA_SAMA",
|
|
133
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data === r.data)));
|
|
134
|
-
this.member.define("LEBIH_SAMA",
|
|
135
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data >= r.data)));
|
|
136
|
-
this.member.define("KURANG_SAMA",
|
|
137
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data <= r.data)));
|
|
138
|
-
this.member.define("SERU_SAMA",
|
|
139
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data !== r.data)));
|
|
140
|
-
this.member.define("AMPERSAN",
|
|
141
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data && r.data)));
|
|
142
|
-
this.member.define("PIPA",
|
|
143
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data || r.data)));
|
|
144
|
-
|
|
145
|
-
this.member.define("SERU_UNER",
|
|
146
|
-
makeBuiltInFunc([petikSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
147
|
-
|
|
148
|
-
this.member.define("kePetik",
|
|
149
|
-
makeBuiltInFunc([petikSymbol], petikSymbol, (v, [p]) => new Value(petikSymbol, kePetik(v, p))));
|
|
150
|
-
|
|
151
|
-
this.member.define("pisah", makeBuiltInFunc([petikSymbol, petikSymbol], barisSymbol, (_, [d, sep]) => {
|
|
152
|
-
return new Value(barisSymbol, d.data.split(sep.data).map(val => new Value(petikSymbol, val)));
|
|
153
|
-
}));
|
|
154
|
-
this.member.define("bersih", makeBuiltInFunc([petikSymbol], petikSymbol, (_, [d]) => {
|
|
155
|
-
return new Value(petikSymbol, d.data.trim())
|
|
156
|
-
}));
|
|
157
|
-
this.member.define("ganti", makeBuiltInFunc([petikSymbol, petikSymbol, petikSymbol], petikSymbol,
|
|
158
|
-
(_, [d, what, rep]) => new Value(petikSymbol, d.data.replaceAll(what.data, rep.data))
|
|
159
|
-
));
|
|
160
|
-
this.member.define("besar", makeBuiltInFunc([petikSymbol], petikSymbol, (_, [p]) => {
|
|
161
|
-
return new Value(petikSymbol, p.data.toUpperCase())
|
|
162
|
-
}));
|
|
163
|
-
this.member.define("kecil", makeBuiltInFunc([petikSymbol], petikSymbol, (_, [p]) => {
|
|
164
|
-
return new Value(petikSymbol, p.data.toLowerCase())
|
|
165
|
-
}));
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
class AngkaTipe extends Stipe {
|
|
170
|
-
constructor() {
|
|
171
|
-
super(angkaSymbol, new Callable(null, (v, args) => {
|
|
172
|
-
if (typeof args[0].data === "number") {
|
|
173
|
-
return new Value(angkaSymbol, args[0].data);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
switch (args[0].type) {
|
|
177
|
-
case petikSymbol:
|
|
178
|
-
if (isNaN(Number(args[0].data))) {
|
|
179
|
-
v.error("Nilai dari petik bukanlah sebuah angka, konversi gagal.");
|
|
180
|
-
}
|
|
181
|
-
return new Value(angkaSymbol, Number(args[0].data));
|
|
182
|
-
case angkaSymbol:
|
|
183
|
-
return new Value(angkaSymbol, args[0].data);
|
|
184
|
-
case logisSymbol:
|
|
185
|
-
return new Value(angkaSymbol, Number(args[0].data));
|
|
186
|
-
default:
|
|
187
|
-
v.error(`Tipe yang dapat diterima hanyalah petik, angka, logis, dan jenis. Mendapatkan ${args[0].type.description}.`);
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
}, [[null]], angkaSymbol, true)
|
|
191
|
-
);
|
|
192
|
-
this.init();
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
init() {
|
|
196
|
-
this.member.define("PLUS",
|
|
197
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data + r.data)));
|
|
198
|
-
this.member.define("MINUS",
|
|
199
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data - r.data)));
|
|
200
|
-
this.member.define("BINTANG",
|
|
201
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data * r.data)));
|
|
202
|
-
this.member.define("GARIS_MIRING",
|
|
203
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data / r.data)));
|
|
204
|
-
this.member.define("MODULUS",
|
|
205
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data % r.data)));
|
|
206
|
-
|
|
207
|
-
this.member.define("LEBIH",
|
|
208
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data > r.data)));
|
|
209
|
-
this.member.define("KURANG",
|
|
210
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data < r.data)));
|
|
211
|
-
this.member.define("SAMA_SAMA",
|
|
212
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data === r.data)));
|
|
213
|
-
this.member.define("LEBIH_SAMA",
|
|
214
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data >= r.data)));
|
|
215
|
-
this.member.define("KURANG_SAMA",
|
|
216
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data <= r.data)));
|
|
217
|
-
this.member.define("SERU_SAMA",
|
|
218
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data !== r.data)));
|
|
219
|
-
this.member.define("AMPERSAN",
|
|
220
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data && r.data)));
|
|
221
|
-
this.member.define("PIPA",
|
|
222
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data || r.data)));
|
|
223
|
-
this.member.define("SERU_UNER",
|
|
224
|
-
makeBuiltInFunc([angkaSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
225
|
-
this.member.define("PLUS_UNER",
|
|
226
|
-
makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [r]) => new Value(angkaSymbol, +r.data)));
|
|
227
|
-
this.member.define("MINUS_UNER",
|
|
228
|
-
makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [r]) => new Value(angkaSymbol, -r.data)));
|
|
229
|
-
|
|
230
|
-
this.member.define("kePetik",
|
|
231
|
-
makeBuiltInFunc([angkaSymbol], petikSymbol, (v, [a]) => new Value(petikSymbol, kePetik(v, a))));
|
|
232
|
-
|
|
233
|
-
this.member.define("bulat", makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [a]) => {
|
|
234
|
-
return new Value(angkaSymbol, Math.round(a.data));
|
|
235
|
-
}));
|
|
236
|
-
this.member.define("bulatAtas", makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [a]) => {
|
|
237
|
-
return new Value(angkaSymbol, Math.ceil(a.data))
|
|
238
|
-
}));
|
|
239
|
-
this.member.define("bulatBawah", makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [a]) => {
|
|
240
|
-
return new Value(angkaSymbol, Math.floor(a.data))
|
|
241
|
-
}));
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
class LogisTipe extends Stipe {
|
|
246
|
-
constructor() {
|
|
247
|
-
super(logisSymbol, new Callable(null, (_, args) => {
|
|
248
|
-
if (args[0].type === barisSymbol && args[0].data.length === 0) {
|
|
249
|
-
return new Value(logisSymbol, false);
|
|
250
|
-
}
|
|
251
|
-
return new Value(logisSymbol, Boolean(args[0].data) || Boolean(args[0].data?.member?.size));
|
|
252
|
-
}, [[null]], logisSymbol, true)
|
|
253
|
-
);
|
|
254
|
-
this.init();
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
init() {
|
|
258
|
-
this.member.define("SAMA_SAMA",
|
|
259
|
-
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data === r.data)));
|
|
260
|
-
this.member.define("SERU_SAMA",
|
|
261
|
-
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data !== r.data)));
|
|
262
|
-
this.member.define("AMPERSAN",
|
|
263
|
-
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data && r.data)));
|
|
264
|
-
this.member.define("PIPA",
|
|
265
|
-
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data || r.data)));
|
|
266
|
-
this.member.define("SERU_UNER",
|
|
267
|
-
makeBuiltInFunc([logisSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
268
|
-
|
|
269
|
-
this.member.define("kePetik",
|
|
270
|
-
makeBuiltInFunc([logisSymbol], petikSymbol, (v, [l]) => new Value(petikSymbol, kePetik(v, l))));
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
class BarisTipe extends Stipe {
|
|
275
|
-
constructor() {
|
|
276
|
-
super(barisSymbol);
|
|
277
|
-
this.init();
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
init() {
|
|
281
|
-
const valueToVariableDatum = (d) => {
|
|
282
|
-
let input = new Variable(d.type, false, d.data);
|
|
283
|
-
input.member = d.member;
|
|
284
|
-
input.isDatum = true;
|
|
285
|
-
return input;
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
this.member.define("PLUS",
|
|
289
|
-
makeBuiltInFunc([barisSymbol, barisSymbol], barisSymbol, (_, [r, l]) =>
|
|
290
|
-
new Value(barisSymbol, Array(...l.data, ...r.data))
|
|
291
|
-
));
|
|
292
|
-
|
|
293
|
-
this.member.define("MINUS_UNER",
|
|
294
|
-
makeBuiltInFunc([barisSymbol], barisSymbol, (_, [r]) =>
|
|
295
|
-
new Value(barisSymbol, r.data.slice(0, r.length))
|
|
296
|
-
));
|
|
297
|
-
|
|
298
|
-
this.member.define("SAMA_SAMA",
|
|
299
|
-
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, ((a, b) => {
|
|
300
|
-
if (a.length !== b.length) return false;
|
|
301
|
-
for (let i = 0; i < a.length; i++) {
|
|
302
|
-
if (a[i].data !== b[i].data) return false;
|
|
303
|
-
}
|
|
304
|
-
return true;
|
|
305
|
-
})(l.data, r.data)))
|
|
306
|
-
);
|
|
307
|
-
|
|
308
|
-
this.member.define("SERU_SAMA",
|
|
309
|
-
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, ((a, b) => {
|
|
310
|
-
if (a.length !== b.length) return true;
|
|
311
|
-
for (let i = 0; i < a.length; i++) {
|
|
312
|
-
if (a[i].data !== b[i].data) return true;
|
|
313
|
-
}
|
|
314
|
-
return false;
|
|
315
|
-
})(l.data, r.data)))
|
|
316
|
-
);
|
|
317
|
-
|
|
318
|
-
this.member.define("AMPERSAN",
|
|
319
|
-
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data && r.data)));
|
|
320
|
-
this.member.define("PIPA",
|
|
321
|
-
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data || r.data)));
|
|
322
|
-
this.member.define("SERU_UNER",
|
|
323
|
-
makeBuiltInFunc([barisSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
324
|
-
|
|
325
|
-
this.member.define("kePetik",
|
|
326
|
-
makeBuiltInFunc([barisSymbol], petikSymbol, (v, [p]) => new Value(petikSymbol, kePetik(v, p))));
|
|
327
|
-
|
|
328
|
-
this.member.define("hapus", makeBuiltInFunc([barisSymbol, angkaSymbol], barisSymbol, (v, [b, i]) => {
|
|
329
|
-
if (b.data.length <= i.data) {
|
|
330
|
-
v.error(`Indeks tidak boleh lebih besar atau sama dengan ukuran baris, ${i.data} >= ${b.data.length}`);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
while (i.data < 0) i.data += b.data.length;
|
|
334
|
-
b.data = b.data.filter((_, idx) => idx !== i.data);
|
|
335
|
-
return b;
|
|
336
|
-
}));
|
|
337
|
-
|
|
338
|
-
this.member.define("potongan", makeBuiltInFunc([barisSymbol, angkaSymbol, angkaSymbol], barisSymbol, (v, [b, fr, to]) => {
|
|
339
|
-
if (fr.data >= b.data.length || fr.data < 0 || to.data <= fr.data || to.data > b.data.length) {
|
|
340
|
-
v.error(`Indeks tidak valid, ${fr.data} sampai ${to.data}, dengan ukuran baris ${b.data.length}`);
|
|
341
|
-
}
|
|
342
|
-
return new Value(barisSymbol, b.data.slice(fr.data, to.data));
|
|
343
|
-
}));
|
|
344
|
-
this.member.define("tumpuk", makeBuiltInFunc([barisSymbol, null], null, (_, [b, d]) => {
|
|
345
|
-
b.data.push(valueToVariableDatum(d));
|
|
346
|
-
return b;
|
|
347
|
-
}));
|
|
348
|
-
this.member.define("tumpah", makeBuiltInFunc([barisSymbol], null, (_, [b]) => {
|
|
349
|
-
b.data.pop();
|
|
350
|
-
return b;
|
|
351
|
-
}));
|
|
352
|
-
this.member.define("masuk", makeBuiltInFunc([barisSymbol, null, angkaSymbol], null, (v, [b, d, idx]) => {
|
|
353
|
-
if (idx.data > b.data.length) {
|
|
354
|
-
v.error(`Indeks tidak valid, ${idx.data}, dengan ukuran baris ${b.data.length}`);
|
|
355
|
-
}
|
|
356
|
-
b.data.splice(idx.data, 0, valueToVariableDatum(d));
|
|
357
|
-
return b;
|
|
358
|
-
}));
|
|
359
|
-
this.member.define("petakan", makeBuiltInFunc([barisSymbol, mesinSymbol], barisSymbol, (v, [b, m]) => {
|
|
360
|
-
let newBaris = new Value(barisSymbol, []);
|
|
361
|
-
for (let datum of b.data) {
|
|
362
|
-
let result = v.callFunc(m.data, [datum]);
|
|
363
|
-
newBaris.data.push(valueToVariableDatum(result));
|
|
364
|
-
}
|
|
365
|
-
return newBaris;
|
|
366
|
-
}));
|
|
367
|
-
this.member.define("saring", makeBuiltInFunc([barisSymbol, mesinSymbol], barisSymbol, (v, [b, m]) => {
|
|
368
|
-
let newBaris = new Value(barisSymbol, []);
|
|
369
|
-
for (let datum of b.data) {
|
|
370
|
-
let result = v.callFunc(m.data, [datum]);
|
|
371
|
-
if (result.data === true) {
|
|
372
|
-
newBaris.data.push(valueToVariableDatum(datum));
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
return newBaris;
|
|
376
|
-
}));
|
|
377
|
-
this.member.define("reduksi", makeBuiltInFunc([barisSymbol, mesinSymbol, null], null, (v, [b, m, d]) => {
|
|
378
|
-
for (let datum of b.data) {
|
|
379
|
-
let result = v.callFunc(m.data, [d, datum]);
|
|
380
|
-
d = result;
|
|
381
|
-
}
|
|
382
|
-
return d;
|
|
383
|
-
}));
|
|
384
|
-
|
|
385
|
-
this.member.define("punya?", makeBuiltInFunc([barisSymbol, null], logisSymbol, (v, [b, d]) => {
|
|
386
|
-
let type = v.environment.get(d.type?.description);
|
|
387
|
-
if (!type)
|
|
388
|
-
v.error(`Tipe tidak ditemukan atau tidak valid`);
|
|
389
|
-
let equalFunc;
|
|
390
|
-
if (type.member?.has("SAMA_SAMA")) {
|
|
391
|
-
equalFunc = type.member.get("SAMA_SAMA");
|
|
392
|
-
} else {
|
|
393
|
-
v.error(`model ${d.type.description} tidak mempunyai mesin SAMA_SAMA di dalam modulnya.`);
|
|
394
|
-
}
|
|
395
|
-
for (let datum of b.data) {
|
|
396
|
-
if (datum.type !== d.type) continue;
|
|
397
|
-
let isEqual = v.callFunc(equalFunc.data, [datum, d]);
|
|
398
|
-
if (isEqual.data) return new Value(logisSymbol, true);
|
|
399
|
-
}
|
|
400
|
-
return new Value(logisSymbol, false);
|
|
401
|
-
}));
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
class MesinTipe extends Stipe {
|
|
406
|
-
constructor() {
|
|
407
|
-
super(mesinSymbol);
|
|
408
|
-
|
|
409
|
-
this.member.define("kePetik",
|
|
410
|
-
makeBuiltInFunc([mesinSymbol], petikSymbol, (v, [m]) => new Value(petikSymbol, kePetik(v, m))));
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
116
|
let Model$1 = class Model extends Stipe {
|
|
415
117
|
constructor(name, params) {
|
|
416
118
|
let sym = Symbol(name);
|
|
@@ -454,10 +156,7 @@ let Jenis$1 = class Jenis extends Stipe {
|
|
|
454
156
|
this.member.define("kePetik", makeBuiltInFunc([sym], petikSymbol, (_, [j]) => {
|
|
455
157
|
return new Value(petikSymbol, `${name}<${j.data}>`);
|
|
456
158
|
}));
|
|
457
|
-
this.init(sym);
|
|
458
|
-
}
|
|
459
159
|
|
|
460
|
-
init(sym) {
|
|
461
160
|
this.member.define("SAMA_SAMA",
|
|
462
161
|
makeBuiltInFunc([sym, sym], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data === r.data)));
|
|
463
162
|
this.member.define("SERU_SAMA",
|
|
@@ -516,13 +215,302 @@ function copier(thing) {
|
|
|
516
215
|
}
|
|
517
216
|
|
|
518
217
|
|
|
218
|
+
const PetikTipe = (() => {
|
|
219
|
+
let tipe = new Stipe(petikSymbol, new Callable(null, (v, args) => new Value(petikSymbol, kePetik(v, args[0])),
|
|
220
|
+
[[null]], petikSymbol, true));
|
|
221
|
+
|
|
222
|
+
tipe.member.define("PLUS",
|
|
223
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], petikSymbol, (_, [r, l]) => new Value(petikSymbol, l.data + r.data)));
|
|
224
|
+
tipe.member.define("LEBIH",
|
|
225
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data > r.data)));
|
|
226
|
+
tipe.member.define("KURANG",
|
|
227
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data < r.data)));
|
|
228
|
+
tipe.member.define("SAMA_SAMA",
|
|
229
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data === r.data)));
|
|
230
|
+
tipe.member.define("LEBIH_SAMA",
|
|
231
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data >= r.data)));
|
|
232
|
+
tipe.member.define("KURANG_SAMA",
|
|
233
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data <= r.data)));
|
|
234
|
+
tipe.member.define("SERU_SAMA",
|
|
235
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data !== r.data)));
|
|
236
|
+
tipe.member.define("AMPERSAN",
|
|
237
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data && r.data)));
|
|
238
|
+
tipe.member.define("PIPA",
|
|
239
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data || r.data)));
|
|
240
|
+
|
|
241
|
+
tipe.member.define("SERU_UNER",
|
|
242
|
+
makeBuiltInFunc([petikSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
243
|
+
|
|
244
|
+
tipe.member.define("kePetik",
|
|
245
|
+
makeBuiltInFunc([petikSymbol], petikSymbol, (v, [p]) => new Value(petikSymbol, kePetik(v, p))));
|
|
246
|
+
|
|
247
|
+
tipe.member.define("pisah", makeBuiltInFunc([petikSymbol, petikSymbol], barisSymbol, (_, [d, sep]) => {
|
|
248
|
+
return new Value(barisSymbol, d.data.split(sep.data).map(val => new Value(petikSymbol, val)));
|
|
249
|
+
}));
|
|
250
|
+
tipe.member.define("bersih", makeBuiltInFunc([petikSymbol], petikSymbol, (_, [d]) => {
|
|
251
|
+
return new Value(petikSymbol, d.data.trim())
|
|
252
|
+
}));
|
|
253
|
+
tipe.member.define("ganti", makeBuiltInFunc([petikSymbol, petikSymbol, petikSymbol], petikSymbol,
|
|
254
|
+
(_, [d, what, rep]) => new Value(petikSymbol, d.data.replaceAll(what.data, rep.data))
|
|
255
|
+
));
|
|
256
|
+
tipe.member.define("besar", makeBuiltInFunc([petikSymbol], petikSymbol, (_, [p]) => {
|
|
257
|
+
return new Value(petikSymbol, p.data.toUpperCase())
|
|
258
|
+
}));
|
|
259
|
+
tipe.member.define("kecil", makeBuiltInFunc([petikSymbol], petikSymbol, (_, [p]) => {
|
|
260
|
+
return new Value(petikSymbol, p.data.toLowerCase())
|
|
261
|
+
}));
|
|
262
|
+
|
|
263
|
+
return tipe;
|
|
264
|
+
})();
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
const AngkaTipe = (() => {
|
|
268
|
+
let tipe = new Stipe(angkaSymbol, new Callable(null, (v, args) => {
|
|
269
|
+
if (typeof args[0].data === "number") {
|
|
270
|
+
return new Value(angkaSymbol, args[0].data);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
switch (args[0].type) {
|
|
274
|
+
case petikSymbol:
|
|
275
|
+
if (isNaN(Number(args[0].data))) {
|
|
276
|
+
v.error("Nilai dari petik bukanlah sebuah angka, konversi gagal.");
|
|
277
|
+
}
|
|
278
|
+
return new Value(angkaSymbol, Number(args[0].data));
|
|
279
|
+
case angkaSymbol:
|
|
280
|
+
return new Value(angkaSymbol, args[0].data);
|
|
281
|
+
case logisSymbol:
|
|
282
|
+
return new Value(angkaSymbol, Number(args[0].data));
|
|
283
|
+
default:
|
|
284
|
+
v.error(`Tipe yang dapat diterima hanyalah petik, angka, logis, dan jenis. Mendapatkan ${args[0].type.description}.`);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
}, [[null]], angkaSymbol, true)
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
tipe.member.define("PLUS",
|
|
291
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data + r.data)));
|
|
292
|
+
tipe.member.define("MINUS",
|
|
293
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data - r.data)));
|
|
294
|
+
tipe.member.define("BINTANG",
|
|
295
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data * r.data)));
|
|
296
|
+
tipe.member.define("GARIS_MIRING",
|
|
297
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data / r.data)));
|
|
298
|
+
tipe.member.define("MODULUS",
|
|
299
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data % r.data)));
|
|
300
|
+
|
|
301
|
+
tipe.member.define("LEBIH",
|
|
302
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data > r.data)));
|
|
303
|
+
tipe.member.define("KURANG",
|
|
304
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data < r.data)));
|
|
305
|
+
tipe.member.define("SAMA_SAMA",
|
|
306
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data === r.data)));
|
|
307
|
+
tipe.member.define("LEBIH_SAMA",
|
|
308
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data >= r.data)));
|
|
309
|
+
tipe.member.define("KURANG_SAMA",
|
|
310
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data <= r.data)));
|
|
311
|
+
tipe.member.define("SERU_SAMA",
|
|
312
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data !== r.data)));
|
|
313
|
+
tipe.member.define("AMPERSAN",
|
|
314
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data && r.data)));
|
|
315
|
+
tipe.member.define("PIPA",
|
|
316
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data || r.data)));
|
|
317
|
+
tipe.member.define("SERU_UNER",
|
|
318
|
+
makeBuiltInFunc([angkaSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
319
|
+
tipe.member.define("PLUS_UNER",
|
|
320
|
+
makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [r]) => new Value(angkaSymbol, +r.data)));
|
|
321
|
+
tipe.member.define("MINUS_UNER",
|
|
322
|
+
makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [r]) => new Value(angkaSymbol, -r.data)));
|
|
323
|
+
|
|
324
|
+
tipe.member.define("kePetik",
|
|
325
|
+
makeBuiltInFunc([angkaSymbol], petikSymbol, (v, [a]) => new Value(petikSymbol, kePetik(v, a))));
|
|
326
|
+
|
|
327
|
+
tipe.member.define("bulat", makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [a]) => {
|
|
328
|
+
return new Value(angkaSymbol, Math.round(a.data));
|
|
329
|
+
}));
|
|
330
|
+
tipe.member.define("bulatAtas", makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [a]) => {
|
|
331
|
+
return new Value(angkaSymbol, Math.ceil(a.data))
|
|
332
|
+
}));
|
|
333
|
+
tipe.member.define("bulatBawah", makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [a]) => {
|
|
334
|
+
return new Value(angkaSymbol, Math.floor(a.data))
|
|
335
|
+
}));
|
|
336
|
+
|
|
337
|
+
return tipe;
|
|
338
|
+
})();
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
const LogisTipe = (() => {
|
|
342
|
+
let tipe = new Stipe(logisSymbol, new Callable(null, (_, args) => {
|
|
343
|
+
if (args[0].type === barisSymbol && args[0].data.length === 0) {
|
|
344
|
+
return new Value(logisSymbol, false);
|
|
345
|
+
}
|
|
346
|
+
return new Value(logisSymbol, Boolean(args[0].data) || Boolean(args[0].data?.member?.size));
|
|
347
|
+
}, [[null]], logisSymbol, true)
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
tipe.member.define("SAMA_SAMA",
|
|
351
|
+
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data === r.data)));
|
|
352
|
+
tipe.member.define("SERU_SAMA",
|
|
353
|
+
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data !== r.data)));
|
|
354
|
+
tipe.member.define("AMPERSAN",
|
|
355
|
+
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data && r.data)));
|
|
356
|
+
tipe.member.define("PIPA",
|
|
357
|
+
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data || r.data)));
|
|
358
|
+
tipe.member.define("SERU_UNER",
|
|
359
|
+
makeBuiltInFunc([logisSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
360
|
+
|
|
361
|
+
tipe.member.define("kePetik",
|
|
362
|
+
makeBuiltInFunc([logisSymbol], petikSymbol, (v, [l]) => new Value(petikSymbol, kePetik(v, l))));
|
|
363
|
+
|
|
364
|
+
return tipe;
|
|
365
|
+
})();
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
const BarisTipe = (() => {
|
|
369
|
+
let tipe = new Stipe(barisSymbol);
|
|
370
|
+
|
|
371
|
+
const valueToVariableDatum = (d) => {
|
|
372
|
+
let input = new Variable(d.type, false, d.data);
|
|
373
|
+
input.member = d.member;
|
|
374
|
+
input.isDatum = true;
|
|
375
|
+
return input;
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
tipe.member.define("PLUS",
|
|
379
|
+
makeBuiltInFunc([barisSymbol, barisSymbol], barisSymbol, (_, [r, l]) =>
|
|
380
|
+
new Value(barisSymbol, Array(...l.data, ...r.data))
|
|
381
|
+
));
|
|
382
|
+
|
|
383
|
+
tipe.member.define("MINUS_UNER",
|
|
384
|
+
makeBuiltInFunc([barisSymbol], barisSymbol, (_, [r]) =>
|
|
385
|
+
new Value(barisSymbol, r.data.slice(0, r.length))
|
|
386
|
+
));
|
|
387
|
+
|
|
388
|
+
tipe.member.define("SAMA_SAMA",
|
|
389
|
+
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, ((a, b) => {
|
|
390
|
+
if (a.length !== b.length) return false;
|
|
391
|
+
for (let i = 0; i < a.length; i++) {
|
|
392
|
+
if (a[i].data !== b[i].data) return false;
|
|
393
|
+
}
|
|
394
|
+
return true;
|
|
395
|
+
})(l.data, r.data)))
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
tipe.member.define("SERU_SAMA",
|
|
399
|
+
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, ((a, b) => {
|
|
400
|
+
if (a.length !== b.length) return true;
|
|
401
|
+
for (let i = 0; i < a.length; i++) {
|
|
402
|
+
if (a[i].data !== b[i].data) return true;
|
|
403
|
+
}
|
|
404
|
+
return false;
|
|
405
|
+
})(l.data, r.data)))
|
|
406
|
+
);
|
|
407
|
+
|
|
408
|
+
tipe.member.define("AMPERSAN",
|
|
409
|
+
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data && r.data)));
|
|
410
|
+
tipe.member.define("PIPA",
|
|
411
|
+
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data || r.data)));
|
|
412
|
+
tipe.member.define("SERU_UNER",
|
|
413
|
+
makeBuiltInFunc([barisSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
414
|
+
|
|
415
|
+
tipe.member.define("kePetik",
|
|
416
|
+
makeBuiltInFunc([barisSymbol], petikSymbol, (v, [p]) => new Value(petikSymbol, kePetik(v, p))));
|
|
417
|
+
|
|
418
|
+
tipe.member.define("hapus", makeBuiltInFunc([barisSymbol, angkaSymbol], barisSymbol, (v, [b, i]) => {
|
|
419
|
+
if (b.data.length <= i.data) {
|
|
420
|
+
v.error(`Indeks tidak boleh lebih besar atau sama dengan ukuran baris, ${i.data} >= ${b.data.length}`);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
while (i.data < 0) i.data += b.data.length;
|
|
424
|
+
b.data = b.data.filter((_, idx) => idx !== i.data);
|
|
425
|
+
return b;
|
|
426
|
+
}));
|
|
427
|
+
|
|
428
|
+
tipe.member.define("potongan", makeBuiltInFunc([barisSymbol, angkaSymbol, angkaSymbol], barisSymbol, (v, [b, fr, to]) => {
|
|
429
|
+
if (fr.data >= b.data.length || fr.data < 0 || to.data <= fr.data || to.data > b.data.length) {
|
|
430
|
+
v.error(`Indeks tidak valid, ${fr.data} sampai ${to.data}, dengan ukuran baris ${b.data.length}`);
|
|
431
|
+
}
|
|
432
|
+
return new Value(barisSymbol, b.data.slice(fr.data, to.data));
|
|
433
|
+
}));
|
|
434
|
+
tipe.member.define("tumpuk", makeBuiltInFunc([barisSymbol, null], null, (_, [b, d]) => {
|
|
435
|
+
b.data.push(valueToVariableDatum(d));
|
|
436
|
+
return b;
|
|
437
|
+
}));
|
|
438
|
+
tipe.member.define("tumpah", makeBuiltInFunc([barisSymbol], null, (_, [b]) => {
|
|
439
|
+
b.data.pop();
|
|
440
|
+
return b;
|
|
441
|
+
}));
|
|
442
|
+
tipe.member.define("masuk", makeBuiltInFunc([barisSymbol, null, angkaSymbol], null, (v, [b, d, idx]) => {
|
|
443
|
+
if (idx.data > b.data.length) {
|
|
444
|
+
v.error(`Indeks tidak valid, ${idx.data}, dengan ukuran baris ${b.data.length}`);
|
|
445
|
+
}
|
|
446
|
+
b.data.splice(idx.data, 0, valueToVariableDatum(d));
|
|
447
|
+
return b;
|
|
448
|
+
}));
|
|
449
|
+
tipe.member.define("petakan", makeBuiltInFunc([barisSymbol, mesinSymbol], barisSymbol, (v, [b, m]) => {
|
|
450
|
+
let newBaris = new Value(barisSymbol, []);
|
|
451
|
+
for (let datum of b.data) {
|
|
452
|
+
let result = v.callFunc(m.data, [datum]);
|
|
453
|
+
newBaris.data.push(valueToVariableDatum(result));
|
|
454
|
+
}
|
|
455
|
+
return newBaris;
|
|
456
|
+
}));
|
|
457
|
+
tipe.member.define("saring", makeBuiltInFunc([barisSymbol, mesinSymbol], barisSymbol, (v, [b, m]) => {
|
|
458
|
+
let newBaris = new Value(barisSymbol, []);
|
|
459
|
+
for (let datum of b.data) {
|
|
460
|
+
let result = v.callFunc(m.data, [datum]);
|
|
461
|
+
if (result.data === true) {
|
|
462
|
+
newBaris.data.push(valueToVariableDatum(datum));
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return newBaris;
|
|
466
|
+
}));
|
|
467
|
+
tipe.member.define("reduksi", makeBuiltInFunc([barisSymbol, mesinSymbol, null], null, (v, [b, m, d]) => {
|
|
468
|
+
for (let datum of b.data) {
|
|
469
|
+
let result = v.callFunc(m.data, [d, datum]);
|
|
470
|
+
d = result;
|
|
471
|
+
}
|
|
472
|
+
return d;
|
|
473
|
+
}));
|
|
474
|
+
|
|
475
|
+
tipe.member.define("punya?", makeBuiltInFunc([barisSymbol, null], logisSymbol, (v, [b, d]) => {
|
|
476
|
+
let type = v.environment.get(d.type?.description);
|
|
477
|
+
if (!type)
|
|
478
|
+
v.error(`Tipe tidak ditemukan atau tidak valid`);
|
|
479
|
+
let equalFunc;
|
|
480
|
+
if (type.member?.has("SAMA_SAMA")) {
|
|
481
|
+
equalFunc = type.member.get("SAMA_SAMA");
|
|
482
|
+
} else {
|
|
483
|
+
v.error(`model ${d.type.description} tidak mempunyai mesin SAMA_SAMA di dalam modulnya.`);
|
|
484
|
+
}
|
|
485
|
+
for (let datum of b.data) {
|
|
486
|
+
if (datum.type !== d.type) continue;
|
|
487
|
+
let isEqual = v.callFunc(equalFunc.data, [datum, d]);
|
|
488
|
+
if (isEqual.data) return new Value(logisSymbol, true);
|
|
489
|
+
}
|
|
490
|
+
return new Value(logisSymbol, false);
|
|
491
|
+
}));
|
|
492
|
+
|
|
493
|
+
return tipe;
|
|
494
|
+
})();
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
const MesinTipe = (() => {
|
|
498
|
+
let tipe = new Stipe(mesinSymbol);
|
|
499
|
+
|
|
500
|
+
tipe.member.define("kePetik",
|
|
501
|
+
makeBuiltInFunc([mesinSymbol], petikSymbol, (v, [m]) => new Value(petikSymbol, kePetik(v, m))));
|
|
502
|
+
|
|
503
|
+
return tipe;
|
|
504
|
+
})();
|
|
505
|
+
|
|
506
|
+
|
|
519
507
|
const GLOBAL_ENV = (() => {
|
|
520
508
|
let env = new Environment();
|
|
521
|
-
env.define("petik",
|
|
522
|
-
env.define("angka",
|
|
523
|
-
env.define("logis",
|
|
524
|
-
env.define("baris",
|
|
525
|
-
env.define("mesin",
|
|
509
|
+
env.define("petik", PetikTipe);
|
|
510
|
+
env.define("angka", AngkaTipe);
|
|
511
|
+
env.define("logis", LogisTipe);
|
|
512
|
+
env.define("baris", BarisTipe);
|
|
513
|
+
env.define("mesin", MesinTipe);
|
|
526
514
|
|
|
527
515
|
env.define("jarak", makeBuiltInFunc([angkaSymbol, angkaSymbol], barisSymbol,
|
|
528
516
|
(_, [from, to]) => new Value(barisSymbol,
|
|
@@ -717,23 +705,26 @@ let Hasil$1 = class Hasil {
|
|
|
717
705
|
}
|
|
718
706
|
};
|
|
719
707
|
|
|
720
|
-
const location = {
|
|
721
|
-
GLOBAL: 1,
|
|
722
|
-
SLAGI: 2,
|
|
723
|
-
UNTUK: 3,
|
|
724
|
-
MESIN: 4,
|
|
725
|
-
LIHAT: 5,
|
|
726
|
-
};
|
|
727
|
-
const MAX_STACK_SIZE = 500;
|
|
728
|
-
|
|
729
708
|
// Implements all Expressions and Statements Visitor
|
|
730
709
|
class Interpreter {
|
|
731
710
|
constructor() {
|
|
732
711
|
this.globalEnvironment = GLOBAL_ENV;
|
|
712
|
+
this.location = {
|
|
713
|
+
GLOBAL: 1,
|
|
714
|
+
SLAGI: 2,
|
|
715
|
+
UNTUK: 3,
|
|
716
|
+
MESIN: 4,
|
|
717
|
+
LIHAT: 5,
|
|
718
|
+
};
|
|
719
|
+
this.MAX_STACK_SIZE = 500;
|
|
720
|
+
this.init();
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
init() {
|
|
733
724
|
this.line = 0;
|
|
734
725
|
this.environment = new Environment(this.globalEnvironment);
|
|
735
726
|
this.tree = null;
|
|
736
|
-
this.state = location.GLOBAL;
|
|
727
|
+
this.state = this.location.GLOBAL;
|
|
737
728
|
this.stack = [];
|
|
738
729
|
this.output = [];
|
|
739
730
|
this.objectStack = null;
|
|
@@ -741,6 +732,14 @@ class Interpreter {
|
|
|
741
732
|
this.pipeStack = [];
|
|
742
733
|
}
|
|
743
734
|
|
|
735
|
+
interpret(tree) {
|
|
736
|
+
this.line = 0;
|
|
737
|
+
this.output = [];
|
|
738
|
+
this.tree = tree;
|
|
739
|
+
tree.accept(this);
|
|
740
|
+
return this.output;
|
|
741
|
+
}
|
|
742
|
+
|
|
744
743
|
// EXPRESSION VISITORS
|
|
745
744
|
|
|
746
745
|
visitLiteralExpr(literalExpr) {
|
|
@@ -762,7 +761,7 @@ class Interpreter {
|
|
|
762
761
|
let value = new Value(barisSymbol, []);
|
|
763
762
|
|
|
764
763
|
for (let expr of arrayExpr.contents) {
|
|
765
|
-
let v =
|
|
764
|
+
let v = expr.accept(this);
|
|
766
765
|
let newVar = new Variable(v.type, false, v.data);
|
|
767
766
|
newVar.member = v.member;
|
|
768
767
|
newVar.isDatum = true;
|
|
@@ -830,7 +829,7 @@ class Interpreter {
|
|
|
830
829
|
this.error(`Hanya bisa 'memanggil' mesin atau model, malah menemukan ${callable.type.description}. `);
|
|
831
830
|
}
|
|
832
831
|
|
|
833
|
-
if (!callable
|
|
832
|
+
if (!callable?.data?.block) {
|
|
834
833
|
this.error(`Mesin tidak terdefinisi, tidak bisa dipanggil.`);
|
|
835
834
|
}
|
|
836
835
|
|
|
@@ -841,7 +840,7 @@ class Interpreter {
|
|
|
841
840
|
this.objectStack = null;
|
|
842
841
|
}
|
|
843
842
|
|
|
844
|
-
args = [...args, ...callExpr.args.map(val =>
|
|
843
|
+
args = [...args, ...callExpr.args.map(val => val.accept(this))];
|
|
845
844
|
|
|
846
845
|
let result = this.callFunc(callable.data, args);
|
|
847
846
|
return result;
|
|
@@ -851,13 +850,16 @@ class Interpreter {
|
|
|
851
850
|
// args.forEach((val,idx)=>{
|
|
852
851
|
// console.log(idx, val);
|
|
853
852
|
// });
|
|
853
|
+
if (!callable) {
|
|
854
|
+
this.error(`Mesin tidak terdefinisi, tidak bisa dipanggil.`);
|
|
855
|
+
}
|
|
854
856
|
this.stack.push(this.line);
|
|
855
|
-
if (this.stack.length > MAX_STACK_SIZE)
|
|
856
|
-
this.error(`Rekursi melebihi batas: Lebih dari ${MAX_STACK_SIZE}`);
|
|
857
|
+
if (this.stack.length > this.MAX_STACK_SIZE)
|
|
858
|
+
this.error(`Rekursi melebihi batas: Lebih dari ${this.MAX_STACK_SIZE}`);
|
|
857
859
|
|
|
858
860
|
let prevState = this.state;
|
|
859
861
|
this.line = this.stack[this.stack.length - 1];
|
|
860
|
-
this.state = location.MESIN;
|
|
862
|
+
this.state = this.location.MESIN;
|
|
861
863
|
|
|
862
864
|
if (args.length !== callable.parameters.length) {
|
|
863
865
|
this.error(`Jumlah argumen tidak sama dengan parameter mesin. Menemukan ${args.length}, harusnya ${callable.parameters.length}.`);
|
|
@@ -918,8 +920,8 @@ class Interpreter {
|
|
|
918
920
|
|
|
919
921
|
|
|
920
922
|
visitBinaryExpr(binaryExpr) {
|
|
921
|
-
let leftValue =
|
|
922
|
-
let rightValue =
|
|
923
|
+
let leftValue = binaryExpr.left.accept(this);
|
|
924
|
+
let rightValue = binaryExpr.right.accept(this);
|
|
923
925
|
|
|
924
926
|
this.line = binaryExpr.op.line;
|
|
925
927
|
|
|
@@ -936,7 +938,7 @@ class Interpreter {
|
|
|
936
938
|
}
|
|
937
939
|
|
|
938
940
|
visitUnaryExpr(unaryExpr) {
|
|
939
|
-
let rightValue =
|
|
941
|
+
let rightValue = unaryExpr.right.accept(this);
|
|
940
942
|
|
|
941
943
|
this.line = unaryExpr.op.line;
|
|
942
944
|
|
|
@@ -967,7 +969,7 @@ class Interpreter {
|
|
|
967
969
|
}
|
|
968
970
|
|
|
969
971
|
visitGroupingExpr(groupingExpr) {
|
|
970
|
-
return
|
|
972
|
+
return groupingExpr.expr.accept(this);
|
|
971
973
|
}
|
|
972
974
|
|
|
973
975
|
visitIdentifierExpr(identifierExpr) {
|
|
@@ -1010,11 +1012,11 @@ class Interpreter {
|
|
|
1010
1012
|
}
|
|
1011
1013
|
|
|
1012
1014
|
visitPipeLineExpr (pipeLineExpr) {
|
|
1013
|
-
let expr =
|
|
1015
|
+
let expr = pipeLineExpr.expr.accept(this);
|
|
1014
1016
|
|
|
1015
1017
|
this.pipeStack.push(expr);
|
|
1016
1018
|
|
|
1017
|
-
let pipeValue =
|
|
1019
|
+
let pipeValue = pipeLineExpr.pipeTo.accept(this);
|
|
1018
1020
|
|
|
1019
1021
|
this.pipeStack.pop();
|
|
1020
1022
|
|
|
@@ -1027,7 +1029,8 @@ class Interpreter {
|
|
|
1027
1029
|
visitTypeStmt(typeStmt) {
|
|
1028
1030
|
if (typeStmt.type === null) return null;
|
|
1029
1031
|
let type = typeStmt.type.accept(this);
|
|
1030
|
-
if (type.type !== stipeSymbol
|
|
1032
|
+
if (type.type !== stipeSymbol || !(type.symbol))
|
|
1033
|
+
this.error(`'${type.type.description}' bukan sebuah Model/Tipe Valid.`);
|
|
1031
1034
|
return type.symbol;
|
|
1032
1035
|
}
|
|
1033
1036
|
|
|
@@ -1048,7 +1051,7 @@ class Interpreter {
|
|
|
1048
1051
|
|
|
1049
1052
|
let variable = new Variable(type, datumStmt.type.tetap);
|
|
1050
1053
|
|
|
1051
|
-
let value =
|
|
1054
|
+
let value = datumStmt.expr.accept(this);
|
|
1052
1055
|
|
|
1053
1056
|
if (value.data === null) value.type = variable.type; // if nihil, ok
|
|
1054
1057
|
|
|
@@ -1071,7 +1074,7 @@ class Interpreter {
|
|
|
1071
1074
|
if (variable.tetap) {
|
|
1072
1075
|
this.error(`Variabel tetap tidak dapat di-rubah.`);
|
|
1073
1076
|
}
|
|
1074
|
-
let value =
|
|
1077
|
+
let value = rubahStmt.value.accept(this);
|
|
1075
1078
|
if (value.data === null) value.type = variable.type; // if nihil, ok
|
|
1076
1079
|
|
|
1077
1080
|
if (variable.isDatum)
|
|
@@ -1110,20 +1113,20 @@ class Interpreter {
|
|
|
1110
1113
|
}
|
|
1111
1114
|
|
|
1112
1115
|
visitHentiStmt() {
|
|
1113
|
-
if (this.state === location.UNTUK || this.state === location.SLAGI)
|
|
1116
|
+
if (this.state === this.location.UNTUK || this.state === this.location.SLAGI)
|
|
1114
1117
|
throw new Henti$1(); // throws exception to escape from deep recursion
|
|
1115
1118
|
else this.error("Tidak ada pengulangan untuk dihentikan.");
|
|
1116
1119
|
}
|
|
1117
1120
|
|
|
1118
1121
|
|
|
1119
1122
|
visitLewatStmt() {
|
|
1120
|
-
if (this.state === location.UNTUK || this.state === location.SLAGI)
|
|
1123
|
+
if (this.state === this.location.UNTUK || this.state === this.location.SLAGI)
|
|
1121
1124
|
throw new Lewat$1(); // throws exception to escape from deep recursion
|
|
1122
1125
|
else this.error("Tidak ada pengulangan untuk dilewatkan.");
|
|
1123
1126
|
}
|
|
1124
1127
|
|
|
1125
1128
|
visitJatuhStmt() {
|
|
1126
|
-
if (this.state === location.LIHAT)
|
|
1129
|
+
if (this.state === this.location.LIHAT)
|
|
1127
1130
|
throw new Jatuh$1();
|
|
1128
1131
|
else this.error("Tidak bisa jatuh di luar blok kasus.");
|
|
1129
1132
|
}
|
|
@@ -1147,9 +1150,9 @@ class Interpreter {
|
|
|
1147
1150
|
this.environment = new Environment(lastEnv);
|
|
1148
1151
|
try {
|
|
1149
1152
|
for (let stmt of slagiStmt.block.statements) {
|
|
1150
|
-
this.state = location.SLAGI;
|
|
1153
|
+
this.state = this.location.SLAGI;
|
|
1151
1154
|
stmt.accept(this);
|
|
1152
|
-
this.state = location.SLAGI;
|
|
1155
|
+
this.state = this.location.SLAGI;
|
|
1153
1156
|
}
|
|
1154
1157
|
} catch (err) {
|
|
1155
1158
|
if (err instanceof Henti$1) {
|
|
@@ -1160,15 +1163,15 @@ class Interpreter {
|
|
|
1160
1163
|
}
|
|
1161
1164
|
}
|
|
1162
1165
|
this.environment = lastEnv;
|
|
1163
|
-
if (this.stackNum !== 0) this.state = location.MESIN;
|
|
1164
|
-
else this.state = location.GLOBAL;
|
|
1166
|
+
if (this.stackNum !== 0) this.state = this.location.MESIN;
|
|
1167
|
+
else this.state = this.location.GLOBAL;
|
|
1165
1168
|
}
|
|
1166
1169
|
|
|
1167
1170
|
visitUntukStmt(untukStmt) {
|
|
1168
1171
|
let name = this.validName(untukStmt.varName.lexeme, false);
|
|
1169
1172
|
let type = untukStmt.varType.accept(this);
|
|
1170
1173
|
|
|
1171
|
-
let iter =
|
|
1174
|
+
let iter = untukStmt.iterable.accept(this);
|
|
1172
1175
|
if (iter.type === petikSymbol) {
|
|
1173
1176
|
iter = new Value(barisSymbol, iter.data.split("").map(str => new Value(petikSymbol, str)));
|
|
1174
1177
|
}
|
|
@@ -1189,9 +1192,9 @@ class Interpreter {
|
|
|
1189
1192
|
try {
|
|
1190
1193
|
// didn't 'accept' the block, just uses it directly
|
|
1191
1194
|
for (let stmt of untukStmt.block.statements) {
|
|
1192
|
-
this.state = location.UNTUK;
|
|
1195
|
+
this.state = this.location.UNTUK;
|
|
1193
1196
|
stmt.accept(this);
|
|
1194
|
-
this.state = location.UNTUK;
|
|
1197
|
+
this.state = this.location.UNTUK;
|
|
1195
1198
|
}
|
|
1196
1199
|
} catch (err) {
|
|
1197
1200
|
this.environment = untukEnv.enclosing;
|
|
@@ -1205,8 +1208,8 @@ class Interpreter {
|
|
|
1205
1208
|
}
|
|
1206
1209
|
this.environment = untukEnv.enclosing;
|
|
1207
1210
|
}
|
|
1208
|
-
if (this.stackNum !== 0) this.state = location.MESIN;
|
|
1209
|
-
else this.state = location.GLOBAL;
|
|
1211
|
+
if (this.stackNum !== 0) this.state = this.location.MESIN;
|
|
1212
|
+
else this.state = this.location.GLOBAL;
|
|
1210
1213
|
}
|
|
1211
1214
|
|
|
1212
1215
|
visitJenisStmt(jenisStmt) {
|
|
@@ -1216,7 +1219,7 @@ class Interpreter {
|
|
|
1216
1219
|
}
|
|
1217
1220
|
|
|
1218
1221
|
visitLihatStmt(lihatStmt) {
|
|
1219
|
-
let match =
|
|
1222
|
+
let match = lihatStmt.expr.accept(this);
|
|
1220
1223
|
let matchType = this.environment.get(match?.type?.description);
|
|
1221
1224
|
if (!matchType?.member?.has("SAMA_SAMA")) {
|
|
1222
1225
|
this.error(`tipe ${matchType ? match.type.description : "nihil"} tidak mempunyai mesin SAMA_SAMA.`);
|
|
@@ -1226,9 +1229,9 @@ class Interpreter {
|
|
|
1226
1229
|
const handleBlock = (index) => {
|
|
1227
1230
|
while (index < lihatStmt.cases.length) {
|
|
1228
1231
|
try {
|
|
1229
|
-
this.state = location.LIHAT;
|
|
1232
|
+
this.state = this.location.LIHAT;
|
|
1230
1233
|
lihatStmt.cases[index][1].accept(this);
|
|
1231
|
-
this.state = location.LIHAT;
|
|
1234
|
+
this.state = this.location.LIHAT;
|
|
1232
1235
|
} catch (err) {
|
|
1233
1236
|
if (err instanceof Jatuh$1) {
|
|
1234
1237
|
index++; continue;
|
|
@@ -1236,8 +1239,8 @@ class Interpreter {
|
|
|
1236
1239
|
}
|
|
1237
1240
|
break;
|
|
1238
1241
|
}
|
|
1239
|
-
if (this.stackNum !== 0) this.state = location.MESIN;
|
|
1240
|
-
else this.state = location.GLOBAL;
|
|
1242
|
+
if (this.stackNum !== 0) this.state = this.location.MESIN;
|
|
1243
|
+
else this.state = this.location.GLOBAL;
|
|
1241
1244
|
};
|
|
1242
1245
|
|
|
1243
1246
|
for (let i = 0; i < lihatStmt.cases.length; i++) {
|
|
@@ -1271,7 +1274,7 @@ class Interpreter {
|
|
|
1271
1274
|
if (variable.type !== stipeSymbol) {
|
|
1272
1275
|
this.error(`Modul hanya bisa _ditambahkan_ pada tipe. '${name}' bukan merupakan tipe.`);
|
|
1273
1276
|
}
|
|
1274
|
-
if (variable.member.memory.size >
|
|
1277
|
+
if (variable.member.memory.size > 1) {
|
|
1275
1278
|
this.error(`Tipe '${name}' sudah memiliki modul sendiri, tidak bisa definisi ulang.`);
|
|
1276
1279
|
}
|
|
1277
1280
|
} else {
|
|
@@ -1295,6 +1298,7 @@ class Interpreter {
|
|
|
1295
1298
|
|
|
1296
1299
|
typeCheck(a, b, message) {
|
|
1297
1300
|
if (a.type !== b.type) {
|
|
1301
|
+
console.log(a, b);
|
|
1298
1302
|
this.error(`Tipe data tidak sama: ${a.type.description} != ${b.type.description}. ` + message);
|
|
1299
1303
|
}
|
|
1300
1304
|
}
|
|
@@ -1306,11 +1310,6 @@ class Interpreter {
|
|
|
1306
1310
|
return false;
|
|
1307
1311
|
}
|
|
1308
1312
|
|
|
1309
|
-
validValue(v) {
|
|
1310
|
-
if (v.type !== stipeSymbol) return v;
|
|
1311
|
-
this.error("stipe tidak dapat menjadi nilai.");
|
|
1312
|
-
}
|
|
1313
|
-
|
|
1314
1313
|
validName(n, checkExisted = true) {
|
|
1315
1314
|
if (RESERVED_NAMES.some(v => v === n)) {
|
|
1316
1315
|
this.error(`Nama sistem (${n}) tidak boleh didefinisi ulang.`);
|
|
@@ -1324,13 +1323,7 @@ class Interpreter {
|
|
|
1324
1323
|
throw new SimplErrorEksekusi(`Error Eksekusi => ${message}`, this.line, this.output.join('\n'));
|
|
1325
1324
|
}
|
|
1326
1325
|
|
|
1327
|
-
|
|
1328
|
-
this.line = 0;
|
|
1329
|
-
this.output = [];
|
|
1330
|
-
this.tree = tree;
|
|
1331
|
-
tree.accept(this);
|
|
1332
|
-
return this.output;
|
|
1333
|
-
}
|
|
1326
|
+
|
|
1334
1327
|
}
|
|
1335
1328
|
|
|
1336
1329
|
class Token {
|
|
@@ -1360,6 +1353,23 @@ class Lexer {
|
|
|
1360
1353
|
this.errors = [];
|
|
1361
1354
|
}
|
|
1362
1355
|
|
|
1356
|
+
scanTokens(text) {
|
|
1357
|
+
this.init();
|
|
1358
|
+
this.text = text;
|
|
1359
|
+
let tokens = [];
|
|
1360
|
+
|
|
1361
|
+
while (!this.isAtEnd()) {
|
|
1362
|
+
let token = this.scan();
|
|
1363
|
+
this.charStart = this.charIndex;
|
|
1364
|
+
if (token) tokens.push(token);
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
tokens.push(new Token(EOF, "Akhir dokumen", null, this.lineIndex));
|
|
1368
|
+
|
|
1369
|
+
this.tokens = tokens;
|
|
1370
|
+
return this.tokens;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1363
1373
|
isAtEnd() {
|
|
1364
1374
|
return this.charIndex >= this.text.length;
|
|
1365
1375
|
}
|
|
@@ -1402,23 +1412,6 @@ class Lexer {
|
|
|
1402
1412
|
return this.text.slice(this.charStart, this.charIndex);
|
|
1403
1413
|
}
|
|
1404
1414
|
|
|
1405
|
-
scanTokens(text) {
|
|
1406
|
-
this.init();
|
|
1407
|
-
this.text = text;
|
|
1408
|
-
let tokens = [];
|
|
1409
|
-
|
|
1410
|
-
while (!this.isAtEnd()) {
|
|
1411
|
-
let token = this.scan();
|
|
1412
|
-
this.charStart = this.charIndex;
|
|
1413
|
-
if (token) tokens.push(token);
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
|
-
tokens.push(new Token(EOF, "Akhir dokumen", null, this.lineIndex));
|
|
1417
|
-
|
|
1418
|
-
this.tokens = tokens;
|
|
1419
|
-
return this.tokens;
|
|
1420
|
-
}
|
|
1421
|
-
|
|
1422
1415
|
id() {
|
|
1423
1416
|
while (!this.isAtEnd() && this.isAlphaNumeric(this.see())) this.advance();
|
|
1424
1417
|
|
|
@@ -1968,6 +1961,17 @@ class Parser {
|
|
|
1968
1961
|
this.tree = null;
|
|
1969
1962
|
}
|
|
1970
1963
|
|
|
1964
|
+
parse(tokens) {
|
|
1965
|
+
this.init();
|
|
1966
|
+
this.tokens = tokens;
|
|
1967
|
+
let treeList = [];
|
|
1968
|
+
while (!this.match(EOF)) {
|
|
1969
|
+
treeList.push(this.statement());
|
|
1970
|
+
}
|
|
1971
|
+
this.tree = new Simpl$1(treeList);
|
|
1972
|
+
return this.tree;
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1971
1975
|
see() {
|
|
1972
1976
|
return this.tokens[this.tokenIndex];
|
|
1973
1977
|
}
|
|
@@ -2446,28 +2450,23 @@ class Parser {
|
|
|
2446
2450
|
throw new SimplErrorStruktur(`Error Struktur => ` + errmsg + ((found) ? ` Menemukan '${this.see().lexeme}'.` : ""), this.see().line);
|
|
2447
2451
|
}
|
|
2448
2452
|
|
|
2449
|
-
parse(tokens) {
|
|
2450
|
-
this.init();
|
|
2451
|
-
this.tokens = tokens;
|
|
2452
|
-
let treeList = [];
|
|
2453
|
-
while (!this.match(EOF)) {
|
|
2454
|
-
treeList.push(this.statement());
|
|
2455
|
-
}
|
|
2456
|
-
this.tree = new Simpl$1(treeList);
|
|
2457
|
-
return this.tree;
|
|
2458
|
-
}
|
|
2459
2453
|
}
|
|
2460
2454
|
|
|
2461
2455
|
// Simpl: Indonesian Mini Programming Language !!
|
|
2462
2456
|
|
|
2463
2457
|
class Simpl {
|
|
2464
|
-
constructor(
|
|
2458
|
+
constructor(opts = {
|
|
2459
|
+
keepMemory: false
|
|
2460
|
+
}) {
|
|
2465
2461
|
this.lexer = new Lexer();
|
|
2466
2462
|
this.parser = new Parser();
|
|
2467
2463
|
this.interpreter = new Interpreter();
|
|
2464
|
+
this.keepMemory = opts?.keepMemory ? opts.keepMemory : false;
|
|
2468
2465
|
}
|
|
2469
2466
|
|
|
2470
2467
|
runCode(text) {
|
|
2468
|
+
if (!this.keepMemory) this.interpreter.init();
|
|
2469
|
+
|
|
2471
2470
|
// console.log(text.split("\n").reduce((codeStr, line, idx) => codeStr + `${idx + 1}.\t${line}\n`, ''));
|
|
2472
2471
|
const textLines = text.split("\n");
|
|
2473
2472
|
try {
|
|
@@ -2476,7 +2475,6 @@ class Simpl {
|
|
|
2476
2475
|
let output = this.interpreter.interpret(pohon);
|
|
2477
2476
|
return output.join("\n");
|
|
2478
2477
|
} catch (err) {
|
|
2479
|
-
// throw err
|
|
2480
2478
|
if (err instanceof SimplError) {
|
|
2481
2479
|
const errorCode = textLines[err.line - 1];
|
|
2482
2480
|
let errorText = (errorCode ? `ERROR! Pada baris ke-${err.line}\n>> ` + errorCode + '\n' : "") + err.message;
|
|
@@ -2490,10 +2488,6 @@ class Simpl {
|
|
|
2490
2488
|
}
|
|
2491
2489
|
|
|
2492
2490
|
}
|
|
2493
|
-
}
|
|
2494
|
-
|
|
2495
|
-
function run(code) {
|
|
2496
|
-
return new Simpl().runCode(code);
|
|
2497
2491
|
}
|
|
2498
2492
|
|
|
2499
|
-
export {
|
|
2493
|
+
export { Simpl };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class e extends Error{constructor(e,t){super(e),this.line=t}}class t extends e{constructor(e,t,i){super(e,t),this.output=i}}class i extends e{}class a extends e{}class s{constructor(e){this.enclosing=e,this.memory=new Map}define(e,t){this.memory.set(e,t)}assign(e,t){return this.has(e)?this.memory.set(e,t):this.enclosing&&this.enclosing.assign(e,t),null}get(e){return this.has(e)?this.memory.get(e):this.enclosing?this.enclosing.get(e):null}has(e){return this.memory.has(e)}}const n=["petik","angka","logis","mesin","baris","stipe","modul"],r=Symbol("petik"),h=Symbol("angka"),l=Symbol("logis"),m=Symbol("mesin"),o=Symbol("baris"),d=Symbol("stipe"),u=Symbol("modul");class c{constructor(e,t){this.type=e,this.data=t,this.member=null}}const p=new c(null,null);class k extends c{constructor(e,t,i){super(e,i),this.tetap=t,this.isDatum=!1}}class b extends k{constructor(e,t){super(d,!0,t),this.symbol=e,this.member=new s,this.member.define("buat",new k(m,!0,t))}}function f(e,t){if(t.type===l)return t.data?"benar":"salah";if(t.type===o)return"["+t.data.reduce((t,i)=>t+", "+f(e,i),"").slice(1)+" ]";if(t.type===d)return`Model<${t.symbol?.description?t.symbol.description:""}>`;if(t.type===m){let e=t.data.returnType?.description;return`Mesin<${e||"datum"}>`}if(t.type===h)return t.data.toString();if(t.type===r)return t.data;{if(!t?.type)return"nihil";let i=e.environment.get(t.type.description);if(i?.member.has("kePetik")){return e.callFunc(i.member.get("kePetik").data,[t]).data}return`${t.type.description}<>`}}let w=class extends b{constructor(e,t){let i=Symbol(e);super(i,new g(null,(e,a)=>{let n=new c(i,!0);n.member=new s;let r=e.line;for(let i=0;i<a.length;i++){let s=t[i][0],h=s.accept(e),l=t[i][1].lexeme,m=new k(h,s.tetap,a[i].data);null===h?(m.isDatum=!0,m.type=a[i].type):a[i].type!==h&&(e.line=r,e.error(`Argumen pembuatan objek tidak sama dengan argumen model, menemukan ${a[i].type?.description}, mengharapkan ${h?h.description:"nihil"}`)),m.member=a[i].member,n.member.define(l,m)}return n},t.map(e=>[null]),i,!0))}},S=class extends b{constructor(e,t){let i=Symbol(e);super(i,null),t.forEach((e,t)=>{this.member.define(e.lexeme,new c(i,t))}),this.member.define("kePetik",y([i],r,(t,[i])=>new c(r,`${e}<${i.data}>`))),this.member.define("SAMA_SAMA",y([i,i],l,(e,[t,i])=>new c(l,i.data===t.data))),this.member.define("SERU_SAMA",y([i,i],l,(e,[t,i])=>new c(l,i.data!==t.data)))}};class g{constructor(e,t,i,a,s=!1){this.closure=e,this.block=t,this.parameters=i,this.returnType=a,this.isBuiltIn=s}}function y(e,t,i){let a=new g(null,i,e.map(e=>[e]),t,!0);return new k(m,!0,a)}function A(e){switch(e.type){case r:return new c(r,e.data);case h:return new c(h,e.data);case l:return new c(l,e.data);case m:return new c(m,e.data);case o:return new c(o,e.data.map(e=>{let t=A(e),i=new k(t.type,!1,t.data);return i.member=t.member,i}));case d:case u:return p;default:if(e.member&&e.member instanceof s){let t=e.member.memory.keys(),i=new c(e.type,null),a=new s;for(let i of t){let t=e.member.get(i),s=A(t),n=new k(t.type,t.tetap,s.data);n.member=s.member,a.define(i,n)}return i.member=a,i.data=e.data,i}return new c(e.type,e.data)}}const x=(()=>{let e=new b(r,new g(null,(e,t)=>new c(r,f(e,t[0])),[[null]],r,!0));return e.member.define("PLUS",y([r,r],r,(e,[t,i])=>new c(r,i.data+t.data))),e.member.define("LEBIH",y([r,r],l,(e,[t,i])=>new c(l,i.data>t.data))),e.member.define("KURANG",y([r,r],l,(e,[t,i])=>new c(l,i.data<t.data))),e.member.define("SAMA_SAMA",y([r,r],l,(e,[t,i])=>new c(l,i.data===t.data))),e.member.define("LEBIH_SAMA",y([r,r],l,(e,[t,i])=>new c(l,i.data>=t.data))),e.member.define("KURANG_SAMA",y([r,r],l,(e,[t,i])=>new c(l,i.data<=t.data))),e.member.define("SERU_SAMA",y([r,r],l,(e,[t,i])=>new c(l,i.data!==t.data))),e.member.define("AMPERSAN",y([r,r],l,(e,[t,i])=>new c(l,i.data&&t.data))),e.member.define("PIPA",y([r,r],l,(e,[t,i])=>new c(l,i.data||t.data))),e.member.define("SERU_UNER",y([r],l,(e,[t])=>new c(l,!Boolean(t.data)))),e.member.define("kePetik",y([r],r,(e,[t])=>new c(r,f(e,t)))),e.member.define("pisah",y([r,r],o,(e,[t,i])=>new c(o,t.data.split(i.data).map(e=>new c(r,e))))),e.member.define("bersih",y([r],r,(e,[t])=>new c(r,t.data.trim()))),e.member.define("ganti",y([r,r,r],r,(e,[t,i,a])=>new c(r,t.data.replaceAll(i.data,a.data)))),e.member.define("besar",y([r],r,(e,[t])=>new c(r,t.data.toUpperCase()))),e.member.define("kecil",y([r],r,(e,[t])=>new c(r,t.data.toLowerCase()))),e})(),M=(()=>{let e=new b(h,new g(null,(e,t)=>{if("number"==typeof t[0].data)return new c(h,t[0].data);switch(t[0].type){case r:return isNaN(Number(t[0].data))&&e.error("Nilai dari petik bukanlah sebuah angka, konversi gagal."),new c(h,Number(t[0].data));case h:return new c(h,t[0].data);case l:return new c(h,Number(t[0].data));default:return void e.error(`Tipe yang dapat diterima hanyalah petik, angka, logis, dan jenis. Mendapatkan ${t[0].type.description}.`)}},[[null]],h,!0));return e.member.define("PLUS",y([h,h],h,(e,[t,i])=>new c(h,i.data+t.data))),e.member.define("MINUS",y([h,h],h,(e,[t,i])=>new c(h,i.data-t.data))),e.member.define("BINTANG",y([h,h],h,(e,[t,i])=>new c(h,i.data*t.data))),e.member.define("GARIS_MIRING",y([h,h],h,(e,[t,i])=>new c(h,i.data/t.data))),e.member.define("MODULUS",y([h,h],h,(e,[t,i])=>new c(h,i.data%t.data))),e.member.define("LEBIH",y([h,h],l,(e,[t,i])=>new c(l,i.data>t.data))),e.member.define("KURANG",y([h,h],l,(e,[t,i])=>new c(l,i.data<t.data))),e.member.define("SAMA_SAMA",y([h,h],l,(e,[t,i])=>new c(l,i.data===t.data))),e.member.define("LEBIH_SAMA",y([h,h],l,(e,[t,i])=>new c(l,i.data>=t.data))),e.member.define("KURANG_SAMA",y([h,h],l,(e,[t,i])=>new c(l,i.data<=t.data))),e.member.define("SERU_SAMA",y([h,h],l,(e,[t,i])=>new c(l,i.data!==t.data))),e.member.define("AMPERSAN",y([h,h],l,(e,[t,i])=>new c(l,i.data&&t.data))),e.member.define("PIPA",y([h,h],l,(e,[t,i])=>new c(l,i.data||t.data))),e.member.define("SERU_UNER",y([h],l,(e,[t])=>new c(l,!Boolean(t.data)))),e.member.define("PLUS_UNER",y([h],h,(e,[t])=>new c(h,+t.data))),e.member.define("MINUS_UNER",y([h],h,(e,[t])=>new c(h,-t.data))),e.member.define("kePetik",y([h],r,(e,[t])=>new c(r,f(e,t)))),e.member.define("bulat",y([h],h,(e,[t])=>new c(h,Math.round(t.data)))),e.member.define("bulatAtas",y([h],h,(e,[t])=>new c(h,Math.ceil(t.data)))),e.member.define("bulatBawah",y([h],h,(e,[t])=>new c(h,Math.floor(t.data)))),e})(),E=(()=>{let e=new b(l,new g(null,(e,t)=>t[0].type===o&&0===t[0].data.length?new c(l,!1):new c(l,Boolean(t[0].data)||Boolean(t[0].data?.member?.size)),[[null]],l,!0));return e.member.define("SAMA_SAMA",y([l,l],l,(e,[t,i])=>new c(l,i.data===t.data))),e.member.define("SERU_SAMA",y([l,l],l,(e,[t,i])=>new c(l,i.data!==t.data))),e.member.define("AMPERSAN",y([l,l],l,(e,[t,i])=>new c(l,i.data&&t.data))),e.member.define("PIPA",y([l,l],l,(e,[t,i])=>new c(l,i.data||t.data))),e.member.define("SERU_UNER",y([l],l,(e,[t])=>new c(l,!Boolean(t.data)))),e.member.define("kePetik",y([l],r,(e,[t])=>new c(r,f(e,t)))),e})(),T=(()=>{let e=new b(o);const t=e=>{let t=new k(e.type,!1,e.data);return t.member=e.member,t.isDatum=!0,t};return e.member.define("PLUS",y([o,o],o,(e,[t,i])=>new c(o,Array(...i.data,...t.data)))),e.member.define("MINUS_UNER",y([o],o,(e,[t])=>new c(o,t.data.slice(0,t.length)))),e.member.define("SAMA_SAMA",y([o,o],l,(e,[t,i])=>new c(l,((e,t)=>{if(e.length!==t.length)return!1;for(let i=0;i<e.length;i++)if(e[i].data!==t[i].data)return!1;return!0})(i.data,t.data)))),e.member.define("SERU_SAMA",y([o,o],l,(e,[t,i])=>new c(l,((e,t)=>{if(e.length!==t.length)return!0;for(let i=0;i<e.length;i++)if(e[i].data!==t[i].data)return!0;return!1})(i.data,t.data)))),e.member.define("AMPERSAN",y([o,o],l,(e,[t,i])=>new c(l,i.data&&t.data))),e.member.define("PIPA",y([o,o],l,(e,[t,i])=>new c(l,i.data||t.data))),e.member.define("SERU_UNER",y([o],l,(e,[t])=>new c(l,!Boolean(t.data)))),e.member.define("kePetik",y([o],r,(e,[t])=>new c(r,f(e,t)))),e.member.define("hapus",y([o,h],o,(e,[t,i])=>{for(t.data.length<=i.data&&e.error(`Indeks tidak boleh lebih besar atau sama dengan ukuran baris, ${i.data} >= ${t.data.length}`);i.data<0;)i.data+=t.data.length;return t.data=t.data.filter((e,t)=>t!==i.data),t})),e.member.define("potongan",y([o,h,h],o,(e,[t,i,a])=>((i.data>=t.data.length||i.data<0||a.data<=i.data||a.data>t.data.length)&&e.error(`Indeks tidak valid, ${i.data} sampai ${a.data}, dengan ukuran baris ${t.data.length}`),new c(o,t.data.slice(i.data,a.data))))),e.member.define("tumpuk",y([o,null],null,(e,[i,a])=>(i.data.push(t(a)),i))),e.member.define("tumpah",y([o],null,(e,[t])=>(t.data.pop(),t))),e.member.define("masuk",y([o,null,h],null,(e,[i,a,s])=>(s.data>i.data.length&&e.error(`Indeks tidak valid, ${s.data}, dengan ukuran baris ${i.data.length}`),i.data.splice(s.data,0,t(a)),i))),e.member.define("petakan",y([o,m],o,(e,[i,a])=>{let s=new c(o,[]);for(let n of i.data){let i=e.callFunc(a.data,[n]);s.data.push(t(i))}return s})),e.member.define("saring",y([o,m],o,(e,[i,a])=>{let s=new c(o,[]);for(let n of i.data){!0===e.callFunc(a.data,[n]).data&&s.data.push(t(n))}return s})),e.member.define("reduksi",y([o,m,null],null,(e,[t,i,a])=>{for(let s of t.data){a=e.callFunc(i.data,[a,s])}return a})),e.member.define("punya?",y([o,null],l,(e,[t,i])=>{let a,s=e.environment.get(i.type?.description);s||e.error("Tipe tidak ditemukan atau tidak valid"),s.member?.has("SAMA_SAMA")?a=s.member.get("SAMA_SAMA"):e.error(`model ${i.type.description} tidak mempunyai mesin SAMA_SAMA di dalam modulnya.`);for(let s of t.data){if(s.type!==i.type)continue;if(e.callFunc(a.data,[s,i]).data)return new c(l,!0)}return new c(l,!1)})),e})(),I=(()=>{let e=new b(m);return e.member.define("kePetik",y([m],r,(e,[t])=>new c(r,f(e,t)))),e})(),N=(()=>{let e=new s;e.define("petik",x),e.define("angka",M),e.define("logis",E),e.define("baris",T),e.define("mesin",I),e.define("jarak",y([h,h],o,(e,[t,i])=>new c(o,Array(Math.abs(Math.floor(i.data-t.data))).fill(0).map((e,a)=>new c(h,t.data+(i.data>t.data?1:-1)*a))))),e.define("nihil?",y([null],l,(e,[t])=>new c(l,null===t.data))),e.define("ukuran",y([null],h,(e,[t])=>t.type===o||t.type===r?new c(h,t.data.length):v.error(`Ukuran hanya terdapat untuk tipe petik atau baris. Menemukan tipe ${t.type.description}.`))),e.define("salin",y([null],null,(e,[t])=>A(t))),e.define("tipe",y([null],r,(e,[t])=>t.type?.description?new c(r,t.type.description):new c(r,"datum")));let t=new k(u,!0,null);t.member=new s,t.member.define("acak",y([h,h],h,(e,[t,i])=>{let a=Math.abs(t.data-i.data),s=Math.random()*a+Math.min(t.data,i.data);return new c(h,s)})),t.member.define("akar2",y([h],h,(e,[t])=>new c(h,Math.sqrt(t.data)))),t.member.define("min",y([h,h],h,(e,[t,i])=>new c(h,Math.min(t.data,i.data)))),t.member.define("maks",y([h,h],h,(e,[t,i])=>new c(h,Math.max(t.data,i.data))));const i=(e,t)=>{for([e,t]=[Math.max(e,t),Math.min(e,t)];t>0;)[e,t]=[t,e%t];return e};return t.member.define("fpb",y([h,h],h,(e,[t,a])=>{let s=i(t.data,a.data);return new c(h,s)})),t.member.define("kpk",y([h,h],h,(e,[t,a])=>{let s=i(t.data,a.data);return new c(h,t.data*a*data/s)})),e.define("mtk",t),e})(),L=["rubah","kalau","namun","slagi","untuk","cetak","henti","lewat","dalam","hasil","kerja","datum","jenis","model","tetap","modul","lihat","kasus","jatuh"],U=11,$=20,R=21,P=26,_=27,B=37,C=["RUBAH","KALAU","NAMUN","SLAGI","UNTUK","CETAK","HENTI","LEWAT","DALAM","HASIL","KERJA","DATUM","JENIS","MODEL","TETAP","MODUL","LIHAT","KASUS","JATUH","EOF","ID","LITERAL","PLUS","MINUS","BINTANG","GARIS_MIRING","LPAREN","RPAREN","LEBIH","LEBIH_SAMA","KURANG","KURANG_SAMA","SAMA","SAMA_SAMA","DOT","LCURLY","RCURLY","COMMA","LSQUARE","RSQUARE","PIPA","AMPERSAN","SERU","ARROW","SERU_SAMA","MODULUS","PIPELINE","COLON","DOLLAR"];let j=class{},G=class{},K=class{},H=class{constructor(e){this.value=e}};class O{constructor(){this.globalEnvironment=N,this.location={GLOBAL:1,SLAGI:2,UNTUK:3,MESIN:4,LIHAT:5},this.MAX_STACK_SIZE=500,this.init()}init(){this.line=0,this.environment=new s(this.globalEnvironment),this.tree=null,this.state=this.location.GLOBAL,this.stack=[],this.output=[],this.objectStack=null,this.exprWillBeCalled=!1,this.pipeStack=[]}interpret(e){return this.line=0,this.output=[],this.tree=e,e.accept(this),this.output}visitLiteralExpr(e){let t=e.token;switch(this.line=t.line,typeof t.value){case"string":return new c(r,t.value);case"number":return new c(h,t.value);case"boolean":return new c(l,t.value);default:return p}}visitArrayExpr(e){let t=new c(o,[]);for(let i of e.contents){let e=i.accept(this),a=new k(e.type,!1,e.data);a.member=e.member,a.isDatum=!0,t.data.push(a)}return t}visitIndexExpr(e){let t=e.iterable.accept(this);t.type===r&&(t=new c(o,t.data.split("").map(e=>new c(r,e)))),t.type!==o&&this.error(`'${t.type.description}' bukan baris/petik, tidak bisa di-indeks`);let i=e.index.accept(this);for(i.type!==h&&this.error(`Ekspresi di dalam indeks harus bertipe angka. Menemukan ${i.type.description}`),i.data>=t.data.length&&this.error(`Indeks tidak boleh lebih besar atau sama dengan ukuran baris: ${i.data} >= ${t.data.length}`);i.data<0;)i.data+=t.data.length;return t.data[i.data]}visitLambdaExpr(e){let t=e.params.map(e=>[e[0].accept(this),e[0].tetap,e[1].lexeme]);t.length>1&&(e=>{let t=new Map;for(let i of e){if(t.has(i))return!0;t.set(i,!0)}return!1})(t.map(e=>e[2]))&&this.error("Parameter mesin tidak boleh mempunyai nama yang sama.");let i=null;e.returnType&&(i=e.returnType.accept(this));let a=new g(this.environment,e.block,t,i);return new c(m,a)}visitCallExpr(e){this.exprWillBeCalled=!0;let t=e.callable.accept(this);this.exprWillBeCalled=!1,t.type!==m&&t.type!==d&&this.error(`Hanya bisa 'memanggil' mesin atau model, malah menemukan ${t.type.description}. `),t?.data?.block||this.error("Mesin tidak terdefinisi, tidak bisa dipanggil.");let i=[];return this.objectStack&&(i=[this.objectStack],this.objectStack=null),i=[...i,...e.args.map(e=>e.accept(this))],this.callFunc(t.data,i)}callFunc(e,t){e||this.error("Mesin tidak terdefinisi, tidak bisa dipanggil."),this.stack.push(this.line),this.stack.length>this.MAX_STACK_SIZE&&this.error(`Rekursi melebihi batas: Lebih dari ${this.MAX_STACK_SIZE}`);let i=this.state;this.line=this.stack[this.stack.length-1],this.state=this.location.MESIN,t.length!==e.parameters.length&&this.error(`Jumlah argumen tidak sama dengan parameter mesin. Menemukan ${t.length}, harusnya ${e.parameters.length}.`);let a=this.line;for(let i=0;i<t.length;i++){let s=e.parameters[i][0];null!==s&&(t[i].type!==s&&(this.line=a,this.error(`Tipe argumen tidak sama dengan parameter. Menemukan ${t[i].type.description}, harusnya ${s.description}`)))}if(e.isBuiltIn)return this.stack.pop(),this.state=i,e.block(this,t);let n=this.environment,r=new s(e.closure);this.environment=r;for(let i=0;i<t.length;i++){let[a,s,n]=e.parameters[i];null===a&&(a=t[i].type);let r=new k(a,s,t[i].data);r.member=t[i].member,this.environment.define(n,r)}let h=p;for(let t of e.block.statements)try{t.accept(this)}catch(e){if(e instanceof H){h=e.value;break}if(!(e instanceof j||e instanceof K))throw e;this.error("Tidak bisa menghentikan atau melewatkan mesin. ")}return this.stack.pop(),this.state=i,this.environment=n,h}visitBinaryExpr(e){let t=e.left.accept(this),i=e.right.accept(this);this.line=e.op.line,this.nullCheck(t,i)&&this.error("Tidak bisa mengoperasikan nilai Nihil."),this.typeCheck(t,i,`Pada operasi biner ${e.op.lexeme}`);let a=this.environment.get(t.type.description);return this.operate(a,e.op.type,i,t)}visitUnaryExpr(e){let t=e.right.accept(this);this.line=e.op.line,this.nullCheck(t)&&this.error("Tidak bisa mengoperasikan nilai Nihil.");let i=this.environment.get(t.type.description);return this.operate(i,e.op.type,t)}operate(e,t,i,a){let s=C[t]+(a?"":"_UNER"),n=e.member.get(s);n||this.error(`operator ${s} tidak terdefinisi untuk Model ${i.type.description}.`);let r=null;return r=a?this.callFunc(n.data,[i,a]):this.callFunc(n.data,[i]),r}visitGroupingExpr(e){return e.expr.accept(this)}visitIdentifierExpr(e){if("$"===e.token.lexeme){if(this.line=e.token.line,!(this.pipeStack.length<=0))return this.pipeStack[this.pipeStack.length-1];this.error("$ hanya ada dalam ekspresi saluran.")}let t=this.environment.get(e.token.lexeme);return this.line=e.token.line,t||this.error(`'${e.token.lexeme}' tidak dapat ditemukan.`),t}visitMemberExpr(e){let t=this.exprWillBeCalled;this.exprWillBeCalled=!1;let i=e.main.accept(this),a=e.member.token.lexeme;if(this.line=e.member.token.line,i?.member&&i.member.has(a))return i.member.get(a);{const e=this.environment.get(i.type.description);if(e||this.error(`nama .${a} tidak ditemukan.`),e.member?.has(a)){if(t)return this.objectStack=i,e.member.get(a);this.error("akses titik . dari objek ke model harus berupa panggilan/penggunaaan mesin.")}this.error(`nama .${a} tidak ditemukan dalam tipe ${i.type.description}`)}}visitPipeLineExpr(e){let t=e.expr.accept(this);this.pipeStack.push(t);let i=e.pipeTo.accept(this);return this.pipeStack.pop(),i}visitTypeStmt(e){if(null===e.type)return null;let t=e.type.accept(this);return t.type===d&&t.symbol||this.error(`'${t.type.description}' bukan sebuah Model/Tipe Valid.`),t.symbol}visitCetakStmt(e){let t=e.expr.accept(this);this.output.push(f(this,t))}visitKerjaStmt(e){e.expr.accept(this)}visitDatumStmt(e){let t=e.type.accept(this),i=this.validName(e.name.lexeme);this.line=e.name.line;let a=new k(t,e.type.tetap),s=e.expr.accept(this);null===s.data&&(s.type=a.type),null===t?(a.isDatum=!0,a.type=s.type):this.typeCheck(a,s,`Pada pembuatan variabel '${i}'`),a.data=s.data,a.member=s.member,this.environment.define(i,a)}visitRubahStmt(e){let t=e.variable.accept(this);void 0===t.tetap&&this.error("Pe-rubah-an hanya dapat dilakukan kepada Variabel!"),t.tetap&&this.error("Variabel tetap tidak dapat di-rubah.");let i=e.value.accept(this);null===i.data&&(i.type=t.type),t.isDatum?t.type=i.type:this.typeCheck(t,i,"Pada perubahan variabel."),t.data=i.data,t.member=i.member}visitBlockStmt(e){let t=new s(this.environment);this.environment=t;try{for(let t of e.statements)t.accept(this)}catch(e){throw this.environment=t.enclosing,e}this.environment=t.enclosing}visitKalauStmt(e){let t=e.condition?.accept(this);t?.type&&t?.type!==l&&this.error(`Ekspresi dalam 'kalau' harus bertipe logis, menemukan ${t.type?t.type.description:"nihil"}`),null==t||t.data?e.thenBlock.accept(this):e.elseKalau?.accept(this)}visitHentiStmt(){if(this.state===this.location.UNTUK||this.state===this.location.SLAGI)throw new j;this.error("Tidak ada pengulangan untuk dihentikan.")}visitLewatStmt(){if(this.state===this.location.UNTUK||this.state===this.location.SLAGI)throw new K;this.error("Tidak ada pengulangan untuk dilewatkan.")}visitJatuhStmt(){if(this.state===this.location.LIHAT)throw new G;this.error("Tidak bisa jatuh di luar blok kasus.")}visitHasilStmt(e){throw 0==this.stack.length&&this.error("Tidak bisa menghasilkan diluar blok mesin."),new H(e.expr.accept(this))}visitSlagiStmt(e){const t=e=>(e.type!==l&&this.error(`Ekspresi dalam 'slagi' harus bertipe 'logis', menemukan ${e.type?e.type.description:"nihil"}`),e.data);let i=this.environment;for(;t(e.condition.accept(this));){this.environment=new s(i);try{for(let t of e.block.statements)this.state=this.location.SLAGI,t.accept(this),this.state=this.location.SLAGI}catch(e){if(e instanceof j)break;if(e instanceof K)continue;throw e}}this.environment=i,0!==this.stackNum?this.state=this.location.MESIN:this.state=this.location.GLOBAL}visitUntukStmt(e){let t=this.validName(e.varName.lexeme,!1),i=e.varType.accept(this),a=e.iterable.accept(this);a.type===r&&(a=new c(o,a.data.split("").map(e=>new c(r,e)))),a.type!==o&&this.error(`Pernyataan 'untuk' harus mengiterasi sebuah baris atau petik, bukan ${a.type.description}`);for(let n=0;n<a.data.length;n++){let r=a.data[n],h=new k(r.type,!!e.type?.tetap,r.data);null===i?h.isDatum=!0:r.type!==i&&this.error(`Tipe data tidak sama pada indeks ke-${n}: ${r.type.description} != ${i.description}.`);let l=new s(this.environment);l.define(t,h),this.environment=l;try{for(let t of e.block.statements)this.state=this.location.UNTUK,t.accept(this),this.state=this.location.UNTUK}catch(e){if(this.environment=l.enclosing,e instanceof K)continue;if(e instanceof j)break;throw e}this.environment=l.enclosing}0!==this.stackNum?this.state=this.location.MESIN:this.state=this.location.GLOBAL}visitJenisStmt(e){let t=this.validName(e.name.lexeme);this.line=e.name.line,this.environment.define(t,new S(t,e.enums))}visitLihatStmt(e){let t=e.expr.accept(this),i=this.environment.get(t?.type?.description);i?.member?.has("SAMA_SAMA")||this.error(`tipe ${i?t.type.description:"nihil"} tidak mempunyai mesin SAMA_SAMA.`);let a=i.member.get("SAMA_SAMA");const s=t=>{for(;t<e.cases.length;){try{this.state=this.location.LIHAT,e.cases[t][1].accept(this),this.state=this.location.LIHAT}catch(e){if(e instanceof G){t++;continue}throw e}break}0!==this.stackNum?this.state=this.location.MESIN:this.state=this.location.GLOBAL};for(let i=0;i<e.cases.length;i++){let n=e.cases[i];if(!n[0])return s(i);let r=n[0].accept(this);if(this.callFunc(a.data,[t,r]).data)return s(i)}}visitSimplStmt(e){for(let t of e.statements)t.accept(this)}visitModelStmt(e){let t=this.validName(e.name.lexeme);this.line=e.name.line,this.environment.define(t,new w(t,e.contents))}visitModulStmt(e){let t=this.validName(e.name.lexeme,!1);this.line=e.name.line;let i=this.environment.get(t);i?(i.type!==d&&this.error(`Modul hanya bisa _ditambahkan_ pada tipe. '${t}' bukan merupakan tipe.`),i.member.memory.size>1&&this.error(`Tipe '${t}' sudah memiliki modul sendiri, tidak bisa definisi ulang.`)):(i=new k(u,!0,null),i.member=new s,this.environment.define(t,i));let a=this.environment;i.member.enclosing=this.environment,this.environment=i.member;for(let t of e.statements)t.accept(this);[this.environment,i.member]=[a,this.environment]}typeCheck(e,t,i){e.type!==t.type&&(console.log(e,t),this.error(`Tipe data tidak sama: ${e.type.description} != ${t.type.description}. `+i))}nullCheck(...e){for(let t of e)if(null===t.data||null===t.type)return t;return!1}validName(e,t=!0){return n.some(t=>t===e)?this.error(`Nama sistem (${e}) tidak boleh didefinisi ulang.`):t&&this.environment.has(e)&&this.error(`Variabel dengan nama '${e}' sudah ada. Tidak bisa didefinisi ulang.`),e}error(e){throw new t(`Error Eksekusi => ${e}`,this.line,this.output.join("\n"))}}class D{constructor(e,t,i,a){this.type=e,this.lexeme=t,this.value=i,this.line=a}toString(){return`< [${this.line}] ${C[this.type]}, ${this.lexeme} >`}}class F{constructor(){this.init()}init(){this.text=null,this.charStart=0,this.charIndex=0,this.lineIndex=1,this.tokens=[],this.errors=[]}scanTokens(e){this.init(),this.text=e;let t=[];for(;!this.isAtEnd();){let e=this.scan();this.charStart=this.charIndex,e&&t.push(e)}return t.push(new D(19,"Akhir dokumen",null,this.lineIndex)),this.tokens=t,this.tokens}isAtEnd(){return this.charIndex>=this.text.length}advance(){this.isAtEnd()||("\n"===this.see()&&this.lineIndex++,this.charIndex++)}see(){return this.isAtEnd()?"EOF":this.text[this.charIndex]}peek(e=1){return this.isAtEnd()?null:this.text[this.charIndex+e]}isAlpha(e){return/^[a-zA-Z_]$/.test(e)}isNumeric(e){return/^[0-9]$/.test(e)}isAlphaNumeric(e){return this.isAlpha(e)||this.isNumeric(e)||"?"===e}skipWhitespaces(){for(;!this.isAtEnd()&&/\s/.test(this.see());)this.advance(),this.charStart++}parseLexeme(){return this.text.slice(this.charStart,this.charIndex)}id(){for(;!this.isAtEnd()&&this.isAlphaNumeric(this.see());)this.advance();let e=this.parseLexeme(),t=L.findIndex(t=>t===e);return-1!=t?new D(t,e,null,this.lineIndex):["benar","salah"].some(t=>t===e)?new D(R,e,"benar"===e,this.lineIndex):new D("nihil"===e?R:$,e,null,this.lineIndex)}number(){let e=!1;for(;!this.isAtEnd()&&this.isNumeric(this.see());)if(this.advance(),"."===this.see()){if(e)break;e=!0,this.advance()}let t=parseFloat(e?this.parseLexeme():this.parseLexeme()+".");return new D(R,this.parseLexeme(),t,this.lineIndex)}string(){for(this.advance();!this.isAtEnd()&&'"'!==this.see();)this.advance();this.isAtEnd()&&this.error("Petik tidak tertutup."),this.advance();let e=this.parseLexeme();return new D(R,e,e.slice(1,e.length-1),this.lineIndex)}comment(){for(;!this.isAtEnd()&&"\n"!==this.see();)this.advance(),this.charStart++;this.advance(),this.charStart++}multilineComment(){for(this.advance(),this.advance(),this.charStart=this.charStart+2;!this.isAtEnd()&&("*"!==this.see()||"/"!==this.peek());)this.advance(),this.charStart++;this.advance(),this.advance(),this.charStart=this.charStart+2}makeToken(e){return this.advance(),new D(e,this.parseLexeme(),null,this.lineIndex)}scan(){for(this.skipWhitespaces();"#"===this.see()||"/"===this.see()&&"*"===this.peek();)"#"===this.see()?this.comment():this.multilineComment(),this.skipWhitespaces();if(this.isAlpha(this.see()))return this.id();if(this.isNumeric(this.see()))return this.number();switch(this.see()){case"$":return this.makeToken(48);case":":return this.makeToken(47);case"+":return this.makeToken(22);case"-":return this.makeToken(23);case"/":return this.makeToken(25);case"*":return this.makeToken(24);case"(":return this.makeToken(P);case")":return this.makeToken(_);case".":return this.makeToken(34);case",":return this.makeToken(B);case"{":return this.makeToken(35);case"}":return this.makeToken(36);case"[":return this.makeToken(38);case"]":return this.makeToken(39);case"|":return">"===this.peek()?(this.advance(),this.makeToken(46)):this.makeToken(40);case"&":return this.makeToken(41);case"%":return this.makeToken(45);case"!":return"="===this.peek()?(this.advance(),this.makeToken(44)):this.makeToken(42);case">":return"="===this.peek()?(this.advance(),this.makeToken(29)):this.makeToken(28);case"<":return"="===this.peek()?(this.advance(),this.makeToken(31)):this.makeToken(30);case"=":return"="===this.peek()&&">"===this.peek(2)?this.makeToken(32):"="===this.peek()?(this.advance(),this.makeToken(33)):">"===this.peek()?(this.advance(),this.makeToken(43)):this.makeToken(32);case'"':return this.string()}this.isAtEnd()||this.error(`karakter tidak valid: Menemukan '${this.see()}'.`)}error(e){throw new a("Error Tulisan => "+e,this.see().line)}debugPrintTokens(e){for(let t of e)console.log(t.toString())}}class J{accept(e){return this.visit(e)}}class W extends J{constructor(e,t,i){super(),this.left=e,this.op=t,this.right=i}visit(e){return e.visitBinaryExpr(this)}}class q extends J{constructor(e,t){super(),this.op=e,this.right=t}visit(e){return e.visitUnaryExpr(this)}}class V extends J{constructor(e){super(),this.token=e}visit(e){return e.visitLiteralExpr(this)}}class Z extends J{constructor(e){super(),this.expr=e}visit(e){return e.visitGroupingExpr(this)}}class z extends J{constructor(e,t){super(),this.main=e,this.member=t}visit(e){return e.visitMemberExpr(this)}}class X extends J{constructor(e){super(),this.token=e}visit(e){return e.visitIdentifierExpr(this)}}class Q extends J{constructor(e,t,i){super(),this.params=e,this.returnType=t,this.block=i}visit(e){return e.visitLambdaExpr(this)}}class Y extends J{constructor(e,t){super(),this.callable=e,this.args=t}visit(e){return e.visitCallExpr(this)}}let ee=class extends J{constructor(e){super(),this.contents=e}visit(e){return e.visitArrayExpr(this)}};class te extends J{constructor(e,t){super(),this.iterable=e,this.index=t}visit(e){return e.visitIndexExpr(this)}}class ie extends J{constructor(e,t){super(),this.expr=e,this.pipeTo=t}visit(e){return e.visitPipeLineExpr(this)}}class ae{accept(e){return this.visit(e)}}class se extends ae{constructor(e){super(),this.expr=e}visit(e){return e.visitCetakStmt(this)}}class ne extends ae{constructor(e,t,i){super(),this.type=e,this.name=t,this.expr=i}visit(e){return e.visitDatumStmt(this)}}class re extends ae{constructor(e,t,i){super(),this.type=e,this.tetap=t,this.contents=i}visit(e){return e.visitTypeStmt(this)}}class he extends ae{constructor(e){super(),this.expr=e}visit(e){return e.visitKerjaStmt(this)}}class le extends ae{constructor(e){super(),this.statements=e}visit(e){return e.visitBlockStmt(this)}}class me extends ae{constructor(e,t,i){super(),this.condition=e,this.thenBlock=t,this.elseKalau=i}visit(e){return e.visitKalauStmt(this)}}class oe extends ae{constructor(e,t,i,a){super(),this.varType=e,this.varName=t,this.iterable=i,this.block=a}visit(e){return e.visitUntukStmt(this)}}class de extends ae{constructor(e,t){super(),this.condition=e,this.block=t}visit(e){return e.visitSlagiStmt(this)}}class ue extends ae{constructor(){super()}visit(e){return e.visitHentiStmt(this)}}class ce extends ae{constructor(){super()}visit(e){return e.visitLewatStmt(this)}}class pe extends ae{constructor(){super()}visit(e){return e.visitJatuhStmt(this)}}class ke extends ae{constructor(e,t){super(),this.variable=e,this.value=t}visit(e){return e.visitRubahStmt(this)}}class be extends ae{constructor(e){super(),this.expr=e}visit(e){return e.visitHasilStmt(this)}}class fe extends ae{constructor(e,t){super(),this.name=e,this.enums=t}visit(e){return e.visitJenisStmt(this)}}class we extends ae{constructor(e,t){super(),this.expr=e,this.cases=t}visit(e){return e.visitLihatStmt(this)}}class ve extends ae{constructor(e,t){super(),this.name=e,this.contents=t}visit(e){return e.visitModelStmt(this)}}let Se=class extends ae{constructor(e){super(),this.statements=e}visit(e){return e.visitSimplStmt(this)}};class ge extends ae{constructor(e,t){super(),this.name=e,this.statements=t}visit(e){return e.visitModulStmt(this)}}class ye{constructor(){this.init()}init(){this.tokens=[],this.tokenIndex=0,this.tree=null}parse(e){this.init(),this.tokens=e;let t=[];for(;!this.match(19);)t.push(this.statement());return this.tree=new Se(t),this.tree}see(){return this.tokens[this.tokenIndex]}peek(){return this.tokenIndex+1>=this.tokens.length?null:this.tokens[this.tokenIndex+1]}check(e){return this.tokens[this.tokenIndex].type===e}isAtEnd(){return this.tokenIndex>=this.tokens.length}match(...e){if(this.isAtEnd())return!1;for(let t of e)if(this.check(t))return this.tokenIndex++,!0;return!1}eat(e,t){this.match(e)||this.error(t)}previous(){return this.tokens[this.tokenIndex-1]}blockStmt(){if(this.match(47))return new le([this.statement()]);this.eat(35,"Mengharapkan sebuah blok.");let e=[];for(;!this.match(36);)e.push(this.statement());return new le(e)}functionCallExpr(e){let t=[];if(this.check(_));else do{let e=this.expression();t.push(e)}while(this.match(B));return this.eat(_,"Mengharapkan ')' setelah penggunaan mesin."),new Y(e,t)}lambda(){let e=[];if(this.eat(P,"Mengharapkan '(' setelah '=>' untuk deklarasi objek `mesin`."),this.match($,U)){let t=this.typeStmt();this.eat($,"Mengharapkan Nama parameter setelah deklarasi Tipe parameter dalam objek `mesin`.");let i=this.previous();for(e.push([t,i]);this.match(B);){this.match($,U)||this.error("Mengharapkan Tipe parameter setelah koma dalam objek `mesin`.");let t=this.typeStmt();this.eat($,"Mengharapkan Nama parameter setelah deklarasi Tipe parameter dalam objek `mesin`.");let i=this.previous();e.push([t,i])}}this.eat(_,"Mengharapkan ')' setelah deklarasi parameter objek `mesin`.");let t=null;this.match($,U)&&(t=this.typeStmt()),this.match(R)&&(null!==this.previous().value&&this.error("Mengharapkan Tipe Hasil yang valid."),t=null);let i=this.blockStmt();return new Q(e,t,i)}arrayExpr(){if(this.match(39))return new ee([]);let e=[];do{if(this.check(39))break;let t=this.expression();e.push(t)}while(this.match(B));return this.eat(39,"Mengharapkan ']' untuk menutup 'baris'."),new ee(e)}arrayIndex(e){let t=this.expression();return this.eat(39,"Mengharapkan ']' untuk menutup indeks."),new te(e,t)}primary(){if(this.match(P)){let e=this.expression();return this.eat(_,"Mengharapkan ')' untuk mengakhiri ekspresi kurung"),new Z(e)}return this.match(R)?new V(this.previous()):this.match($,48)?this.identifier():this.match(43)?this.lambda():this.match(38)?this.arrayExpr():void this.error("Mengharapkan Ekspresi valid.")}valuable(){let e=this.primary();for(;;)if(this.match(P))e=this.functionCallExpr(e);else if(this.match(38))e=this.arrayIndex(e);else{if(!this.match(34))break;e=this.member(e)}return e}unary(){if(this.match(22,23,42)){let e=this.previous(),t=this.unary();return new q(e,t)}return this.valuable()}identifier(){return new X(this.previous())}member(e){this.eat($,"Mengharapkan Nama variabel setelah '.'.");let t=this.identifier();return new z(e,t)}factor(){let e=this.unary();for(;this.match(45,24,25);){let t=this.previous(),i=this.unary();e=new W(e,t,i)}return e}term(){let e=this.factor();for(;this.match(22,23);){let t=this.previous(),i=this.factor();e=new W(e,t,i)}return e}equality(){let e=this.term();if(this.match(28,29,30,31,33,44)){let t=this.previous(),i=this.term();e=new W(e,t,i)}return e}andTerm(){let e=this.equality();for(;this.match(41);){let t=this.previous(),i=this.equality();e=new W(e,t,i)}return e}orTerm(){let e=this.andTerm();for(;this.match(40);){let t=this.previous(),i=this.andTerm();e=new W(e,t,i)}return e}pipeLine(){let e=this.orTerm();for(;this.match(46);){let t=this.orTerm();e=new ie(e,t)}return e}expression(){return this.pipeLine()}cetakStmt(){let e=this.expression();return new se(e)}typeStmt(){if(this.previous().type===U){let e=!1;return this.match(14)&&(e=!0),new re(null,e,null)}let e=this.identifier(),t=!1;return this.match(14)&&(t=!0),new re(e,t,null)}datumStmt(){let e=this.typeStmt();this.eat($,"Mengharapkan Nama setelah Tipe pada deklarasi variabel.");let t=this.previous();this.eat(32,"Mengharapkan '=' setelah Nama variabel.");let i=this.expression();return new ne(e,t,i)}kalauStmt(){this.check(35)&&this.error("Mengharapkan ekspresi setelah 'kalau'.");let e=this.expression(),t=this.blockStmt(),i=null;if(this.match(2))if(this.match(1))i=this.kalauStmt();else{let e=null,t=this.blockStmt();i=new me(e,t)}return new me(e,t,i)}untukStmt(){this.match($,U)||this.error("Mengharapkan Tipe variabel untuk diinisialisasi setelah 'untuk'.");let e=this.typeStmt();this.eat($,"Mengharapkan Nama variabel setelah Tipe dalam pernyataan 'untuk'.");let t=this.previous();this.eat(8,"Mengharapkan 'dalam' setelah deklarasi variabel pada pernyataan 'untuk'.");let i=this.expression(),a=this.blockStmt();return new oe(e,t,i,a)}slagiStmt(){let e=this.expression(),t=this.blockStmt();return new de(e,t)}rubahStmt(){let e=this.valuable(),t=null;this.match(22,23,24,25,41,40,45)&&(t=new W(e,this.previous(),null)),this.eat(32,"Mengharapkan '=' setelah variable yang ingin di-'rubah'.");let i=this.expression();return t&&(t.right=i,i=t),new ke(e,i)}jenisStmt(){this.eat($,"Mengharapkan Nama Jenis setelah 'jenis'.");let e=this.previous();this.eat(P,"Mengharapkan '(' setelah deklarasi Nama Jenis."),this.check(_)&&this.error("Isian Jenis tidak boleh kosong.",!1);let t=[];do{this.eat($,"Mengharapkan macam jenis dalam 'jenis'.");let e=this.previous();t.push(e)}while(this.match(B));return this.eat(_,"Mengharapkan ')' untuk mengakhiri deklarasi 'jenis'."),new fe(e,t)}lihatStmt(){let e=this.expression(),t=[];for(this.check(17)||this.error("Mengharapkan `kasus` setelah ekspresi dalam `lihat`.");this.match(17);)t.push([this.expression(),this.blockStmt()]);return this.match(2)&&t.push([null,this.blockStmt()]),new we(e,t)}modelStmt(){this.eat($,"Mengharapkan Nama Model setelah 'model'.");let e=this.previous();this.eat(P,"Mengharapkan '(' setelah Nama Model dalam 'model'."),this.check(_)&&this.error("Model tidak boleh tanpa isian.",!1);let t=[];do{this.match($,U)||this.error("Mengharapkan Tipe variabel dalam deklarasi 'Model'.");let e=this.typeStmt();this.eat($,"Mengharapkan Nama variabel dalam deklarasi 'model'.");let i=this.previous();t.push([e,i])}while(this.match(B));return this.eat(_,"Mengharapkan ')' untuk mengakhiri deklarasi 'model'."),new ve(e,t)}modulStmt(){this.eat($,"Mengharapkan Nama modul setelah deklarasi.");let e=this.previous(),t=this.blockStmt();return new ge(e,t.statements)}statement(){return this.match(5)?this.cetakStmt():this.match($,U)?this.datumStmt():this.match(10)?new he(this.expression()):this.match(1)?this.kalauStmt():this.check(35)?this.blockStmt():this.match(4)?this.untukStmt():this.match(3)?this.slagiStmt():this.match(6)?new ue:this.match(7)?new ce:this.match(18)?new pe:this.match(0)?this.rubahStmt():this.match(9)?new be(this.expression()):this.match(12)?this.jenisStmt():this.match(16)?this.lihatStmt():this.match(13)?this.modelStmt():this.match(15)?this.modulStmt():void this.error(`Pernyataan tidak bisa diawali '${this.see().lexeme}'.`,!1)}error(e,t=!0){throw new i("Error Struktur => "+e+(t?` Menemukan '${this.see().lexeme}'.`:""),this.see().line)}}class Ae{constructor(e={keepMemory:!1}){this.lexer=new F,this.parser=new ye,this.interpreter=new O,this.keepMemory=!!e?.keepMemory&&e.keepMemory}runCode(i){this.keepMemory||this.interpreter.init();const a=i.split("\n");try{let e=this.lexer.scanTokens(i),t=this.parser.parse(e);return this.interpreter.interpret(t).join("\n")}catch(i){if(i instanceof e){const e=a[i.line-1];let s=(e?`ERROR! Pada baris ke-${i.line}\n>> `+e+"\n":"")+i.message;return i instanceof t&&(s+=(i.output?"\nOutput dari kode:\n":"")+i.output),s}return`[Pada baris ke-${this.interpreter.line}] Uh Oh, ini error sistem. Mohon laporkan agar diperbaiki. [ ${i} ]`}}}export{Ae as Simpl};
|
package/package.json
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bahasa-simpl",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.13",
|
|
4
4
|
"description": "Simpl: Indonesian Mini Programming Language interpreter",
|
|
5
|
-
"
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"types": "./dist/simpl.d.ts",
|
|
8
|
+
"import": "./dist/simpl.js"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"main": "./dist/simpl.js",
|
|
12
|
+
"module": "./dist/simpl.js",
|
|
13
|
+
"types": "./dist/simpl.js",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
6
17
|
"scripts": {
|
|
7
18
|
"build": "rollup -c"
|
|
8
19
|
},
|
|
@@ -19,7 +30,8 @@
|
|
|
19
30
|
},
|
|
20
31
|
"homepage": "https://github.com/faeiz-ff/simpl#readme",
|
|
21
32
|
"devDependencies": {
|
|
22
|
-
"rollup": "^4.
|
|
33
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
34
|
+
"rollup": "^4.55.1"
|
|
23
35
|
},
|
|
24
36
|
"dependencies": {
|
|
25
37
|
"bahasa-simpl": "^1.0.3"
|