bahasa-simpl 1.0.0 → 1.0.2
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-interpreter.js +352 -222
- package/package.json +1 -1
|
@@ -4,7 +4,12 @@ class SimplError extends Error {
|
|
|
4
4
|
super(message);
|
|
5
5
|
this.line = line;
|
|
6
6
|
}
|
|
7
|
-
}class SimplErrorEksekusi extends SimplError {
|
|
7
|
+
}class SimplErrorEksekusi extends SimplError {
|
|
8
|
+
constructor(message, line, output) {
|
|
9
|
+
super(message, line);
|
|
10
|
+
this.output = output;
|
|
11
|
+
}
|
|
12
|
+
}class SimplErrorStruktur extends SimplError {}class SimplErrorTulisan extends SimplError {}
|
|
8
13
|
|
|
9
14
|
// Environment defines a scope for all data to live in
|
|
10
15
|
class Environment {
|
|
@@ -174,6 +179,8 @@ class Value {
|
|
|
174
179
|
}
|
|
175
180
|
}
|
|
176
181
|
|
|
182
|
+
const NIHIL = new Value(null, null);
|
|
183
|
+
|
|
177
184
|
class Variable extends Value {
|
|
178
185
|
constructor(type, tetap, data) {
|
|
179
186
|
super(type, data);
|
|
@@ -198,9 +205,9 @@ class Stipe extends Variable {
|
|
|
198
205
|
|
|
199
206
|
let result = null;
|
|
200
207
|
if (left) { // Binary
|
|
201
|
-
result = operatorFunc.data
|
|
208
|
+
result = visitor.callFunc(operatorFunc.data, [right, left]);
|
|
202
209
|
} else { // Unary, safe because valid unary op is just + - ! in the parser
|
|
203
|
-
result = operatorFunc.data
|
|
210
|
+
result = visitor.callFunc(operatorFunc.data, [right]);
|
|
204
211
|
}
|
|
205
212
|
return result;
|
|
206
213
|
}
|
|
@@ -208,168 +215,180 @@ class Stipe extends Variable {
|
|
|
208
215
|
|
|
209
216
|
class PetikTipe extends Stipe {
|
|
210
217
|
constructor() {
|
|
211
|
-
super(petikSymbol,
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
return new Value(petikSymbol, kePetik(args[0]));
|
|
218
|
+
super(petikSymbol, new Callable(null, (v,args) => {
|
|
219
|
+
const kePetik = (thing) => {
|
|
220
|
+
if (thing.type === logisSymbol) {
|
|
221
|
+
return thing.data ? "benar" : "salah";
|
|
222
|
+
} else if (thing.type === barisSymbol) {
|
|
223
|
+
return '[' + thing.data.reduce((str, val)=>str+", "+kePetik(val), "").slice(1) + ' ]';
|
|
224
|
+
} else if (thing.type === stipeSymbol) {
|
|
225
|
+
return `Model<${thing.symbol.description}>`;
|
|
226
|
+
} else if (thing.type === mesinSymbol) {
|
|
227
|
+
let underlying = thing.data.returnType?.description;
|
|
228
|
+
return `Mesin<${underlying? underlying : 'datum'}>`;
|
|
229
|
+
} else if (thing.type === angkaSymbol) {
|
|
230
|
+
return thing.data.toString();
|
|
231
|
+
} else if (thing.type === petikSymbol) {
|
|
232
|
+
return '"' + thing.data + '"';
|
|
233
|
+
} else {
|
|
234
|
+
if (!thing?.type) return `nihil`;
|
|
235
|
+
let type = v.environment.get(thing.type.description);
|
|
236
|
+
if (type?.member.has("kePetik")) {
|
|
237
|
+
v.stack.push(v.line);
|
|
238
|
+
let res = v.callFunc(type.member.get("kePetik").data, [thing]).data;
|
|
239
|
+
v.stack.pop();
|
|
240
|
+
return res;
|
|
235
241
|
}
|
|
236
|
-
|
|
237
|
-
|
|
242
|
+
return `${thing.type.description}<>`;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
return new Value(petikSymbol, kePetik(args[0]));
|
|
246
|
+
}, [[null]], petikSymbol, true)
|
|
247
|
+
);
|
|
238
248
|
this.init();
|
|
239
249
|
}
|
|
240
250
|
|
|
241
251
|
init() {
|
|
242
252
|
// BINARY / UNARY OPERATORS
|
|
243
253
|
this.operators.define("PLUS",
|
|
244
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], petikSymbol, (
|
|
254
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], petikSymbol, (_, [r, l]) => new Value(petikSymbol, l.data+r.data)));
|
|
245
255
|
this.operators.define("LEBIH",
|
|
246
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (
|
|
256
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data>r.data)));
|
|
247
257
|
this.operators.define("KURANG",
|
|
248
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (
|
|
258
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data<r.data)));
|
|
249
259
|
this.operators.define("SAMA_SAMA",
|
|
250
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (
|
|
260
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data===r.data)));
|
|
251
261
|
this.operators.define("LEBIH_SAMA",
|
|
252
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (
|
|
262
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data>=r.data)));
|
|
253
263
|
this.operators.define("KURANG_SAMA",
|
|
254
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (
|
|
264
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data<=r.data)));
|
|
255
265
|
this.operators.define("SERU_SAMA",
|
|
256
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (
|
|
266
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data!==r.data)));
|
|
257
267
|
this.operators.define("AMPERSAN",
|
|
258
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (
|
|
268
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data&&r.data)));
|
|
259
269
|
this.operators.define("PIPA",
|
|
260
|
-
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (
|
|
270
|
+
makeBuiltInFunc([petikSymbol, petikSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data||r.data)));
|
|
261
271
|
|
|
262
272
|
this.operators.define("SERU_UNARY",
|
|
263
|
-
makeBuiltInFunc([petikSymbol], logisSymbol, (
|
|
273
|
+
makeBuiltInFunc([petikSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
264
274
|
|
|
265
275
|
this.member = new Environment();
|
|
266
276
|
|
|
267
|
-
this.member.define("pisah", makeBuiltInFunc([petikSymbol, petikSymbol], barisSymbol, (
|
|
277
|
+
this.member.define("pisah", makeBuiltInFunc([petikSymbol, petikSymbol], barisSymbol, (_, [d, sep])=>{
|
|
268
278
|
return new Value(barisSymbol, d.data.split(sep.data).map(val=>new Value(petikSymbol, val)));
|
|
269
279
|
}));
|
|
270
|
-
this.member.define("bersih", makeBuiltInFunc([petikSymbol], petikSymbol, (
|
|
280
|
+
this.member.define("bersih", makeBuiltInFunc([petikSymbol], petikSymbol, (_, [d])=> {
|
|
271
281
|
return new Value(petikSymbol, d.data.trim())
|
|
272
282
|
}));
|
|
273
283
|
this.member.define("ganti", makeBuiltInFunc([petikSymbol, petikSymbol, petikSymbol], petikSymbol,
|
|
274
|
-
(
|
|
284
|
+
(_, [d, what, rep]) => new Value(petikSymbol, d.data.replaceAll(what.data, rep.data))
|
|
275
285
|
));
|
|
286
|
+
this.member.define("besar", makeBuiltInFunc([petikSymbol], petikSymbol, (_, [p]) => {
|
|
287
|
+
return new Value(petikSymbol, p.data.toUpperCase())
|
|
288
|
+
}));
|
|
289
|
+
this.member.define("kecil", makeBuiltInFunc([petikSymbol], petikSymbol, (_, [p]) => {
|
|
290
|
+
return new Value(petikSymbol, p.data.toLowerCase())
|
|
291
|
+
}));
|
|
276
292
|
}
|
|
277
293
|
}
|
|
278
294
|
|
|
279
295
|
class AngkaTipe extends Stipe {
|
|
280
296
|
constructor() {
|
|
281
|
-
super(angkaSymbol, {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
});
|
|
297
|
+
super(angkaSymbol, new Callable(null, (v, args) => {
|
|
298
|
+
if (typeof args[0].data === "number") {
|
|
299
|
+
return new Value(angkaSymbol, args[0].data);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
switch (args[0].type) {
|
|
303
|
+
case petikSymbol:
|
|
304
|
+
if (isNaN(Number(args[0].data))) {
|
|
305
|
+
v.error("Nilai dari petik bukanlah sebuah angka, konversi gagal.");
|
|
306
|
+
}
|
|
307
|
+
return new Value(angkaSymbol, Number(args[0].data));
|
|
308
|
+
case angkaSymbol:
|
|
309
|
+
return new Value(angkaSymbol, args[0].data);
|
|
310
|
+
case logisSymbol:
|
|
311
|
+
return new Value(angkaSymbol, Number(args[0].data));
|
|
312
|
+
default:
|
|
313
|
+
v.error(`Tipe yang dapat diterima hanyalah petik, angka, logis, dan jenis. Mendapatkan ${args[0].type.description}.`);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
}, [[null]], angkaSymbol, true)
|
|
317
|
+
);
|
|
303
318
|
this.init();
|
|
304
319
|
}
|
|
305
320
|
|
|
306
321
|
init() {
|
|
307
322
|
this.operators.define("PLUS",
|
|
308
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (
|
|
323
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data+r.data)));
|
|
309
324
|
this.operators.define("MINUS",
|
|
310
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (
|
|
325
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data-r.data)));
|
|
311
326
|
this.operators.define("BINTANG",
|
|
312
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (
|
|
327
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data*r.data)));
|
|
313
328
|
this.operators.define("GARIS_MIRING",
|
|
314
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (
|
|
329
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data/r.data)));
|
|
315
330
|
this.operators.define("MODULUS",
|
|
316
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (
|
|
331
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [r, l]) => new Value(angkaSymbol, l.data%r.data)));
|
|
317
332
|
|
|
318
333
|
this.operators.define("LEBIH",
|
|
319
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (
|
|
334
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data>r.data)));
|
|
320
335
|
this.operators.define("KURANG",
|
|
321
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (
|
|
336
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data<r.data)));
|
|
322
337
|
this.operators.define("SAMA_SAMA",
|
|
323
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (
|
|
338
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data===r.data)));
|
|
324
339
|
this.operators.define("LEBIH_SAMA",
|
|
325
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (
|
|
340
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data>=r.data)));
|
|
326
341
|
this.operators.define("KURANG_SAMA",
|
|
327
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (
|
|
342
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data<=r.data)));
|
|
328
343
|
this.operators.define("SERU_SAMA",
|
|
329
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (
|
|
344
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data!==r.data)));
|
|
330
345
|
this.operators.define("AMPERSAN",
|
|
331
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (
|
|
346
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data&&r.data)));
|
|
332
347
|
this.operators.define("PIPA",
|
|
333
|
-
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (
|
|
348
|
+
makeBuiltInFunc([angkaSymbol, angkaSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data||r.data)));
|
|
334
349
|
this.operators.define("SERU_UNARY",
|
|
335
|
-
makeBuiltInFunc([angkaSymbol], logisSymbol, (
|
|
350
|
+
makeBuiltInFunc([angkaSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
336
351
|
this.operators.define("PLUS_UNARY",
|
|
337
|
-
makeBuiltInFunc([angkaSymbol], angkaSymbol, (
|
|
352
|
+
makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [r]) => new Value(angkaSymbol, +r.data)));
|
|
338
353
|
this.operators.define("MINUS_UNARY",
|
|
339
|
-
makeBuiltInFunc([angkaSymbol], angkaSymbol, (
|
|
354
|
+
makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [r]) => new Value(angkaSymbol, -r.data)));
|
|
340
355
|
|
|
341
356
|
this.member = new Environment();
|
|
357
|
+
|
|
358
|
+
this.member.define("bulat", makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [a]) => {
|
|
359
|
+
return new Value(angkaSymbol, Math.round(a.data));
|
|
360
|
+
}));
|
|
361
|
+
this.member.define("bulatAtas", makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [a]) => {
|
|
362
|
+
return new Value(angkaSymbol, Math.ceil(a.data))
|
|
363
|
+
}));
|
|
364
|
+
this.member.define("bulatBawah", makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [a]) => {
|
|
365
|
+
return new Value(angkaSymbol, Math.floor(a.data))
|
|
366
|
+
}));
|
|
342
367
|
}
|
|
343
368
|
}
|
|
344
369
|
|
|
345
370
|
class LogisTipe extends Stipe {
|
|
346
371
|
constructor() {
|
|
347
|
-
super(logisSymbol, {
|
|
348
|
-
callFunc: (v, args) => {
|
|
349
|
-
if (args.length !== 1) {
|
|
350
|
-
v.error(`Jumlah argumen tidak sama dengan parameter mesin: ${args.length} != 1.`);
|
|
351
|
-
}
|
|
352
|
-
|
|
372
|
+
super(logisSymbol, new Callable(null, (_, args) => {
|
|
353
373
|
return new Value(logisSymbol, Boolean(args[0].data) || Boolean(args[0].data.member));
|
|
354
|
-
}
|
|
355
|
-
|
|
374
|
+
}, [[null]], logisSymbol, true)
|
|
375
|
+
);
|
|
356
376
|
this.init();
|
|
357
377
|
}
|
|
358
378
|
|
|
359
379
|
init() {
|
|
360
380
|
this.operators.define("SAMA_SAMA",
|
|
361
|
-
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (
|
|
381
|
+
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data===r.data)));
|
|
362
382
|
this.operators.define("SERU_SAMA",
|
|
363
|
-
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (
|
|
364
|
-
|
|
383
|
+
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data!==r.data)));
|
|
365
384
|
this.operators.define("AMPERSAN",
|
|
366
|
-
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (
|
|
385
|
+
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data&&r.data)));
|
|
367
386
|
this.operators.define("PIPA",
|
|
368
|
-
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (
|
|
387
|
+
makeBuiltInFunc([logisSymbol, logisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data||r.data)));
|
|
369
388
|
this.operators.define("SERU_UNARY",
|
|
370
|
-
makeBuiltInFunc([logisSymbol], logisSymbol, (
|
|
389
|
+
makeBuiltInFunc([logisSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
371
390
|
|
|
372
|
-
this.member =
|
|
391
|
+
this.member = new Environment();
|
|
373
392
|
}
|
|
374
393
|
}
|
|
375
394
|
|
|
@@ -381,17 +400,17 @@ class BarisTipe extends Stipe {
|
|
|
381
400
|
|
|
382
401
|
init () {
|
|
383
402
|
this.operators.define("PLUS",
|
|
384
|
-
makeBuiltInFunc([barisSymbol, barisSymbol], barisSymbol, (
|
|
403
|
+
makeBuiltInFunc([barisSymbol, barisSymbol], barisSymbol, (_, [r,l]) =>
|
|
404
|
+
new Value(barisSymbol, Array(...l.data, ...r.data))
|
|
405
|
+
));
|
|
385
406
|
|
|
386
407
|
this.operators.define("MINUS_UNARY",
|
|
387
|
-
makeBuiltInFunc([barisSymbol], barisSymbol, (
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
return newBaris;
|
|
391
|
-
}));
|
|
408
|
+
makeBuiltInFunc([barisSymbol], barisSymbol, (_, [r]) =>
|
|
409
|
+
new Value(barisSymbol, r.data.slice(0,r.length))
|
|
410
|
+
));
|
|
392
411
|
|
|
393
412
|
this.operators.define("SAMA_SAMA",
|
|
394
|
-
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (
|
|
413
|
+
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, ((a,b)=>{
|
|
395
414
|
if (a.length !== b.length) return false;
|
|
396
415
|
for (let i = 0; i < a.length; i++) {
|
|
397
416
|
if (a[i].data !== b[i].data) return false;
|
|
@@ -401,7 +420,7 @@ class BarisTipe extends Stipe {
|
|
|
401
420
|
);
|
|
402
421
|
|
|
403
422
|
this.operators.define("SERU_SAMA",
|
|
404
|
-
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (
|
|
423
|
+
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, ((a,b)=>{
|
|
405
424
|
if (a.length !== b.length) return true;
|
|
406
425
|
for (let i = 0; i < a.length; i++) {
|
|
407
426
|
if (a[i].data !== b[i].data) return true;
|
|
@@ -411,11 +430,11 @@ class BarisTipe extends Stipe {
|
|
|
411
430
|
);
|
|
412
431
|
|
|
413
432
|
this.operators.define("AMPERSAN",
|
|
414
|
-
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (
|
|
433
|
+
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data&&r.data)));
|
|
415
434
|
this.operators.define("PIPA",
|
|
416
|
-
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (
|
|
435
|
+
makeBuiltInFunc([barisSymbol, barisSymbol], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data||r.data)));
|
|
417
436
|
this.operators.define("SERU_UNARY",
|
|
418
|
-
makeBuiltInFunc([barisSymbol], logisSymbol, (
|
|
437
|
+
makeBuiltInFunc([barisSymbol], logisSymbol, (_, [r]) => new Value(logisSymbol, !Boolean(r.data))));
|
|
419
438
|
|
|
420
439
|
this.member = new Environment();
|
|
421
440
|
|
|
@@ -425,7 +444,55 @@ class BarisTipe extends Stipe {
|
|
|
425
444
|
}
|
|
426
445
|
|
|
427
446
|
while (i.data < 0) i.data += b.data.length;
|
|
428
|
-
|
|
447
|
+
b.data = b.data.filter((_, idx) => idx !== i.data);
|
|
448
|
+
return b;
|
|
449
|
+
}));
|
|
450
|
+
|
|
451
|
+
this.member.define("potongan", makeBuiltInFunc([barisSymbol, angkaSymbol, angkaSymbol], barisSymbol, (v, [b, fr, to]) => {
|
|
452
|
+
if (fr.data >= b.data.length || fr.data < 0 || to.data <= fr.data || to.data > b.data.length) {
|
|
453
|
+
v.error(`Indeks tidak valid, ${fr.data}:${to.data}, dengan ukuran baris ${b.data.length}`);
|
|
454
|
+
}
|
|
455
|
+
return new Value(barisSymbol, b.data.slice(fr.data, to.data));
|
|
456
|
+
}));
|
|
457
|
+
this.member.define("tumpuk", makeBuiltInFunc([barisSymbol, null], null, (_, [b, d])=>{
|
|
458
|
+
b.data.push(d);
|
|
459
|
+
return b;
|
|
460
|
+
}));
|
|
461
|
+
this.member.define("tumpah", makeBuiltInFunc([barisSymbol], null, (_, [b])=>{
|
|
462
|
+
b.data.pop();
|
|
463
|
+
return b;
|
|
464
|
+
}));
|
|
465
|
+
this.member.define("masuk", makeBuiltInFunc([barisSymbol, null, angkaSymbol], null, (v, [b, d, idx]) => {
|
|
466
|
+
if (idx.data > b.data.length) {
|
|
467
|
+
v.error(`Indeks tidak valid, ${idx.data}, dengan ukuran baris ${b.data.length}`);
|
|
468
|
+
}
|
|
469
|
+
b.data.splice(idx.data, 0, d);
|
|
470
|
+
return b;
|
|
471
|
+
}));
|
|
472
|
+
this.member.define("petakan", makeBuiltInFunc([barisSymbol, mesinSymbol], barisSymbol, (v, [b, m]) => {
|
|
473
|
+
let newBaris = new Value(barisSymbol, []);
|
|
474
|
+
for (let datum of b.data) {
|
|
475
|
+
let result = v.callFunc(m.data, [datum]);
|
|
476
|
+
newBaris.data.push(result);
|
|
477
|
+
}
|
|
478
|
+
return newBaris;
|
|
479
|
+
}));
|
|
480
|
+
this.member.define("saring", makeBuiltInFunc([barisSymbol, mesinSymbol], barisSymbol, (v, [b, m]) => {
|
|
481
|
+
let newBaris = new Value(barisSymbol, []);
|
|
482
|
+
for (let datum of b.data) {
|
|
483
|
+
let result = v.callFunc(m.data, [datum]);
|
|
484
|
+
if (result.data === true) {
|
|
485
|
+
newBaris.data.push(datum);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return newBaris;
|
|
489
|
+
}));
|
|
490
|
+
this.member.define("reduksi", makeBuiltInFunc([barisSymbol, mesinSymbol, null], null, (v, [b, m, d]) => {
|
|
491
|
+
for (let datum of b.data) {
|
|
492
|
+
let result = v.callFunc(m.data, [d, datum]);
|
|
493
|
+
d = result;
|
|
494
|
+
}
|
|
495
|
+
return d;
|
|
429
496
|
}));
|
|
430
497
|
}
|
|
431
498
|
}
|
|
@@ -433,20 +500,14 @@ class BarisTipe extends Stipe {
|
|
|
433
500
|
class MesinTipe extends Stipe {
|
|
434
501
|
constructor() {
|
|
435
502
|
super(mesinSymbol);
|
|
436
|
-
this.member =
|
|
503
|
+
this.member = new Environment();
|
|
437
504
|
}
|
|
438
505
|
}
|
|
439
|
-
|
|
506
|
+
|
|
440
507
|
let Model$1 = class Model extends Stipe {
|
|
441
508
|
constructor(name, params) {
|
|
442
509
|
let sym = Symbol(name);
|
|
443
|
-
super(sym, {
|
|
444
|
-
callFunc: (v, args) => {
|
|
445
|
-
if (args.length !== params.length) {
|
|
446
|
-
v.error("Jumlah argumen tidak sama dengan parameter mesin:" + ` ${args.length} != ${params.length}.`);
|
|
447
|
-
}
|
|
448
|
-
// for call error info
|
|
449
|
-
let callLineNum = v.line;
|
|
510
|
+
super(sym, new Callable(null, (v, args) => {
|
|
450
511
|
|
|
451
512
|
let obj = new Value(sym, true);
|
|
452
513
|
obj.member = new Environment();
|
|
@@ -460,18 +521,14 @@ let Model$1 = class Model extends Stipe {
|
|
|
460
521
|
if (args[i].data === null) ; else if (symbol === null) {
|
|
461
522
|
val.isDatum = true;
|
|
462
523
|
val.type = args[i].type;
|
|
463
|
-
} else if (symbol !== args[i].type) {
|
|
464
|
-
v.line = callLineNum;
|
|
465
|
-
v.error(`Tipe member tidak sama dengan argumen. ${symbol.description} != ${args[i].type.description}`);
|
|
466
524
|
}
|
|
467
525
|
val.member = args[i].member;
|
|
468
526
|
obj.member.define(name, val);
|
|
469
527
|
}
|
|
470
528
|
|
|
471
|
-
obj.member.define("objek", obj);
|
|
472
529
|
return obj;
|
|
473
|
-
}
|
|
474
|
-
|
|
530
|
+
}, params.map(_=>[null]), sym, true)
|
|
531
|
+
);
|
|
475
532
|
}
|
|
476
533
|
};
|
|
477
534
|
|
|
@@ -488,81 +545,24 @@ let Jenis$1 = class Jenis extends Stipe {
|
|
|
488
545
|
|
|
489
546
|
init(sym) {
|
|
490
547
|
this.operators.define("SAMA_SAMA",
|
|
491
|
-
makeBuiltInFunc([sym, sym], logisSymbol, (
|
|
548
|
+
makeBuiltInFunc([sym, sym], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data===r.data)));
|
|
492
549
|
this.operators.define("SERU_SAMA",
|
|
493
|
-
makeBuiltInFunc([sym, sym], logisSymbol, (
|
|
550
|
+
makeBuiltInFunc([sym, sym], logisSymbol, (_, [r, l]) => new Value(logisSymbol, l.data!==r.data)));
|
|
494
551
|
}
|
|
495
552
|
};
|
|
496
553
|
|
|
497
554
|
class Callable {
|
|
498
|
-
constructor(enclosing, block, parameters, returnType) {
|
|
555
|
+
constructor(enclosing, block, parameters, returnType, isBuiltIn=false) {
|
|
499
556
|
this.closure = enclosing;
|
|
500
557
|
this.block = block;
|
|
501
558
|
this.parameters = parameters;
|
|
502
559
|
this.returnType = returnType;
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
// call with arguments (of value)
|
|
506
|
-
callFunc (visitor, args) {
|
|
507
|
-
// this function may go into the interpreter idk
|
|
508
|
-
if (args.length !== this.parameters.length) {
|
|
509
|
-
visitor.error("Jumlah argumen tidak sama dengan parameter mesin:" + ` ${args.length} != ${this.parameters.length}.`);
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
// for asserting _call_ error.
|
|
513
|
-
let callLineNum = visitor.line;
|
|
514
|
-
|
|
515
|
-
let visitorEnv = visitor.environment;
|
|
516
|
-
let funcEnv = new Environment(this.closure);
|
|
517
|
-
visitor.environment = funcEnv;
|
|
518
|
-
for(let i = 0; i < args.length; i++) {
|
|
519
|
-
let [type, tetap, name] = this.parameters[i];
|
|
520
|
-
let val = new Variable(type, tetap, args[i].data);
|
|
521
|
-
|
|
522
|
-
if (type === null) {
|
|
523
|
-
val.isDatum = true;
|
|
524
|
-
val.type = args[i].type;
|
|
525
|
-
} else if (args[i].data === null) ; else if (args[i].type !== type) {
|
|
526
|
-
visitor.line = callLineNum;
|
|
527
|
-
visitor.error(`Tipe argumen tidak sama dengan parameter. ${args[i].type} != ${type.description}`);
|
|
528
|
-
}
|
|
529
|
-
val.member = args[i].member;
|
|
530
|
-
funcEnv.define(name, val);
|
|
531
|
-
}
|
|
532
|
-
let result = new Value(null, null);
|
|
533
|
-
for(let stmt of this.block.statements) {
|
|
534
|
-
try {
|
|
535
|
-
stmt.accept(visitor);
|
|
536
|
-
} catch (err) {
|
|
537
|
-
if (err instanceof Hasil$1) {
|
|
538
|
-
result = err.value;
|
|
539
|
-
break;
|
|
540
|
-
} else if (err instanceof Henti$1 || err instanceof Lewat$1) {
|
|
541
|
-
visitor.error("Tidak bisa menghentikan atau melewatkan mesin. ");
|
|
542
|
-
} else throw err;
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
visitor.environment = visitorEnv;
|
|
546
|
-
return result;
|
|
560
|
+
this.isBuiltIn = isBuiltIn;
|
|
547
561
|
}
|
|
548
562
|
}
|
|
549
563
|
|
|
550
|
-
// this approach is too slow. Will fix later...
|
|
551
|
-
|
|
552
564
|
function makeBuiltInFunc(parameters, returnType, funcBody) {
|
|
553
|
-
let lambda = new Callable(null,
|
|
554
|
-
lambda.callFunc = (v, args) => {
|
|
555
|
-
if (args.length != parameters.length) {
|
|
556
|
-
v.error("Jumlah Argumen tidak sama dengan parameter:" + ` Seharusnya ${parameters.length} dan bukan ${args.length}.`);
|
|
557
|
-
}
|
|
558
|
-
for (let i = 0; i < args.length; i++) {
|
|
559
|
-
if (parameters[i] === null) continue;
|
|
560
|
-
if (args[i].type !== parameters[i]) {
|
|
561
|
-
v.error("Tipe argumen tidak sama dengan tipe parameter." + ` Seharusnya ${parameters[i].type.description} dan bukan ${args[i].description}`);
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
return funcBody(v, args);
|
|
565
|
-
};
|
|
565
|
+
let lambda = new Callable(null, funcBody, parameters.map((val)=>[val]), returnType, true);
|
|
566
566
|
let variable = new Variable(mesinSymbol, true, lambda);
|
|
567
567
|
return variable;
|
|
568
568
|
}
|
|
@@ -574,23 +574,21 @@ function copier(thing) {
|
|
|
574
574
|
case logisSymbol: return new Value(logisSymbol, thing.data);
|
|
575
575
|
case mesinSymbol: return new Value(mesinSymbol, thing.data);
|
|
576
576
|
case barisSymbol: return new Value(barisSymbol, thing.data.map((val)=>copier(val)));
|
|
577
|
-
case stipeSymbol: return
|
|
578
|
-
case modulSymbol: return
|
|
577
|
+
case stipeSymbol: return NIHIL;
|
|
578
|
+
case modulSymbol: return NIHIL;
|
|
579
579
|
default:
|
|
580
580
|
if (thing.member && thing.member instanceof Environment) {
|
|
581
581
|
let keys = thing.member.memory.keys();
|
|
582
582
|
let valCopy = new Value(thing.type, null);
|
|
583
583
|
let newMember = new Environment();
|
|
584
584
|
for (let i of keys) {
|
|
585
|
-
if (i === "objek") continue;
|
|
586
585
|
newMember.define(i, copier(thing.member.get(i)));
|
|
587
586
|
}
|
|
588
|
-
newMember.define("objek", valCopy);
|
|
589
587
|
valCopy.member = newMember;
|
|
590
588
|
|
|
591
589
|
return valCopy;
|
|
592
590
|
}
|
|
593
|
-
return
|
|
591
|
+
return NIHIL;
|
|
594
592
|
}
|
|
595
593
|
}
|
|
596
594
|
|
|
@@ -604,23 +602,37 @@ const GLOBAL_ENV = (() => {
|
|
|
604
602
|
env.define("mesin", new MesinTipe());
|
|
605
603
|
|
|
606
604
|
env.define("jarak", makeBuiltInFunc([angkaSymbol, angkaSymbol], barisSymbol,
|
|
607
|
-
(
|
|
605
|
+
(_, [from, to])=>new Value(barisSymbol,
|
|
608
606
|
Array(Math.abs(Math.floor(to.data-from.data)))
|
|
609
607
|
.fill(0)
|
|
610
|
-
.map((
|
|
608
|
+
.map((_, idx)=>new Value(angkaSymbol, from.data+((to.data>from.data)?1:-1)*idx))))
|
|
611
609
|
);
|
|
612
610
|
|
|
613
|
-
env.define("nihil?", makeBuiltInFunc([null], logisSymbol, (
|
|
614
|
-
env.define("ukuran", makeBuiltInFunc([null], angkaSymbol,(
|
|
611
|
+
env.define("nihil?", makeBuiltInFunc([null], logisSymbol, (_, [d]) => new Value(logisSymbol, d.data === null)));
|
|
612
|
+
env.define("ukuran", makeBuiltInFunc([null], angkaSymbol,(_, [d]) => d.type === barisSymbol || d.type === petikSymbol
|
|
615
613
|
? new Value(angkaSymbol, d.data.length)
|
|
616
614
|
: v.error(`Ukuran hanya terdapat untuk tipe petik atau baris. Menemukan tipe ${d.type.description}.`)
|
|
617
615
|
));
|
|
618
616
|
|
|
619
|
-
env.define("salin", makeBuiltInFunc([null], null, (
|
|
620
|
-
env.define("tipe", makeBuiltInFunc([null], petikSymbol, (
|
|
617
|
+
env.define("salin", makeBuiltInFunc([null], null, (_, [d]) => copier(d)));
|
|
618
|
+
env.define("tipe", makeBuiltInFunc([null], petikSymbol, (_, [d]) => (d.type?.description)
|
|
621
619
|
? new Value(petikSymbol, d.type.description)
|
|
622
620
|
: new Value(petikSymbol, "datum")
|
|
623
621
|
));
|
|
622
|
+
|
|
623
|
+
let mtkModul = new Variable(modulSymbol, true, null);
|
|
624
|
+
mtkModul.member = new Environment();
|
|
625
|
+
mtkModul.member.define("acak", makeBuiltInFunc([angkaSymbol, angkaSymbol], angkaSymbol, (_, [a,b]) => {
|
|
626
|
+
let width = Math.abs(a.data-b.data);
|
|
627
|
+
let range = Math.random() * width;
|
|
628
|
+
let final = range + Math.min(a.data,b.data);
|
|
629
|
+
return new Value(angkaSymbol, final);
|
|
630
|
+
}));
|
|
631
|
+
mtkModul.member.define("akar2", makeBuiltInFunc([angkaSymbol], angkaSymbol, (_, [a]) => {
|
|
632
|
+
return new Value(angkaSymbol, Math.sqrt(a.data));
|
|
633
|
+
}));
|
|
634
|
+
|
|
635
|
+
env.define("mtk", mtkModul);
|
|
624
636
|
return env;
|
|
625
637
|
})();
|
|
626
638
|
|
|
@@ -651,6 +663,8 @@ class Interpreter {
|
|
|
651
663
|
this.state = location.GLOBAL;
|
|
652
664
|
this.stack = [];
|
|
653
665
|
this.output = [];
|
|
666
|
+
this.objectStack = null;
|
|
667
|
+
this.exprWillBeCalled = false;
|
|
654
668
|
}
|
|
655
669
|
|
|
656
670
|
// EXPRESSION VISITORS
|
|
@@ -666,7 +680,7 @@ class Interpreter {
|
|
|
666
680
|
case "boolean":
|
|
667
681
|
return new Value(logisSymbol, lit.value);
|
|
668
682
|
default:
|
|
669
|
-
return new
|
|
683
|
+
return new NIHIL;
|
|
670
684
|
}
|
|
671
685
|
}
|
|
672
686
|
|
|
@@ -675,10 +689,7 @@ class Interpreter {
|
|
|
675
689
|
|
|
676
690
|
for (let expr of arrayExpr.contents) {
|
|
677
691
|
let v = this.validvalue(expr.accept(this));
|
|
678
|
-
|
|
679
|
-
let result = new Value(v.type, v.data);
|
|
680
|
-
result.member = v.member;
|
|
681
|
-
value.data.push(new Value(v.type, v.data));
|
|
692
|
+
value.data.push(v);
|
|
682
693
|
}
|
|
683
694
|
|
|
684
695
|
return value;
|
|
@@ -710,8 +721,18 @@ class Interpreter {
|
|
|
710
721
|
visitLambdaExpr(lambdaExpr) {
|
|
711
722
|
// let type = lambdaExpr.returnValue.accept(this);
|
|
712
723
|
let params = lambdaExpr.params.map(val=>[val[0].accept(this), val[0].tetap, val[1].lexeme]);
|
|
713
|
-
|
|
714
|
-
|
|
724
|
+
|
|
725
|
+
const check_duplicate_name = (p) => {
|
|
726
|
+
let mapped = new Map();
|
|
727
|
+
for (let name of p) {
|
|
728
|
+
if (mapped.has(name)) return true;
|
|
729
|
+
mapped.set(name, true);
|
|
730
|
+
}
|
|
731
|
+
return false;
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
if (params.length > 1
|
|
735
|
+
&& check_duplicate_name(params.map(p=>p[2])) ){
|
|
715
736
|
this.error("Parameter mesin tidak boleh mempunyai nama yang sama.");
|
|
716
737
|
}
|
|
717
738
|
let retType = null;
|
|
@@ -723,26 +744,101 @@ class Interpreter {
|
|
|
723
744
|
}
|
|
724
745
|
|
|
725
746
|
visitCallExpr(callExpr) {
|
|
726
|
-
this.stack.push(this.line);
|
|
727
|
-
if (this.stack.length > MAX_STACK_SIZE)
|
|
728
|
-
this.error(`Rekursi melebihi batas: Lebih dari ${MAX_STACK_SIZE}`);
|
|
729
|
-
this.state = location.MESIN;
|
|
730
|
-
let callable = callExpr.callable.accept(this);
|
|
731
747
|
|
|
748
|
+
this.exprWillBeCalled = true;
|
|
749
|
+
let callable = callExpr.callable.accept(this);
|
|
750
|
+
this.exprWillBeCalled = false;
|
|
751
|
+
|
|
732
752
|
if (callable.type !== mesinSymbol && callable.type !== stipeSymbol) {
|
|
733
753
|
this.error(`Hanya bisa 'memanggil' mesin atau model, malah menemukan ${callable.type.description}. `);
|
|
734
754
|
}
|
|
735
755
|
|
|
736
|
-
if (!callable.data?.
|
|
756
|
+
if (!callable.data?.block) {
|
|
737
757
|
this.error(`Mesin tidak terdefinisi, tidak bisa dipanggil.`);
|
|
738
758
|
}
|
|
759
|
+
|
|
760
|
+
let args = [];
|
|
761
|
+
|
|
762
|
+
if (this.objectStack) {
|
|
763
|
+
args = [this.objectStack];
|
|
764
|
+
this.objectStack = null;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
args = [...args, ...callExpr.args.map(val=>this.validvalue(val.accept(this)))];
|
|
768
|
+
|
|
769
|
+
let result = this.callFunc(callable.data, args);
|
|
770
|
+
return result;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
callFunc(callable, args) {
|
|
774
|
+
// args.forEach((val,idx)=>{
|
|
775
|
+
// console.log(idx, val);
|
|
776
|
+
// });
|
|
777
|
+
this.stack.push(this.line);
|
|
778
|
+
if (this.stack.length > MAX_STACK_SIZE)
|
|
779
|
+
this.error(`Rekursi melebihi batas: Lebih dari ${MAX_STACK_SIZE}`);
|
|
780
|
+
|
|
739
781
|
this.line = this.stack[this.stack.length-1];
|
|
740
|
-
|
|
782
|
+
this.state = location.MESIN;
|
|
783
|
+
|
|
784
|
+
if (args.length !== callable.parameters.length) {
|
|
785
|
+
this.error(`Jumlah argumen tidak sama dengan parameter mesin. Menemukan ${args.length}, harusnya ${callable.parameters.length}.`);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// for asserting _call_ error.
|
|
789
|
+
let callLineNum = this.line;
|
|
790
|
+
|
|
791
|
+
for(let i = 0; i < args.length; i++) {
|
|
792
|
+
let type = callable.parameters[i][0];
|
|
793
|
+
|
|
794
|
+
if (type === null) continue;
|
|
795
|
+
if (args[i].type !== type) {
|
|
796
|
+
this.line = callLineNum;
|
|
797
|
+
this.error(`Tipe argumen tidak sama dengan parameter. Menemukan ${args[i].type.description}, harusnya ${type.description}`);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
if (callable.isBuiltIn) {
|
|
802
|
+
this.stack.pop();
|
|
803
|
+
if (this.stack.length == 0) this.state = location.GLOBAL;
|
|
804
|
+
return callable.block(this, args);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
let visitorEnv = this.environment;
|
|
808
|
+
let funcEnv = new Environment(callable.closure);
|
|
809
|
+
this.environment = funcEnv;
|
|
810
|
+
|
|
811
|
+
for(let i = 0; i < args.length; i++) {
|
|
812
|
+
let [type, tetap, name] = callable.parameters[i];
|
|
813
|
+
if (type === null) {
|
|
814
|
+
type = args[i].type;
|
|
815
|
+
}
|
|
816
|
+
let variable = new Variable(type, tetap, args[i].data);
|
|
817
|
+
variable.member = args[i].member;
|
|
818
|
+
|
|
819
|
+
this.environment.define(name, variable);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
let result = NIHIL;
|
|
823
|
+
for(let stmt of callable.block.statements) {
|
|
824
|
+
try {
|
|
825
|
+
stmt.accept(this);
|
|
826
|
+
} catch (err) {
|
|
827
|
+
if (err instanceof Hasil$1) {
|
|
828
|
+
result = err.value;
|
|
829
|
+
break;
|
|
830
|
+
} else if (err instanceof Henti$1 || err instanceof Lewat$1) {
|
|
831
|
+
this.error("Tidak bisa menghentikan atau melewatkan mesin. ");
|
|
832
|
+
} else throw err;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
741
835
|
this.stack.pop();
|
|
742
836
|
if (this.stack.length == 0) this.state = location.GLOBAL;
|
|
837
|
+
this.environment = visitorEnv;
|
|
743
838
|
return result;
|
|
744
839
|
}
|
|
745
840
|
|
|
841
|
+
|
|
746
842
|
visitBinaryExpr(binaryExpr) {
|
|
747
843
|
let leftValue = this.validvalue(binaryExpr.left.accept(this));
|
|
748
844
|
let rightValue = this.validvalue(binaryExpr.right.accept(this));
|
|
@@ -789,15 +885,23 @@ class Interpreter {
|
|
|
789
885
|
}
|
|
790
886
|
|
|
791
887
|
visitMemberExpr(memberExpr) {
|
|
888
|
+
let willBeCalled = this.exprWillBeCalled;
|
|
889
|
+
this.exprWillBeCalled = false;
|
|
792
890
|
let main = memberExpr.main.accept(this);
|
|
793
891
|
let name = memberExpr.member.token.lexeme;
|
|
794
892
|
this.line = memberExpr.member.token.line;
|
|
795
|
-
if (!main.member) {
|
|
796
|
-
this.
|
|
797
|
-
|
|
798
|
-
|
|
893
|
+
if (!main.member || !main.member.has(name)) {
|
|
894
|
+
const type = this.environment.get(main.type.description);
|
|
895
|
+
if (type.member?.has(name)) {
|
|
896
|
+
if (willBeCalled) {
|
|
897
|
+
this.objectStack = main;
|
|
898
|
+
}
|
|
899
|
+
return type.member.get(name);
|
|
900
|
+
}
|
|
901
|
+
this.error(`nama .${name} tidak ditemukan dalam tipe ${main.type.description}`);
|
|
902
|
+
} else {
|
|
903
|
+
return main.member.get(name);
|
|
799
904
|
}
|
|
800
|
-
return main.member.get(name);
|
|
801
905
|
}
|
|
802
906
|
|
|
803
907
|
// STATEMENT VISITORS
|
|
@@ -816,7 +920,10 @@ class Interpreter {
|
|
|
816
920
|
if (thing.type === logisSymbol) {
|
|
817
921
|
return thing.data ? "benar" : "salah";
|
|
818
922
|
} else if (thing.type === barisSymbol) {
|
|
819
|
-
return '[' + thing.data.reduce((str, val)=>
|
|
923
|
+
return '[' + thing.data.reduce((str, val)=>{
|
|
924
|
+
let item = kePetik(val);
|
|
925
|
+
return str + ", " + (val.type === petikSymbol ? `"${item}"` : item);
|
|
926
|
+
}, "").slice(1) + ' ]';
|
|
820
927
|
} else if (thing.type === stipeSymbol) {
|
|
821
928
|
return `Model<${thing.symbol.description}>`;
|
|
822
929
|
} else if (thing.type === mesinSymbol) {
|
|
@@ -825,9 +932,18 @@ class Interpreter {
|
|
|
825
932
|
} else if (thing.type === angkaSymbol) {
|
|
826
933
|
return thing.data.toString();
|
|
827
934
|
} else if (thing.type === petikSymbol) {
|
|
828
|
-
return
|
|
935
|
+
return thing.data;
|
|
829
936
|
} else {
|
|
830
937
|
if (!thing?.type) return `nihil`;
|
|
938
|
+
let type = this.environment.get(thing.type.description);
|
|
939
|
+
if (type?.member?.has("kePetik")) {
|
|
940
|
+
this.state = location.MESIN;
|
|
941
|
+
this.stack.push(this.line);
|
|
942
|
+
let res = this.callFunc(type.member.get("kePetik").data, [thing]).data;
|
|
943
|
+
this.stack.pop();
|
|
944
|
+
this.state = this.stack > 0 ? location.MESIN : location.GLOBAL;
|
|
945
|
+
return res;
|
|
946
|
+
}
|
|
831
947
|
return `${thing.type.description}<>`;
|
|
832
948
|
}
|
|
833
949
|
};
|
|
@@ -1029,8 +1145,7 @@ class Interpreter {
|
|
|
1029
1145
|
}
|
|
1030
1146
|
|
|
1031
1147
|
let lastEnv = this.environment;
|
|
1032
|
-
this.environment = new Environment(this.
|
|
1033
|
-
if (variable) this.environment.define(name, variable);
|
|
1148
|
+
this.environment = new Environment(this.environment);
|
|
1034
1149
|
for (let stmt of modulStmt.statements) {
|
|
1035
1150
|
stmt.accept(this);
|
|
1036
1151
|
}
|
|
@@ -1076,7 +1191,7 @@ class Interpreter {
|
|
|
1076
1191
|
}
|
|
1077
1192
|
|
|
1078
1193
|
error(message) {
|
|
1079
|
-
throw new SimplErrorEksekusi(`Error Eksekusi => ${message}`, this.line);
|
|
1194
|
+
throw new SimplErrorEksekusi(`Error Eksekusi => ${message}`, this.line, this.output.join('\n'));
|
|
1080
1195
|
}
|
|
1081
1196
|
|
|
1082
1197
|
interpret(tree) {
|
|
@@ -1240,7 +1355,7 @@ class Lexer {
|
|
|
1240
1355
|
|
|
1241
1356
|
scan() {
|
|
1242
1357
|
this.skipWhitespaces();
|
|
1243
|
-
|
|
1358
|
+
while (this.see() === '#') {
|
|
1244
1359
|
this.comment();
|
|
1245
1360
|
this.skipWhitespaces();
|
|
1246
1361
|
}
|
|
@@ -2011,8 +2126,19 @@ class Parser {
|
|
|
2011
2126
|
|
|
2012
2127
|
rubahStmt() {
|
|
2013
2128
|
let id = this.valuable();
|
|
2129
|
+
let shorthand = null;
|
|
2130
|
+
if (this.match(
|
|
2131
|
+
PLUS, MINUS, STAR, SLASH,
|
|
2132
|
+
AMPERSAND, PIPE, MODULUS
|
|
2133
|
+
)) {
|
|
2134
|
+
shorthand = new Binary(id, this.previous(), null);
|
|
2135
|
+
}
|
|
2014
2136
|
this.eat(EQUAL, "Mengharapkan '=' setelah variable yang ingin di-'rubah'.");
|
|
2015
2137
|
let expr = this.expression();
|
|
2138
|
+
if (shorthand) {
|
|
2139
|
+
shorthand.right = expr;
|
|
2140
|
+
expr = shorthand;
|
|
2141
|
+
}
|
|
2016
2142
|
return new Rubah(id, expr);
|
|
2017
2143
|
}
|
|
2018
2144
|
|
|
@@ -2140,8 +2266,12 @@ class Simpl {
|
|
|
2140
2266
|
return output.join("\n");
|
|
2141
2267
|
} catch (err) {
|
|
2142
2268
|
if (err instanceof SimplError) {
|
|
2143
|
-
const
|
|
2144
|
-
|
|
2269
|
+
const errorCode = textLines[err.line-1];
|
|
2270
|
+
let errorText = (errorCode ? `ERROR! Pada baris ke-${err.line}\n>> ` + errorCode + '\n': "") + err.message;
|
|
2271
|
+
if (err instanceof SimplErrorEksekusi) {
|
|
2272
|
+
errorText += (err.output ? "\nOutput dari kode:\n" : "") + err.output;
|
|
2273
|
+
}
|
|
2274
|
+
return errorText;
|
|
2145
2275
|
} else {
|
|
2146
2276
|
return `[Pada baris ke-${this.interpreter.line}] Uh Oh, ini error sistem. Mohon laporkan agar diperbaiki. [ ${err} ]`;
|
|
2147
2277
|
}
|