Skip to content

Commit 66415a6

Browse files
committed
Добавлен beautifier
1 parent d2a159b commit 66415a6

File tree

2 files changed

+297
-0
lines changed

2 files changed

+297
-0
lines changed

src/com/annimon/ownlang/Main.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.annimon.ownlang;
22

33
import com.annimon.ownlang.exceptions.LexerException;
4+
import com.annimon.ownlang.parser.Beautifier;
45
import com.annimon.ownlang.parser.Lexer;
56
import com.annimon.ownlang.parser.Parser;
67
import com.annimon.ownlang.parser.SourceLoader;
@@ -38,13 +39,19 @@ public static void main(String[] args) throws IOException {
3839
}
3940

4041
boolean showTokens = false, showAst = false, showMeasurements = false;
42+
boolean beautifyMode = false;
4143
String input = null;
4244
for (int i = 0; i < args.length; i++) {
4345
switch (args[i]) {
4446
case "-a":
4547
case "--showast":
4648
showAst = true;
4749
break;
50+
51+
case "-b":
52+
case "--beautify":
53+
beautifyMode = true;
54+
break;
4855

4956
case "-t":
5057
case "--showtokens":
@@ -76,6 +83,10 @@ public static void main(String[] args) throws IOException {
7683
if (input == null) {
7784
throw new IllegalArgumentException("Empty input");
7885
}
86+
if (beautifyMode) {
87+
System.out.println(Beautifier.beautify(input));
88+
return;
89+
}
7990
run(input, showTokens, showAst, showMeasurements);
8091
}
8192

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
package com.annimon.ownlang.parser;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
/**
7+
*
8+
* @author aNNiMON
9+
*/
10+
public final class Beautifier {
11+
12+
public static String beautify(String input) {
13+
return new Beautifier(input).beautify();
14+
}
15+
16+
private enum OperatorMode {
17+
SPACES, RSPACES, TRIM, RTRIM, AS_SOURCE,
18+
}
19+
20+
private static final String OPERATOR_CHARS = "+-*/%()[]=<>!&|.,^~?:";
21+
22+
private static final Map<String, OperatorMode> OPERATORS;
23+
static {
24+
OPERATORS = new HashMap<>();
25+
OPERATORS.put("+", OperatorMode.SPACES);
26+
OPERATORS.put("-", OperatorMode.SPACES);
27+
OPERATORS.put("*", OperatorMode.SPACES);
28+
OPERATORS.put("/", OperatorMode.SPACES);
29+
OPERATORS.put("%", OperatorMode.SPACES);
30+
OPERATORS.put("(", OperatorMode.AS_SOURCE);
31+
OPERATORS.put(")", OperatorMode.AS_SOURCE);
32+
OPERATORS.put("[", OperatorMode.AS_SOURCE);
33+
OPERATORS.put("]", OperatorMode.AS_SOURCE);
34+
OPERATORS.put("=", OperatorMode.SPACES);
35+
OPERATORS.put("<", OperatorMode.SPACES);
36+
OPERATORS.put(">", OperatorMode.SPACES);
37+
OPERATORS.put(".", OperatorMode.TRIM);
38+
OPERATORS.put(",", OperatorMode.RSPACES);
39+
OPERATORS.put("^", OperatorMode.SPACES);
40+
OPERATORS.put("~", OperatorMode.RTRIM);
41+
OPERATORS.put("?", OperatorMode.SPACES);
42+
OPERATORS.put(":", OperatorMode.SPACES);
43+
44+
OPERATORS.put("!", OperatorMode.RTRIM);
45+
OPERATORS.put("&", OperatorMode.SPACES);
46+
OPERATORS.put("|", OperatorMode.SPACES);
47+
48+
OPERATORS.put("==", OperatorMode.SPACES);
49+
OPERATORS.put("!=", OperatorMode.SPACES);
50+
OPERATORS.put("<=", OperatorMode.SPACES);
51+
OPERATORS.put(">=", OperatorMode.SPACES);
52+
53+
OPERATORS.put("+=", OperatorMode.SPACES);
54+
OPERATORS.put("-=", OperatorMode.SPACES);
55+
OPERATORS.put("*=", OperatorMode.SPACES);
56+
OPERATORS.put("/=", OperatorMode.SPACES);
57+
OPERATORS.put("%=", OperatorMode.SPACES);
58+
OPERATORS.put("&=", OperatorMode.SPACES);
59+
OPERATORS.put("^=", OperatorMode.SPACES);
60+
OPERATORS.put("|=", OperatorMode.SPACES);
61+
OPERATORS.put("::=", OperatorMode.SPACES);
62+
OPERATORS.put("<<=", OperatorMode.SPACES);
63+
OPERATORS.put(">>=", OperatorMode.SPACES);
64+
OPERATORS.put(">>>=", OperatorMode.SPACES);
65+
66+
OPERATORS.put("++", OperatorMode.AS_SOURCE);
67+
OPERATORS.put("--", OperatorMode.AS_SOURCE);
68+
69+
OPERATORS.put("::", OperatorMode.AS_SOURCE);
70+
71+
OPERATORS.put("&&", OperatorMode.SPACES);
72+
OPERATORS.put("||", OperatorMode.SPACES);
73+
74+
OPERATORS.put("<<", OperatorMode.SPACES);
75+
OPERATORS.put(">>", OperatorMode.SPACES);
76+
OPERATORS.put(">>>", OperatorMode.SPACES);
77+
}
78+
79+
private final String input;
80+
private final int length;
81+
82+
private final StringBuilder beautifiedCode, buffer;
83+
84+
private int pos;
85+
private int indentLevel;
86+
87+
public Beautifier(String input) {
88+
this.input = input;
89+
length = input.length();
90+
beautifiedCode = new StringBuilder();
91+
buffer = new StringBuilder();
92+
93+
indentLevel = 0;
94+
}
95+
96+
public String beautify() {
97+
while (pos < length) {
98+
final char current = peek(0);
99+
if (current == '"') processText();
100+
else if (current == '`') processExtendedWord();
101+
else if (OPERATOR_CHARS.indexOf(current) != -1) {
102+
processOperator();
103+
} else switch (current) {
104+
case '{':
105+
indentLevel += 2;
106+
addSpaceToLeft();
107+
beautifiedCode.append(current);
108+
newLineStrict();
109+
break;
110+
case '}':
111+
indentLevel -= 2;
112+
trimLeft();
113+
addToLeft('\n');
114+
indent();
115+
beautifiedCode.append(current);
116+
newLineStrict();
117+
break;
118+
case '\n':
119+
newLineStrict();
120+
break;
121+
default:
122+
beautifiedCode.append(current);
123+
next();
124+
break;
125+
}
126+
}
127+
return beautifiedCode.toString();
128+
}
129+
130+
private void processText() {
131+
int index = pos + 1;
132+
while ((index = 1 + input.indexOf('"', index)) != -1) {
133+
if (input.charAt(index - 1) != '\\') {
134+
skipTo(index);
135+
return;
136+
}
137+
}
138+
}
139+
140+
private void processExtendedWord() {
141+
skipTo("`");
142+
}
143+
144+
private void processComment() {
145+
skipTo("\n");
146+
}
147+
148+
private void processMultilineComment() {
149+
skipTo("*/");
150+
newLineStrict();
151+
pos--;
152+
}
153+
154+
private void processOperator() {
155+
char current = peek(0);
156+
if (current == '/') {
157+
if (peek(1) == '/') {
158+
processComment();
159+
return;
160+
} else if (peek(1) == '*') {
161+
processMultilineComment();
162+
return;
163+
}
164+
}
165+
clearBuffer();
166+
while (true) {
167+
final String text = buffer.toString();
168+
if (!OPERATORS.containsKey(text + current) && !text.isEmpty()) {
169+
final OperatorMode mode = OPERATORS.get(text);
170+
switch (mode) {
171+
case SPACES:
172+
addSpaceToLeft();
173+
beautifiedCode.append(buffer);
174+
addSpaceToRight();
175+
break;
176+
case RSPACES:
177+
beautifiedCode.append(buffer);
178+
addSpaceToRight();
179+
break;
180+
181+
case AS_SOURCE:
182+
beautifiedCode.append(buffer);
183+
break;
184+
185+
case RTRIM:
186+
beautifiedCode.append(buffer);
187+
trimRight();
188+
break;
189+
case TRIM:
190+
trimLeft();
191+
beautifiedCode.append(buffer);
192+
trimRight();
193+
break;
194+
}
195+
return;
196+
}
197+
buffer.append(current);
198+
current = next();
199+
}
200+
}
201+
202+
203+
private void trimLeft() {
204+
while (isSpace(last())) {
205+
beautifiedCode.setLength(beautifiedCode.length() - 1);
206+
}
207+
}
208+
209+
private void trimRight() {
210+
while (isSpace(peek(0))) {
211+
next();
212+
}
213+
}
214+
215+
private void addSpaceToLeft() {
216+
addToLeft(' ');
217+
}
218+
219+
private void addSpaceToRight() {
220+
if (peek(0) != ' ') {
221+
beautifiedCode.append(' ');
222+
}
223+
}
224+
225+
private void addToLeft(char ch) {
226+
if (last() != ch) {
227+
beautifiedCode.append(ch);
228+
}
229+
}
230+
231+
private boolean isSpace(char ch) {
232+
return " ".indexOf(ch) != -1;
233+
}
234+
235+
private void newLineStrict() {
236+
beautifiedCode.append(System.lineSeparator());
237+
indent();
238+
do {
239+
next();
240+
} while (Character.isWhitespace(peek(0)));
241+
}
242+
243+
private void indent() {
244+
indent(indentLevel);
245+
}
246+
247+
private void indent(int count) {
248+
for (int i = 0; i < count; i++) {
249+
beautifiedCode.append(' ');
250+
}
251+
}
252+
253+
private void skipTo(String text) {
254+
int index = input.indexOf(text, pos);
255+
if (index == -1) {
256+
index = length - 1;
257+
} else {
258+
index += text.length();
259+
}
260+
skipTo(index);
261+
}
262+
263+
private void skipTo(int position) {
264+
beautifiedCode.append(input.substring(pos, position));
265+
pos += (position - pos);
266+
}
267+
268+
private char last() {
269+
return beautifiedCode.charAt(beautifiedCode.length() - 1);
270+
}
271+
272+
private void clearBuffer() {
273+
buffer.setLength(0);
274+
}
275+
276+
private char next() {
277+
pos++;
278+
return peek(0);
279+
}
280+
281+
private char peek(int relativePosition) {
282+
final int position = pos + relativePosition;
283+
if (position >= length) return '\0';
284+
return input.charAt(position);
285+
}
286+
}

0 commit comments

Comments
 (0)