bahasa-simpl 1.0.6 → 1.0.8
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 +103 -76
- 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,38 +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
|
-
v.stack.push(v.line);
|
|
113
|
-
let res = v.callFunc(type.member.get("kePetik").data, [thing]).data;
|
|
114
|
-
v.stack.pop();
|
|
115
|
-
return res;
|
|
116
|
-
}
|
|
117
|
-
return `${thing.type.description}<>`;
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
return new Value(petikSymbol, kePetik(args[0]));
|
|
121
|
-
}, [[null]], petikSymbol, true)
|
|
122
|
-
);
|
|
121
|
+
super(petikSymbol, new Callable(null, (v, args) => new Value(petikSymbol, kePetik(v, args[0])),
|
|
122
|
+
[[null]], petikSymbol, true) );
|
|
123
123
|
this.init();
|
|
124
124
|
}
|
|
125
125
|
|
|
@@ -147,6 +147,9 @@ class PetikTipe extends Stipe {
|
|
|
147
147
|
this.member.define("SERU_UNER",
|
|
148
148
|
makeBuiltInFunc([petikSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
149
149
|
|
|
150
|
+
this.member.define("kePetik",
|
|
151
|
+
makeBuiltInFunc([petikSymbol], petikSymbol, (v, [p]) => new Value(petikSymbol, kePetik(v, p))));
|
|
152
|
+
|
|
150
153
|
this.member.define("pisah", makeBuiltInFunc([petikSymbol, petikSymbol], barisSymbol, (_, [d, sep]) => {
|
|
151
154
|
return new Value(barisSymbol, d.data.split(sep.data).map(val => new Value(petikSymbol, val)));
|
|
152
155
|
}));
|
|
@@ -226,6 +229,9 @@ class AngkaTipe extends Stipe {
|
|
|
226
229
|
this.member.define("MINUS_UNER",
|
|
227
230
|
makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [r]) => new Value(angkaSymbol, -r.data)));
|
|
228
231
|
|
|
232
|
+
this.member.define("kePetik",
|
|
233
|
+
makeBuiltInFunc([angkaSymbol], petikSymbol, (v, [a]) => new Value(petikSymbol, kePetik(v, a))));
|
|
234
|
+
|
|
229
235
|
this.member.define("bulat", makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [a]) => {
|
|
230
236
|
return new Value(angkaSymbol, Math.round(a.data));
|
|
231
237
|
}));
|
|
@@ -241,7 +247,10 @@ class AngkaTipe extends Stipe {
|
|
|
241
247
|
class LogisTipe extends Stipe {
|
|
242
248
|
constructor() {
|
|
243
249
|
super(logisSymbol, new Callable(null, (_, args) => {
|
|
244
|
-
|
|
250
|
+
if (args[0].type === barisSymbol && args[0].data.length === 0) {
|
|
251
|
+
return new Value(logisSymbol, false);
|
|
252
|
+
}
|
|
253
|
+
return new Value(logisSymbol, Boolean(args[0].data) || Boolean(args[0].data?.member?.size));
|
|
245
254
|
}, [[null]], logisSymbol, true)
|
|
246
255
|
);
|
|
247
256
|
this.init();
|
|
@@ -258,6 +267,9 @@ class LogisTipe extends Stipe {
|
|
|
258
267
|
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data || r.data)));
|
|
259
268
|
this.member.define("SERU_UNER",
|
|
260
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))));
|
|
261
273
|
}
|
|
262
274
|
}
|
|
263
275
|
|
|
@@ -268,6 +280,13 @@ class BarisTipe extends Stipe {
|
|
|
268
280
|
}
|
|
269
281
|
|
|
270
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
|
+
|
|
271
290
|
this.member.define("PLUS",
|
|
272
291
|
makeBuiltInFunc([barisSymbol, barisSymbol], barisSymbol, (_, [r, l]) =>
|
|
273
292
|
new Value(barisSymbol, Array(...l.data, ...r.data))
|
|
@@ -305,6 +324,9 @@ class BarisTipe extends Stipe {
|
|
|
305
324
|
this.member.define("SERU_UNER",
|
|
306
325
|
makeBuiltInFunc([barisSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
307
326
|
|
|
327
|
+
this.member.define("kePetik",
|
|
328
|
+
makeBuiltInFunc([barisSymbol], petikSymbol, (v, [p]) => new Value(petikSymbol, kePetik(v, p))));
|
|
329
|
+
|
|
308
330
|
this.member.define("hapus", makeBuiltInFunc([barisSymbol, angkaSymbol], barisSymbol, (v, [b, i]) => {
|
|
309
331
|
if (b.data.length <= i.data) {
|
|
310
332
|
v.error(`Indeks tidak boleh lebih besar atau sama dengan ukuran baris, ${i.data} >= ${b.data.length}`);
|
|
@@ -317,12 +339,12 @@ class BarisTipe extends Stipe {
|
|
|
317
339
|
|
|
318
340
|
this.member.define("potongan", makeBuiltInFunc([barisSymbol, angkaSymbol, angkaSymbol], barisSymbol, (v, [b, fr, to]) => {
|
|
319
341
|
if (fr.data >= b.data.length || fr.data < 0 || to.data <= fr.data || to.data > b.data.length) {
|
|
320
|
-
v.error(`Indeks tidak valid, ${fr.data}
|
|
342
|
+
v.error(`Indeks tidak valid, ${fr.data} sampai ${to.data}, dengan ukuran baris ${b.data.length}`);
|
|
321
343
|
}
|
|
322
344
|
return new Value(barisSymbol, b.data.slice(fr.data, to.data));
|
|
323
345
|
}));
|
|
324
346
|
this.member.define("tumpuk", makeBuiltInFunc([barisSymbol, null], null, (_, [b, d]) => {
|
|
325
|
-
b.data.push(d);
|
|
347
|
+
b.data.push(valueToVariableDatum(d));
|
|
326
348
|
return b;
|
|
327
349
|
}));
|
|
328
350
|
this.member.define("tumpah", makeBuiltInFunc([barisSymbol], null, (_, [b]) => {
|
|
@@ -333,14 +355,14 @@ class BarisTipe extends Stipe {
|
|
|
333
355
|
if (idx.data > b.data.length) {
|
|
334
356
|
v.error(`Indeks tidak valid, ${idx.data}, dengan ukuran baris ${b.data.length}`);
|
|
335
357
|
}
|
|
336
|
-
b.data.splice(idx.data, 0, d);
|
|
358
|
+
b.data.splice(idx.data, 0, valueToVariableDatum(d));
|
|
337
359
|
return b;
|
|
338
360
|
}));
|
|
339
361
|
this.member.define("petakan", makeBuiltInFunc([barisSymbol, mesinSymbol], barisSymbol, (v, [b, m]) => {
|
|
340
362
|
let newBaris = new Value(barisSymbol, []);
|
|
341
363
|
for (let datum of b.data) {
|
|
342
364
|
let result = v.callFunc(m.data, [datum]);
|
|
343
|
-
newBaris.data.push(result);
|
|
365
|
+
newBaris.data.push(valueToVariableDatum(result));
|
|
344
366
|
}
|
|
345
367
|
return newBaris;
|
|
346
368
|
}));
|
|
@@ -349,7 +371,7 @@ class BarisTipe extends Stipe {
|
|
|
349
371
|
for (let datum of b.data) {
|
|
350
372
|
let result = v.callFunc(m.data, [datum]);
|
|
351
373
|
if (result.data === true) {
|
|
352
|
-
newBaris.data.push(datum);
|
|
374
|
+
newBaris.data.push(valueToVariableDatum(datum));
|
|
353
375
|
}
|
|
354
376
|
}
|
|
355
377
|
return newBaris;
|
|
@@ -361,13 +383,33 @@ class BarisTipe extends Stipe {
|
|
|
361
383
|
}
|
|
362
384
|
return d;
|
|
363
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
|
+
}));
|
|
364
404
|
}
|
|
365
405
|
}
|
|
366
406
|
|
|
367
407
|
class MesinTipe extends Stipe {
|
|
368
408
|
constructor() {
|
|
369
409
|
super(mesinSymbol);
|
|
370
|
-
|
|
410
|
+
|
|
411
|
+
this.member.define("kePetik",
|
|
412
|
+
makeBuiltInFunc([mesinSymbol], petikSymbol, (v, [m]) => new Value(petikSymbol, kePetik(v, m))));
|
|
371
413
|
}
|
|
372
414
|
}
|
|
373
415
|
|
|
@@ -411,6 +453,10 @@ let Jenis$1 = class Jenis extends Stipe {
|
|
|
411
453
|
enums.forEach((thing, idx) => {
|
|
412
454
|
this.member.define(thing.lexeme, new Value(sym, idx));
|
|
413
455
|
});
|
|
456
|
+
this.member.define("kePetik", makeBuiltInFunc([sym], petikSymbol, (_, [j]) => {
|
|
457
|
+
let enumName = enums.map(thing=>thing.lexeme)[j.data];
|
|
458
|
+
return new Value(petikSymbol, `${name}.${enumName}`);
|
|
459
|
+
}));
|
|
414
460
|
this.init(sym);
|
|
415
461
|
}
|
|
416
462
|
|
|
@@ -444,7 +490,12 @@ function copier(thing) {
|
|
|
444
490
|
case angkaSymbol: return new Value(angkaSymbol, thing.data);
|
|
445
491
|
case logisSymbol: return new Value(logisSymbol, thing.data);
|
|
446
492
|
case mesinSymbol: return new Value(mesinSymbol, thing.data);
|
|
447
|
-
case barisSymbol: return new Value(barisSymbol, thing.data.map((val) =>
|
|
493
|
+
case barisSymbol: return new Value(barisSymbol, thing.data.map((val) => {
|
|
494
|
+
let copy = copier(val);
|
|
495
|
+
let varCopy = new Variable(copy.type, false, copy.data);
|
|
496
|
+
varCopy.member = copy.member;
|
|
497
|
+
return varCopy
|
|
498
|
+
}));
|
|
448
499
|
case stipeSymbol: return NIHIL;
|
|
449
500
|
case modulSymbol: return NIHIL;
|
|
450
501
|
default:
|
|
@@ -453,13 +504,17 @@ function copier(thing) {
|
|
|
453
504
|
let valCopy = new Value(thing.type, null);
|
|
454
505
|
let newMember = new Environment();
|
|
455
506
|
for (let i of keys) {
|
|
456
|
-
|
|
507
|
+
let varPrev = thing.member.get(i);
|
|
508
|
+
let tempCopy = copier(varPrev);
|
|
509
|
+
let varCopy = new Variable(varPrev.type, varPrev.tetap, tempCopy.data);
|
|
510
|
+
varCopy.member = tempCopy.member;
|
|
511
|
+
newMember.define(i, varCopy);
|
|
457
512
|
}
|
|
458
513
|
valCopy.member = newMember;
|
|
459
|
-
|
|
514
|
+
valCopy.data = thing.data;
|
|
460
515
|
return valCopy;
|
|
461
516
|
}
|
|
462
|
-
return
|
|
517
|
+
return new Value(thing.type, thing.data);
|
|
463
518
|
}
|
|
464
519
|
}
|
|
465
520
|
|
|
@@ -922,8 +977,9 @@ class Interpreter {
|
|
|
922
977
|
if (type.member?.has(name)) {
|
|
923
978
|
if (willBeCalled) {
|
|
924
979
|
this.objectStack = main;
|
|
980
|
+
return type.member.get(name);
|
|
925
981
|
}
|
|
926
|
-
|
|
982
|
+
this.error(`akses titik . dari objek ke model harus berupa panggilan/penggunaaan mesin.`);
|
|
927
983
|
}
|
|
928
984
|
this.error(`nama .${name} tidak ditemukan dalam tipe ${main.type.description}`);
|
|
929
985
|
} else {
|
|
@@ -943,40 +999,7 @@ class Interpreter {
|
|
|
943
999
|
|
|
944
1000
|
visitCetakStmt(cetakStmt) {
|
|
945
1001
|
let result = cetakStmt.expr.accept(this);
|
|
946
|
-
|
|
947
|
-
if (thing.type === logisSymbol) {
|
|
948
|
-
return thing.data ? "benar" : "salah";
|
|
949
|
-
} else if (thing.type === barisSymbol) {
|
|
950
|
-
return '[' + thing.data.reduce((str, val) => {
|
|
951
|
-
let item = kePetik(val);
|
|
952
|
-
return str + ", " + (val.type === petikSymbol ? `"${item}"` : item);
|
|
953
|
-
}, "").slice(1) + ' ]';
|
|
954
|
-
} else if (thing.type === stipeSymbol) {
|
|
955
|
-
return `Model<${thing.symbol.description}>`;
|
|
956
|
-
} else if (thing.type === mesinSymbol) {
|
|
957
|
-
let underlying = thing.data.returnType?.description;
|
|
958
|
-
return `Mesin<${underlying ? underlying : 'datum'}>`;
|
|
959
|
-
} else if (thing.type === angkaSymbol) {
|
|
960
|
-
return thing.data.toString();
|
|
961
|
-
} else if (thing.type === petikSymbol) {
|
|
962
|
-
return thing.data;
|
|
963
|
-
} else {
|
|
964
|
-
if (!thing?.type) return `nihil`;
|
|
965
|
-
let type = this.environment.get(thing.type.description);
|
|
966
|
-
if (type?.member?.has("kePetik")) {
|
|
967
|
-
let prevState = this.state;
|
|
968
|
-
this.state = location.MESIN;
|
|
969
|
-
this.stack.push(this.line);
|
|
970
|
-
let res = this.callFunc(type.member.get("kePetik").data, [thing]).data;
|
|
971
|
-
this.stack.pop();
|
|
972
|
-
this.state = prevState;
|
|
973
|
-
return res;
|
|
974
|
-
}
|
|
975
|
-
return `${thing.type.description}<>`;
|
|
976
|
-
}
|
|
977
|
-
};
|
|
978
|
-
|
|
979
|
-
this.output.push(kePetik(result));
|
|
1002
|
+
this.output.push(kePetik(this, result));
|
|
980
1003
|
|
|
981
1004
|
}
|
|
982
1005
|
|
|
@@ -1008,6 +1031,9 @@ class Interpreter {
|
|
|
1008
1031
|
|
|
1009
1032
|
visitRubahStmt(rubahStmt) {
|
|
1010
1033
|
let variable = rubahStmt.variable.accept(this); // is a reference to the variable data
|
|
1034
|
+
if (variable.tetap === undefined) {
|
|
1035
|
+
this.error(`Pe-rubah-an hanya dapat dilakukan kepada Variabel!`);
|
|
1036
|
+
}
|
|
1011
1037
|
if (variable.tetap) {
|
|
1012
1038
|
this.error(`Variabel tetap tidak dapat di-rubah.`);
|
|
1013
1039
|
}
|
|
@@ -2295,6 +2321,7 @@ class Simpl {
|
|
|
2295
2321
|
let output = this.interpreter.interpret(pohon);
|
|
2296
2322
|
return output.join("\n");
|
|
2297
2323
|
} catch (err) {
|
|
2324
|
+
// throw err
|
|
2298
2325
|
if (err instanceof SimplError) {
|
|
2299
2326
|
const errorCode = textLines[err.line - 1];
|
|
2300
2327
|
let errorText = (errorCode ? `ERROR! Pada baris ke-${err.line}\n>> ` + errorCode + '\n' : "") + err.message;
|