2021-03-17 23:04:36 +00:00
|
|
|
import 'dart:collection';
|
|
|
|
import 'dart:io';
|
|
|
|
import 'dart:math';
|
2021-05-14 06:11:50 +00:00
|
|
|
import 'package:angel3_combinator/angel3_combinator.dart';
|
2021-03-17 23:04:36 +00:00
|
|
|
import 'package:string_scanner/string_scanner.dart';
|
|
|
|
import 'package:tuple/tuple.dart';
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
var expr = reference();
|
|
|
|
var symbols = <String, dynamic>{};
|
|
|
|
|
|
|
|
void registerFunction(String name, int nArgs, Function(List<num>) f) {
|
2021-05-14 06:11:50 +00:00
|
|
|
symbols[name] = Tuple2(nArgs, f);
|
2021-03-17 23:04:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
registerFunction('**', 2, (args) => pow(args[0], args[1]));
|
|
|
|
registerFunction('*', 2, (args) => args[0] * args[1]);
|
|
|
|
registerFunction('/', 2, (args) => args[0] / args[1]);
|
|
|
|
registerFunction('%', 2, (args) => args[0] % args[1]);
|
|
|
|
registerFunction('+', 2, (args) => args[0] + args[1]);
|
|
|
|
registerFunction('-', 2, (args) => args[0] - args[1]);
|
|
|
|
registerFunction('.', 1, (args) => args[0].toDouble());
|
|
|
|
registerFunction('print', 1, (args) {
|
|
|
|
print(args[0]);
|
|
|
|
return args[0];
|
|
|
|
});
|
|
|
|
|
2021-05-14 06:11:50 +00:00
|
|
|
var number =
|
|
|
|
match(RegExp(r'[0-9]+(\.[0-9]+)?'), errorMessage: 'Expected a number.')
|
|
|
|
.map((r) => num.parse(r.span!.text));
|
2021-03-17 23:04:36 +00:00
|
|
|
|
|
|
|
var id = match(
|
2021-05-14 06:11:50 +00:00
|
|
|
RegExp(
|
2021-03-17 23:04:36 +00:00
|
|
|
r'[A-Za-z_!\\$",\\+-\\./:;\\?<>%&\\*@\[\]\\{\}\\|`\\^~][A-Za-z0-9_!\\$",\\+-\\./:;\\?<>%&\*@\[\]\\{\}\\|`\\^~]*'),
|
|
|
|
errorMessage: 'Expected an ID')
|
2021-05-02 04:12:43 +00:00
|
|
|
.map((r) => symbols[r.span!.text] ??=
|
|
|
|
throw "Undefined symbol: '${r.span!.text}'");
|
2021-03-17 23:04:36 +00:00
|
|
|
|
|
|
|
var atom = number.castDynamic().or(id);
|
|
|
|
|
|
|
|
var list = expr.space().times(2, exact: false).map((r) {
|
|
|
|
try {
|
|
|
|
var out = [];
|
2021-05-14 06:11:50 +00:00
|
|
|
var q = Queue.from(r.value!.reversed);
|
2021-03-17 23:04:36 +00:00
|
|
|
|
|
|
|
while (q.isNotEmpty) {
|
|
|
|
var current = q.removeFirst();
|
2021-05-18 13:15:28 +00:00
|
|
|
if (current is! Tuple2) {
|
2021-03-17 23:04:36 +00:00
|
|
|
out.insert(0, current);
|
2021-05-18 13:15:28 +00:00
|
|
|
} else {
|
2021-03-17 23:04:36 +00:00
|
|
|
var args = [];
|
2021-05-18 13:15:28 +00:00
|
|
|
for (var i = 0; i < (current.item1 as num); i++) {
|
2021-03-17 23:04:36 +00:00
|
|
|
args.add(out.removeLast());
|
2021-05-18 13:15:28 +00:00
|
|
|
}
|
2021-03-17 23:04:36 +00:00
|
|
|
out.add(current.item2(args));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return out.length == 1 ? out.first : out;
|
|
|
|
} catch (_) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
expr.parser = longest([
|
|
|
|
list,
|
|
|
|
atom,
|
|
|
|
expr.parenthesized(),
|
|
|
|
]); //list | atom | expr.parenthesized();
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
stdout.write('> ');
|
2021-03-18 00:00:56 +00:00
|
|
|
var line = stdin.readLineSync()!;
|
2021-05-14 06:11:50 +00:00
|
|
|
var result = expr.parse(SpanScanner(line));
|
2021-03-17 23:04:36 +00:00
|
|
|
|
|
|
|
if (result.errors.isNotEmpty) {
|
|
|
|
for (var error in result.errors) {
|
|
|
|
print(error.toolString);
|
|
|
|
print(error.message);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
print(result.value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|