bahasa-simpl 1.0.7 → 1.0.9
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/README.md +2 -3
- package/dist/simpl-interpreter.js +107 -71
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,6 @@ Berikut fitur yang _sekarang_ sudah diimplementasikan:
|
|
|
16
16
|
- **Semua** kata kunci berjumlah 5 huruf dan dalam bahasa Indonesia
|
|
17
17
|
|
|
18
18
|
Fitur yang akan datang:
|
|
19
|
-
- Website untuk menjalankan `simpl`
|
|
20
19
|
- dokumentasi penuh
|
|
21
20
|
- Pembersihan dan perapihan kode sumber :')
|
|
22
21
|
- Pengecekan sebelum eksekusi (Analisa semantik)
|
|
@@ -114,7 +113,7 @@ Pengguna lain = Pengguna.baru("Hengker Anongnimus")
|
|
|
114
113
|
cetak Pengguna.kepetik(admin)
|
|
115
114
|
# "{ nama: zie, id: 0, status: online }"
|
|
116
115
|
|
|
117
|
-
cetak
|
|
116
|
+
cetak lain.kePetik()
|
|
118
117
|
# "{ nama: Hengker Anongnimus, id: 1, status: online }"
|
|
119
118
|
```
|
|
120
119
|
|
|
@@ -124,4 +123,4 @@ cetak Pengguna.kePetik(lain)
|
|
|
124
123
|
- [https://ruslanspivak.com/lsbasi-part1/](https://ruslanspivak.com/lsbasi-part1/)
|
|
125
124
|
- [https://craftinginterpreters.com/](https://craftinginterpreters.com/)
|
|
126
125
|
|
|
127
|
-
|
|
126
|
+
|
|
@@ -88,36 +88,38 @@ class Stipe extends Variable {
|
|
|
88
88
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
function kePetik(v, thing) {
|
|
92
|
+
if (thing.type === logisSymbol) {
|
|
93
|
+
return thing.data ? "benar" : "salah";
|
|
94
|
+
} else if (thing.type === barisSymbol) {
|
|
95
|
+
return '[' + thing.data.reduce((str, val) => {
|
|
96
|
+
let item = kePetik(v, val);
|
|
97
|
+
return str + ", " + (val.type === Value.petikSymbol ? `"${item}"` : item);
|
|
98
|
+
}, "").slice(1) + ' ]';
|
|
99
|
+
} else if (thing.type === stipeSymbol) {
|
|
100
|
+
return `Model<${thing.symbol.description}>`;
|
|
101
|
+
} else if (thing.type === mesinSymbol) {
|
|
102
|
+
let underlying = thing.data.returnType?.description;
|
|
103
|
+
return `Mesin<${underlying ? underlying : 'datum'}>`;
|
|
104
|
+
} else if (thing.type === angkaSymbol) {
|
|
105
|
+
return thing.data.toString();
|
|
106
|
+
} else if (thing.type === petikSymbol) {
|
|
107
|
+
return '"' + thing.data + '"';
|
|
108
|
+
} else {
|
|
109
|
+
if (!thing?.type) return `nihil`;
|
|
110
|
+
let type = v.environment.get(thing.type.description);
|
|
111
|
+
if (type?.member.has("kePetik")) {
|
|
112
|
+
let res = v.callFunc(type.member.get("kePetik").data, [thing]).data;
|
|
113
|
+
return res;
|
|
114
|
+
}
|
|
115
|
+
return `${thing.type.description}<>`;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
91
119
|
class PetikTipe extends Stipe {
|
|
92
120
|
constructor() {
|
|
93
|
-
super(petikSymbol, new Callable(null, (v, args) =>
|
|
94
|
-
|
|
95
|
-
if (thing.type === logisSymbol) {
|
|
96
|
-
return thing.data ? "benar" : "salah";
|
|
97
|
-
} else if (thing.type === barisSymbol) {
|
|
98
|
-
return '[' + thing.data.reduce((str, val) => str + ", " + kePetik(val), "").slice(1) + ' ]';
|
|
99
|
-
} else if (thing.type === stipeSymbol) {
|
|
100
|
-
return `Model<${thing.symbol.description}>`;
|
|
101
|
-
} else if (thing.type === mesinSymbol) {
|
|
102
|
-
let underlying = thing.data.returnType?.description;
|
|
103
|
-
return `Mesin<${underlying ? underlying : 'datum'}>`;
|
|
104
|
-
} else if (thing.type === angkaSymbol) {
|
|
105
|
-
return thing.data.toString();
|
|
106
|
-
} else if (thing.type === petikSymbol) {
|
|
107
|
-
return '"' + thing.data + '"';
|
|
108
|
-
} else {
|
|
109
|
-
if (!thing?.type) return `nihil`;
|
|
110
|
-
let type = v.environment.get(thing.type.description);
|
|
111
|
-
if (type?.member.has("kePetik")) {
|
|
112
|
-
let res = v.callFunc(type.member.get("kePetik").data, [thing]).data;
|
|
113
|
-
return res;
|
|
114
|
-
}
|
|
115
|
-
return `${thing.type.description}<>`;
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
return new Value(petikSymbol, kePetik(args[0]));
|
|
119
|
-
}, [[null]], petikSymbol, true)
|
|
120
|
-
);
|
|
121
|
+
super(petikSymbol, new Callable(null, (v, args) => new Value(petikSymbol, kePetik(v, args[0])),
|
|
122
|
+
[[null]], petikSymbol, true) );
|
|
121
123
|
this.init();
|
|
122
124
|
}
|
|
123
125
|
|
|
@@ -145,6 +147,9 @@ class PetikTipe extends Stipe {
|
|
|
145
147
|
this.member.define("SERU_UNER",
|
|
146
148
|
makeBuiltInFunc([petikSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
147
149
|
|
|
150
|
+
this.member.define("kePetik",
|
|
151
|
+
makeBuiltInFunc([petikSymbol], petikSymbol, (v, [p]) => new Value(petikSymbol, kePetik(v, p))));
|
|
152
|
+
|
|
148
153
|
this.member.define("pisah", makeBuiltInFunc([petikSymbol, petikSymbol], barisSymbol, (_, [d, sep]) => {
|
|
149
154
|
return new Value(barisSymbol, d.data.split(sep.data).map(val => new Value(petikSymbol, val)));
|
|
150
155
|
}));
|
|
@@ -224,6 +229,9 @@ class AngkaTipe extends Stipe {
|
|
|
224
229
|
this.member.define("MINUS_UNER",
|
|
225
230
|
makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [r]) => new Value(angkaSymbol, -r.data)));
|
|
226
231
|
|
|
232
|
+
this.member.define("kePetik",
|
|
233
|
+
makeBuiltInFunc([angkaSymbol], petikSymbol, (v, [a]) => new Value(petikSymbol, kePetik(v, a))));
|
|
234
|
+
|
|
227
235
|
this.member.define("bulat", makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [a]) => {
|
|
228
236
|
return new Value(angkaSymbol, Math.round(a.data));
|
|
229
237
|
}));
|
|
@@ -259,6 +267,9 @@ class LogisTipe extends Stipe {
|
|
|
259
267
|
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data || r.data)));
|
|
260
268
|
this.member.define("SERU_UNER",
|
|
261
269
|
makeBuiltInFunc([logisSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
270
|
+
|
|
271
|
+
this.member.define("kePetik",
|
|
272
|
+
makeBuiltInFunc([logisSymbol], petikSymbol, (v, [l]) => new Value(petikSymbol, kePetik(v, l))));
|
|
262
273
|
}
|
|
263
274
|
}
|
|
264
275
|
|
|
@@ -269,6 +280,13 @@ class BarisTipe extends Stipe {
|
|
|
269
280
|
}
|
|
270
281
|
|
|
271
282
|
init() {
|
|
283
|
+
const valueToVariableDatum = (d) => {
|
|
284
|
+
let input = new Variable(d.type, false, d.data);
|
|
285
|
+
input.member = d.member;
|
|
286
|
+
input.isDatum = true;
|
|
287
|
+
return input;
|
|
288
|
+
};
|
|
289
|
+
|
|
272
290
|
this.member.define("PLUS",
|
|
273
291
|
makeBuiltInFunc([barisSymbol, barisSymbol], barisSymbol, (_, [r, l]) =>
|
|
274
292
|
new Value(barisSymbol, Array(...l.data, ...r.data))
|
|
@@ -306,6 +324,9 @@ class BarisTipe extends Stipe {
|
|
|
306
324
|
this.member.define("SERU_UNER",
|
|
307
325
|
makeBuiltInFunc([barisSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
308
326
|
|
|
327
|
+
this.member.define("kePetik",
|
|
328
|
+
makeBuiltInFunc([barisSymbol], petikSymbol, (v, [p]) => new Value(petikSymbol, kePetik(v, p))));
|
|
329
|
+
|
|
309
330
|
this.member.define("hapus", makeBuiltInFunc([barisSymbol, angkaSymbol], barisSymbol, (v, [b, i]) => {
|
|
310
331
|
if (b.data.length <= i.data) {
|
|
311
332
|
v.error(`Indeks tidak boleh lebih besar atau sama dengan ukuran baris, ${i.data} >= ${b.data.length}`);
|
|
@@ -318,12 +339,12 @@ class BarisTipe extends Stipe {
|
|
|
318
339
|
|
|
319
340
|
this.member.define("potongan", makeBuiltInFunc([barisSymbol, angkaSymbol, angkaSymbol], barisSymbol, (v, [b, fr, to]) => {
|
|
320
341
|
if (fr.data >= b.data.length || fr.data < 0 || to.data <= fr.data || to.data > b.data.length) {
|
|
321
|
-
v.error(`Indeks tidak valid, ${fr.data}
|
|
342
|
+
v.error(`Indeks tidak valid, ${fr.data} sampai ${to.data}, dengan ukuran baris ${b.data.length}`);
|
|
322
343
|
}
|
|
323
344
|
return new Value(barisSymbol, b.data.slice(fr.data, to.data));
|
|
324
345
|
}));
|
|
325
346
|
this.member.define("tumpuk", makeBuiltInFunc([barisSymbol, null], null, (_, [b, d]) => {
|
|
326
|
-
b.data.push(d);
|
|
347
|
+
b.data.push(valueToVariableDatum(d));
|
|
327
348
|
return b;
|
|
328
349
|
}));
|
|
329
350
|
this.member.define("tumpah", makeBuiltInFunc([barisSymbol], null, (_, [b]) => {
|
|
@@ -334,14 +355,14 @@ class BarisTipe extends Stipe {
|
|
|
334
355
|
if (idx.data > b.data.length) {
|
|
335
356
|
v.error(`Indeks tidak valid, ${idx.data}, dengan ukuran baris ${b.data.length}`);
|
|
336
357
|
}
|
|
337
|
-
b.data.splice(idx.data, 0, d);
|
|
358
|
+
b.data.splice(idx.data, 0, valueToVariableDatum(d));
|
|
338
359
|
return b;
|
|
339
360
|
}));
|
|
340
361
|
this.member.define("petakan", makeBuiltInFunc([barisSymbol, mesinSymbol], barisSymbol, (v, [b, m]) => {
|
|
341
362
|
let newBaris = new Value(barisSymbol, []);
|
|
342
363
|
for (let datum of b.data) {
|
|
343
364
|
let result = v.callFunc(m.data, [datum]);
|
|
344
|
-
newBaris.data.push(result);
|
|
365
|
+
newBaris.data.push(valueToVariableDatum(result));
|
|
345
366
|
}
|
|
346
367
|
return newBaris;
|
|
347
368
|
}));
|
|
@@ -350,7 +371,7 @@ class BarisTipe extends Stipe {
|
|
|
350
371
|
for (let datum of b.data) {
|
|
351
372
|
let result = v.callFunc(m.data, [datum]);
|
|
352
373
|
if (result.data === true) {
|
|
353
|
-
newBaris.data.push(datum);
|
|
374
|
+
newBaris.data.push(valueToVariableDatum(datum));
|
|
354
375
|
}
|
|
355
376
|
}
|
|
356
377
|
return newBaris;
|
|
@@ -362,13 +383,33 @@ class BarisTipe extends Stipe {
|
|
|
362
383
|
}
|
|
363
384
|
return d;
|
|
364
385
|
}));
|
|
386
|
+
|
|
387
|
+
this.member.define("punya?", makeBuiltInFunc([barisSymbol, null], logisSymbol, (v, [b, d]) => {
|
|
388
|
+
let type = v.environment.get(d.type?.description);
|
|
389
|
+
if (!type)
|
|
390
|
+
v.error(`Tipe tidak ditemukan atau tidak valid`);
|
|
391
|
+
let equalFunc;
|
|
392
|
+
if (type.member?.has("SAMA_SAMA")) {
|
|
393
|
+
equalFunc = type.member.get("SAMA_SAMA");
|
|
394
|
+
} else {
|
|
395
|
+
v.error(`model ${d.type.description} tidak mempunyai mesin SAMA_SAMA di dalam modulnya.`);
|
|
396
|
+
}
|
|
397
|
+
for (let datum of b.data) {
|
|
398
|
+
if (datum.type !== d.type) continue;
|
|
399
|
+
let isEqual = v.callFunc(equalFunc.data, [datum, d]);
|
|
400
|
+
if (isEqual.data) return new Value(logisSymbol, true);
|
|
401
|
+
}
|
|
402
|
+
return new Value(logisSymbol, false);
|
|
403
|
+
}));
|
|
365
404
|
}
|
|
366
405
|
}
|
|
367
406
|
|
|
368
407
|
class MesinTipe extends Stipe {
|
|
369
408
|
constructor() {
|
|
370
409
|
super(mesinSymbol);
|
|
371
|
-
|
|
410
|
+
|
|
411
|
+
this.member.define("kePetik",
|
|
412
|
+
makeBuiltInFunc([mesinSymbol], petikSymbol, (v, [m]) => new Value(petikSymbol, kePetik(v, m))));
|
|
372
413
|
}
|
|
373
414
|
}
|
|
374
415
|
|
|
@@ -413,8 +454,7 @@ let Jenis$1 = class Jenis extends Stipe {
|
|
|
413
454
|
this.member.define(thing.lexeme, new Value(sym, idx));
|
|
414
455
|
});
|
|
415
456
|
this.member.define("kePetik", makeBuiltInFunc([sym], petikSymbol, (_, [j]) => {
|
|
416
|
-
|
|
417
|
-
return new Value(petikSymbol, `${name}.${enumName}`);
|
|
457
|
+
return new Value(petikSymbol, `${name}<${j.data}>`);
|
|
418
458
|
}));
|
|
419
459
|
this.init(sym);
|
|
420
460
|
}
|
|
@@ -449,7 +489,12 @@ function copier(thing) {
|
|
|
449
489
|
case angkaSymbol: return new Value(angkaSymbol, thing.data);
|
|
450
490
|
case logisSymbol: return new Value(logisSymbol, thing.data);
|
|
451
491
|
case mesinSymbol: return new Value(mesinSymbol, thing.data);
|
|
452
|
-
case barisSymbol: return new Value(barisSymbol, thing.data.map((val) =>
|
|
492
|
+
case barisSymbol: return new Value(barisSymbol, thing.data.map((val) => {
|
|
493
|
+
let copy = copier(val);
|
|
494
|
+
let varCopy = new Variable(copy.type, false, copy.data);
|
|
495
|
+
varCopy.member = copy.member;
|
|
496
|
+
return varCopy
|
|
497
|
+
}));
|
|
453
498
|
case stipeSymbol: return NIHIL;
|
|
454
499
|
case modulSymbol: return NIHIL;
|
|
455
500
|
default:
|
|
@@ -458,13 +503,17 @@ function copier(thing) {
|
|
|
458
503
|
let valCopy = new Value(thing.type, null);
|
|
459
504
|
let newMember = new Environment();
|
|
460
505
|
for (let i of keys) {
|
|
461
|
-
|
|
506
|
+
let varPrev = thing.member.get(i);
|
|
507
|
+
let tempCopy = copier(varPrev);
|
|
508
|
+
let varCopy = new Variable(varPrev.type, varPrev.tetap, tempCopy.data);
|
|
509
|
+
varCopy.member = tempCopy.member;
|
|
510
|
+
newMember.define(i, varCopy);
|
|
462
511
|
}
|
|
463
512
|
valCopy.member = newMember;
|
|
464
|
-
|
|
513
|
+
valCopy.data = thing.data;
|
|
465
514
|
return valCopy;
|
|
466
515
|
}
|
|
467
|
-
return
|
|
516
|
+
return new Value(thing.type, thing.data);
|
|
468
517
|
}
|
|
469
518
|
}
|
|
470
519
|
|
|
@@ -949,35 +998,7 @@ class Interpreter {
|
|
|
949
998
|
|
|
950
999
|
visitCetakStmt(cetakStmt) {
|
|
951
1000
|
let result = cetakStmt.expr.accept(this);
|
|
952
|
-
|
|
953
|
-
if (thing.type === logisSymbol) {
|
|
954
|
-
return thing.data ? "benar" : "salah";
|
|
955
|
-
} else if (thing.type === barisSymbol) {
|
|
956
|
-
return '[' + thing.data.reduce((str, val) => {
|
|
957
|
-
let item = kePetik(val);
|
|
958
|
-
return str + ", " + (val.type === petikSymbol ? `"${item}"` : item);
|
|
959
|
-
}, "").slice(1) + ' ]';
|
|
960
|
-
} else if (thing.type === stipeSymbol) {
|
|
961
|
-
return `Model<${thing.symbol.description}>`;
|
|
962
|
-
} else if (thing.type === mesinSymbol) {
|
|
963
|
-
let underlying = thing.data.returnType?.description;
|
|
964
|
-
return `Mesin<${underlying ? underlying : 'datum'}>`;
|
|
965
|
-
} else if (thing.type === angkaSymbol) {
|
|
966
|
-
return thing.data.toString();
|
|
967
|
-
} else if (thing.type === petikSymbol) {
|
|
968
|
-
return thing.data;
|
|
969
|
-
} else {
|
|
970
|
-
if (!thing?.type) return `nihil`;
|
|
971
|
-
let type = this.environment.get(thing.type.description);
|
|
972
|
-
if (type?.member?.has("kePetik")) {
|
|
973
|
-
let res = this.callFunc(type.member.get("kePetik").data, [thing]).data;
|
|
974
|
-
return res;
|
|
975
|
-
}
|
|
976
|
-
return `${thing.type.description}<>`;
|
|
977
|
-
}
|
|
978
|
-
};
|
|
979
|
-
|
|
980
|
-
this.output.push(kePetik(result));
|
|
1001
|
+
this.output.push(kePetik(this, result));
|
|
981
1002
|
|
|
982
1003
|
}
|
|
983
1004
|
|
|
@@ -1009,6 +1030,9 @@ class Interpreter {
|
|
|
1009
1030
|
|
|
1010
1031
|
visitRubahStmt(rubahStmt) {
|
|
1011
1032
|
let variable = rubahStmt.variable.accept(this); // is a reference to the variable data
|
|
1033
|
+
if (variable.tetap === undefined) {
|
|
1034
|
+
this.error(`Pe-rubah-an hanya dapat dilakukan kepada Variabel!`);
|
|
1035
|
+
}
|
|
1012
1036
|
if (variable.tetap) {
|
|
1013
1037
|
this.error(`Variabel tetap tidak dapat di-rubah.`);
|
|
1014
1038
|
}
|
|
@@ -1379,6 +1403,17 @@ class Lexer {
|
|
|
1379
1403
|
this.charStart++;
|
|
1380
1404
|
}
|
|
1381
1405
|
|
|
1406
|
+
multilineComment() {
|
|
1407
|
+
this.advance(); this.advance();
|
|
1408
|
+
this.charStart = this.charStart + 2;
|
|
1409
|
+
while (!this.isAtEnd() && (this.see() !== '*' || this.peek() !== '/')) {
|
|
1410
|
+
this.advance();
|
|
1411
|
+
this.charStart++;
|
|
1412
|
+
}
|
|
1413
|
+
this.advance(); this.advance();
|
|
1414
|
+
this.charStart = this.charStart + 2;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1382
1417
|
makeToken(type) {
|
|
1383
1418
|
this.advance();
|
|
1384
1419
|
return new Token(type, this.parseLexeme(), null, this.lineIndex);
|
|
@@ -1386,8 +1421,9 @@ class Lexer {
|
|
|
1386
1421
|
|
|
1387
1422
|
scan() {
|
|
1388
1423
|
this.skipWhitespaces();
|
|
1389
|
-
while (this.see() === '#') {
|
|
1390
|
-
this.comment();
|
|
1424
|
+
while (this.see() === '#' || (this.see() === '/' && this.peek() === '*')) {
|
|
1425
|
+
if (this.see() === '#') this.comment();
|
|
1426
|
+
else this.multilineComment();
|
|
1391
1427
|
this.skipWhitespaces();
|
|
1392
1428
|
}
|
|
1393
1429
|
|