-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathexpression-formatter.ts
More file actions
127 lines (109 loc) · 3.12 KB
/
expression-formatter.ts
File metadata and controls
127 lines (109 loc) · 3.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
* Copyright (c) 2017 MolQL contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import Expression from '../../mini-lisp/expression'
const { isLiteral, isArgumentsArray } = Expression;
export default function format(e: Expression) {
const writer = new Writer();
_format(e, writer);
return writer.getStr();
}
class Writer {
private value: string[] = [];
private currentLineLength = 0;
private prefixLength = 0;
private _prefix: string = '';
private localPrefix: string = '';
private setLocal() {
this.localPrefix = ' ';
}
newline() {
this.value.push(`\n${this._prefix}${this.localPrefix}`);
this.currentLineLength = 0;
}
push() {
this.value.push('(');
this.currentLineLength = 0;
this.localPrefix = '';
this.prefixLength += 2;
this._prefix = new Array(this.prefixLength + 1).join(' ');
}
pop() {
this.value.push(')');
this.prefixLength -= 2;
this._prefix = new Array(this.prefixLength + 1).join(' ');
}
append(str: string) {
if (!this.currentLineLength) {
this.value.push(str);
this.currentLineLength = str.length;
} else if (this.currentLineLength + this.prefixLength + this.localPrefix.length + str.length < 80) {
this.value.push(str);
this.currentLineLength += str.length;
} else {
this.setLocal();
this.newline();
this.value.push(str);
this.currentLineLength = str.length;
}
}
whitespace() {
if (this.currentLineLength + this.prefixLength + this.localPrefix.length + 1 < 80) {
this.value.push(' ');
}
}
getStr() {
return this.value.join('');
}
}
function _format(e: Expression, writer: Writer) {
if (isLiteral(e)) {
if (typeof e === 'string' && (/\s/.test(e) || !e.length)) writer.append(`\`${e}\``);
else writer.append(`${e}`);
return;
}
writer.push();
_format(e.head, writer);
if (!e.args) {
writer.pop();
return;
}
if (isArgumentsArray(e.args)) {
let prevLiteral = true;
for (const a of e.args) {
if (isLiteral(a)) {
if (prevLiteral) writer.whitespace();
else writer.newline();
prevLiteral = true;
} else {
prevLiteral = false;
writer.newline();
}
_format(a, writer);
}
writer.pop();
return;
}
const keys = Object.keys(e.args);
if (!keys.length) {
writer.pop();
return;
}
if (keys.length === 1 && isLiteral(e.args[keys[0]])) {
writer.whitespace()
writer.append(`:${keys[0]}`);
writer.whitespace();
_format(e.args[keys[0]], writer);
writer.pop();
return;
}
for (const a of keys) {
writer.newline();
writer.append(`:${a}`);
writer.whitespace();
_format(e.args[a], writer);
}
writer.pop();
}