blob: 074307cfb158a154ce6af11d101ba7bc88e53efd [file] [log] [blame] [edit]
#!/usr/bin/env dart
import 'dart:convert';
import 'dart:io';
import 'package:pretty/pretty.dart' as pretty;
const int LPAREN = 40;
const int RPAREN = 41;
List<String> tokenize(String input) {
List<String> tokens = <String>[];
for (String s in input.split(' ')) {
int i = 0, j = s.length;
// Add leading parentheses as tokens.
for (; i < s.length && s.codeUnitAt(i) == LPAREN; ++i) {
tokens.add('(');
}
// Count trailing parentheses.
for (; j > i && s.codeUnitAt(j - 1) == RPAREN; --j);
// Add the token itself unless empty.
if (i < j) {
tokens.add(s.substring(i, j));
}
// Add the trailing parentheses.
for (; j < s.length; ++j) {
tokens.add(')');
}
}
return tokens;
}
int position;
List<String> tokens;
buildSexp() {
String s = tokens[position++];
return s == '(' ? buildList() : s;
}
List buildList() {
List result = [];
while (tokens[position] != ')') {
result.add(buildSexp());
}
++position;
return result;
}
pretty.Document sexp2Doc(expression) {
if (expression is String) return pretty.text(expression);
if ((expression as List).isEmpty) return pretty.text('()');
Iterable<pretty.Document> docs = (expression as List).map(sexp2Doc);
pretty.Document result = pretty.text('(') + docs.first;
pretty.Document children =
docs.skip(1).fold(pretty.empty,
(doc0, doc1) => doc0 + pretty.line + doc1);
result += (children + pretty.text(')')).nest(2);
return result.group;
}
void processString(String input) {
position = 0;
tokens = tokenize(input);
print(sexp2Doc(buildSexp()).render(120));
}
main() {
stdin.transform(ASCII.decoder).listen(processString);
}