mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 08:44:20 +03:00
Добавлен beautifier
This commit is contained in:
parent
d2a159bb45
commit
66415a6c31
@ -1,6 +1,7 @@
|
|||||||
package com.annimon.ownlang;
|
package com.annimon.ownlang;
|
||||||
|
|
||||||
import com.annimon.ownlang.exceptions.LexerException;
|
import com.annimon.ownlang.exceptions.LexerException;
|
||||||
|
import com.annimon.ownlang.parser.Beautifier;
|
||||||
import com.annimon.ownlang.parser.Lexer;
|
import com.annimon.ownlang.parser.Lexer;
|
||||||
import com.annimon.ownlang.parser.Parser;
|
import com.annimon.ownlang.parser.Parser;
|
||||||
import com.annimon.ownlang.parser.SourceLoader;
|
import com.annimon.ownlang.parser.SourceLoader;
|
||||||
@ -38,6 +39,7 @@ public final class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean showTokens = false, showAst = false, showMeasurements = false;
|
boolean showTokens = false, showAst = false, showMeasurements = false;
|
||||||
|
boolean beautifyMode = false;
|
||||||
String input = null;
|
String input = null;
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
switch (args[i]) {
|
switch (args[i]) {
|
||||||
@ -45,6 +47,11 @@ public final class Main {
|
|||||||
case "--showast":
|
case "--showast":
|
||||||
showAst = true;
|
showAst = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "-b":
|
||||||
|
case "--beautify":
|
||||||
|
beautifyMode = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case "-t":
|
case "-t":
|
||||||
case "--showtokens":
|
case "--showtokens":
|
||||||
@ -76,6 +83,10 @@ public final class Main {
|
|||||||
if (input == null) {
|
if (input == null) {
|
||||||
throw new IllegalArgumentException("Empty input");
|
throw new IllegalArgumentException("Empty input");
|
||||||
}
|
}
|
||||||
|
if (beautifyMode) {
|
||||||
|
System.out.println(Beautifier.beautify(input));
|
||||||
|
return;
|
||||||
|
}
|
||||||
run(input, showTokens, showAst, showMeasurements);
|
run(input, showTokens, showAst, showMeasurements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
286
src/com/annimon/ownlang/parser/Beautifier.java
Normal file
286
src/com/annimon/ownlang/parser/Beautifier.java
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
package com.annimon.ownlang.parser;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class Beautifier {
|
||||||
|
|
||||||
|
public static String beautify(String input) {
|
||||||
|
return new Beautifier(input).beautify();
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum OperatorMode {
|
||||||
|
SPACES, RSPACES, TRIM, RTRIM, AS_SOURCE,
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String OPERATOR_CHARS = "+-*/%()[]=<>!&|.,^~?:";
|
||||||
|
|
||||||
|
private static final Map<String, OperatorMode> OPERATORS;
|
||||||
|
static {
|
||||||
|
OPERATORS = new HashMap<>();
|
||||||
|
OPERATORS.put("+", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("-", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("*", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("/", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("%", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("(", OperatorMode.AS_SOURCE);
|
||||||
|
OPERATORS.put(")", OperatorMode.AS_SOURCE);
|
||||||
|
OPERATORS.put("[", OperatorMode.AS_SOURCE);
|
||||||
|
OPERATORS.put("]", OperatorMode.AS_SOURCE);
|
||||||
|
OPERATORS.put("=", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("<", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put(">", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put(".", OperatorMode.TRIM);
|
||||||
|
OPERATORS.put(",", OperatorMode.RSPACES);
|
||||||
|
OPERATORS.put("^", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("~", OperatorMode.RTRIM);
|
||||||
|
OPERATORS.put("?", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put(":", OperatorMode.SPACES);
|
||||||
|
|
||||||
|
OPERATORS.put("!", OperatorMode.RTRIM);
|
||||||
|
OPERATORS.put("&", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("|", OperatorMode.SPACES);
|
||||||
|
|
||||||
|
OPERATORS.put("==", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("!=", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("<=", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put(">=", OperatorMode.SPACES);
|
||||||
|
|
||||||
|
OPERATORS.put("+=", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("-=", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("*=", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("/=", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("%=", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("&=", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("^=", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("|=", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("::=", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("<<=", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put(">>=", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put(">>>=", OperatorMode.SPACES);
|
||||||
|
|
||||||
|
OPERATORS.put("++", OperatorMode.AS_SOURCE);
|
||||||
|
OPERATORS.put("--", OperatorMode.AS_SOURCE);
|
||||||
|
|
||||||
|
OPERATORS.put("::", OperatorMode.AS_SOURCE);
|
||||||
|
|
||||||
|
OPERATORS.put("&&", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put("||", OperatorMode.SPACES);
|
||||||
|
|
||||||
|
OPERATORS.put("<<", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put(">>", OperatorMode.SPACES);
|
||||||
|
OPERATORS.put(">>>", OperatorMode.SPACES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String input;
|
||||||
|
private final int length;
|
||||||
|
|
||||||
|
private final StringBuilder beautifiedCode, buffer;
|
||||||
|
|
||||||
|
private int pos;
|
||||||
|
private int indentLevel;
|
||||||
|
|
||||||
|
public Beautifier(String input) {
|
||||||
|
this.input = input;
|
||||||
|
length = input.length();
|
||||||
|
beautifiedCode = new StringBuilder();
|
||||||
|
buffer = new StringBuilder();
|
||||||
|
|
||||||
|
indentLevel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String beautify() {
|
||||||
|
while (pos < length) {
|
||||||
|
final char current = peek(0);
|
||||||
|
if (current == '"') processText();
|
||||||
|
else if (current == '`') processExtendedWord();
|
||||||
|
else if (OPERATOR_CHARS.indexOf(current) != -1) {
|
||||||
|
processOperator();
|
||||||
|
} else switch (current) {
|
||||||
|
case '{':
|
||||||
|
indentLevel += 2;
|
||||||
|
addSpaceToLeft();
|
||||||
|
beautifiedCode.append(current);
|
||||||
|
newLineStrict();
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
indentLevel -= 2;
|
||||||
|
trimLeft();
|
||||||
|
addToLeft('\n');
|
||||||
|
indent();
|
||||||
|
beautifiedCode.append(current);
|
||||||
|
newLineStrict();
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
newLineStrict();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
beautifiedCode.append(current);
|
||||||
|
next();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return beautifiedCode.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processText() {
|
||||||
|
int index = pos + 1;
|
||||||
|
while ((index = 1 + input.indexOf('"', index)) != -1) {
|
||||||
|
if (input.charAt(index - 1) != '\\') {
|
||||||
|
skipTo(index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processExtendedWord() {
|
||||||
|
skipTo("`");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processComment() {
|
||||||
|
skipTo("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processMultilineComment() {
|
||||||
|
skipTo("*/");
|
||||||
|
newLineStrict();
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processOperator() {
|
||||||
|
char current = peek(0);
|
||||||
|
if (current == '/') {
|
||||||
|
if (peek(1) == '/') {
|
||||||
|
processComment();
|
||||||
|
return;
|
||||||
|
} else if (peek(1) == '*') {
|
||||||
|
processMultilineComment();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clearBuffer();
|
||||||
|
while (true) {
|
||||||
|
final String text = buffer.toString();
|
||||||
|
if (!OPERATORS.containsKey(text + current) && !text.isEmpty()) {
|
||||||
|
final OperatorMode mode = OPERATORS.get(text);
|
||||||
|
switch (mode) {
|
||||||
|
case SPACES:
|
||||||
|
addSpaceToLeft();
|
||||||
|
beautifiedCode.append(buffer);
|
||||||
|
addSpaceToRight();
|
||||||
|
break;
|
||||||
|
case RSPACES:
|
||||||
|
beautifiedCode.append(buffer);
|
||||||
|
addSpaceToRight();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AS_SOURCE:
|
||||||
|
beautifiedCode.append(buffer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTRIM:
|
||||||
|
beautifiedCode.append(buffer);
|
||||||
|
trimRight();
|
||||||
|
break;
|
||||||
|
case TRIM:
|
||||||
|
trimLeft();
|
||||||
|
beautifiedCode.append(buffer);
|
||||||
|
trimRight();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buffer.append(current);
|
||||||
|
current = next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void trimLeft() {
|
||||||
|
while (isSpace(last())) {
|
||||||
|
beautifiedCode.setLength(beautifiedCode.length() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void trimRight() {
|
||||||
|
while (isSpace(peek(0))) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addSpaceToLeft() {
|
||||||
|
addToLeft(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addSpaceToRight() {
|
||||||
|
if (peek(0) != ' ') {
|
||||||
|
beautifiedCode.append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addToLeft(char ch) {
|
||||||
|
if (last() != ch) {
|
||||||
|
beautifiedCode.append(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSpace(char ch) {
|
||||||
|
return " ".indexOf(ch) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void newLineStrict() {
|
||||||
|
beautifiedCode.append(System.lineSeparator());
|
||||||
|
indent();
|
||||||
|
do {
|
||||||
|
next();
|
||||||
|
} while (Character.isWhitespace(peek(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void indent() {
|
||||||
|
indent(indentLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void indent(int count) {
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
beautifiedCode.append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void skipTo(String text) {
|
||||||
|
int index = input.indexOf(text, pos);
|
||||||
|
if (index == -1) {
|
||||||
|
index = length - 1;
|
||||||
|
} else {
|
||||||
|
index += text.length();
|
||||||
|
}
|
||||||
|
skipTo(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void skipTo(int position) {
|
||||||
|
beautifiedCode.append(input.substring(pos, position));
|
||||||
|
pos += (position - pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
private char last() {
|
||||||
|
return beautifiedCode.charAt(beautifiedCode.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearBuffer() {
|
||||||
|
buffer.setLength(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private char next() {
|
||||||
|
pos++;
|
||||||
|
return peek(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private char peek(int relativePosition) {
|
||||||
|
final int position = pos + relativePosition;
|
||||||
|
if (position >= length) return '\0';
|
||||||
|
return input.charAt(position);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user