package parser;
import models.objectOrientedTransfer.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.*;
public class Parser {
public TokenStream tokenStream;
public static final String LEFT_CURLY_BRACKET = "{";
public static final String RIGHT_CURLY_BRACKET = "}";
public static final String LEFT_CURLY_BRACKET_REGX = "\\{";
public static final String RIGHT_CURLY_BRACKET_REGX = "\\}";
public static final String LEFT_SQUARE_BRACKET = "[";
public static final String RIGHT_SQUARE_BRACKET = "]";
public static final String LEFT_SQUARE_BRACKET_REGX = "\\[";
public static final String RIGHT_SQUARE_BRACKET_REGX = "\\]";
public static final String COMMA = ",";
public static final String COLON = ":";
public static final String DOUBLE_QUOT = "\"";
protected static List<ReferenceEdge> srcEdges = new ArrayList<>();
protected static List<ReferenceEdge> dstEdges = new ArrayList<>();
protected static Map<String, ObjectNode> objectNodeMap = new HashMap<>();
protected static PushPullValue transferStyle;
protected static MultiplicityValue multiplicityValue;
public Parser() {
Scanner sc = new Scanner(System.in);
StringBuilder s = new StringBuilder();
System.out.println("Jsonをはりつけてください");
while (true) {
String S = sc.nextLine();
if (S.equals("")) {
break;
}
s.append(S);
}
tokenStream = new TokenStream();
tokenStream.addLine(s.toString());
}
public Parser(final BufferedReader reader) {
this.tokenStream = new TokenStream();
try {
String line;
while ((line = reader.readLine()) != null) {
tokenStream.addLine(line);
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public Value getValue() {
return parseValue(tokenStream);
}
public Value parseValue(TokenStream tokenStream) {
if (tokenStream.checkNext().equals(LEFT_CURLY_BRACKET)) {
tokenStream.next();
JsonValue jsonValue = parseJsonValue(tokenStream);
if (tokenStream.checkNext().equals(RIGHT_CURLY_BRACKET)) {
tokenStream.next();
return jsonValue;
} else {
throw new RuntimeException(String.valueOf(tokenStream.getLine()));
}
} else if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) {
tokenStream.next();
ArrayValue arrayValue = parseArrayValue(tokenStream);
if (tokenStream.checkNext().equals(RIGHT_SQUARE_BRACKET)) {
tokenStream.next();
return arrayValue;
} else {
throw new RuntimeException(String.valueOf(tokenStream.getLine()));
}
} else if (tokenStream.checkNext().equals(DOUBLE_QUOT)) {
tokenStream.next();
StringValue stringValue = parseStringValue(tokenStream);
if (tokenStream.checkNext().equals(DOUBLE_QUOT)) {
tokenStream.next();
return stringValue;
} else {
throw new RuntimeException(String.valueOf(tokenStream.getLine()));
}
} else if (Character.isDigit(tokenStream.checkNext().charAt(0))) {
return parseIntegerValue(tokenStream);
}
throw new RuntimeException(String.valueOf(tokenStream.getLine()));
}
public JsonValue parseJsonValue(TokenStream tokenStream) {
JsonValue jsonValue = new JsonValue();
//要素が0
if (tokenStream.checkNext().equals(RIGHT_CURLY_BRACKET)) {
return jsonValue;
}
while (true) {
//key
Value keyValue = parseValue(tokenStream);
if (!(keyValue instanceof StringValue)) {
throw new RuntimeException(String.valueOf(tokenStream.getLine()));
}
expect(tokenStream, COLON);
tokenStream.next();//COLON
//value
Value value = parseValue(tokenStream);
jsonValue.setJsonValue((StringValue) keyValue, value);
if (!tokenStream.checkNext().equals(COMMA)) {
break;
}
tokenStream.next();
}
return jsonValue;
}
public ArrayValue parseArrayValue(TokenStream tokenStream) {
ArrayValue arrayValue = new ArrayValue();
//要素が0
if (tokenStream.checkNext().equals(RIGHT_SQUARE_BRACKET)) {
return arrayValue;
}
while (true) {
Value value = parseValue(tokenStream);
arrayValue.addValue(value);
if (!tokenStream.checkNext().equals(COMMA)) {
break;
}
tokenStream.next();//COMMA
}
return arrayValue;
}
public IntegerValue parseIntegerValue(TokenStream tokenStream) {
IntegerValue integerValue = new IntegerValue();
StringBuilder stringBuilder = new StringBuilder();
while (Character.isDigit(tokenStream.checkNext().charAt(0))) {
stringBuilder.append(tokenStream.next());
}
integerValue.setIntValue(Integer.valueOf(stringBuilder.toString()));
return integerValue;
}
public StringValue parseStringValue(TokenStream tokenStream) {
StringValue stringValue = new StringValue();
StringBuilder stringBuilder = new StringBuilder();
while (!tokenStream.checkNext().equals(DOUBLE_QUOT)) {
stringBuilder.append(tokenStream.next());
}
stringValue.setStringValue(stringBuilder.toString());
return stringValue;
}
public void expect(TokenStream tokenStream, String expect) {
if (!tokenStream.checkNext().equals(expect)) {
throw new RuntimeException("expect" + expect + "but" + tokenStream.checkNext() + " line" + tokenStream.getLine());
}
}
public static class TokenStream {
private ArrayList<ArrayList<Token>> tokens = new ArrayList<>();
private ArrayList<String> lines = new ArrayList<>();
private int line = 0;
private int n = 0;
public TokenStream() {
line = 0;
n = 0;
}
public void addLine(String line) {
lines.add(line);
line = line.trim();
ArrayList<Token> tokenList = splitByDoubleQuotation(line);
tokenList = splitBy(tokenList, COMMA, COMMA);
tokenList = splitBy(tokenList, COLON, COLON);
tokenList = splitBy(tokenList, LEFT_CURLY_BRACKET, LEFT_CURLY_BRACKET_REGX);
tokenList = splitBy(tokenList, RIGHT_CURLY_BRACKET, RIGHT_CURLY_BRACKET_REGX);
tokenList = splitBy(tokenList, LEFT_SQUARE_BRACKET, LEFT_SQUARE_BRACKET_REGX);
tokenList = splitBy(tokenList, RIGHT_SQUARE_BRACKET, RIGHT_SQUARE_BRACKET_REGX);
tokens.add(tokenList);
}
private ArrayList<Token> splitBy(final List<Token> tokens, final String delimiter, final String delimiterRegx) {
ArrayList<Token> newTokens = new ArrayList<>();
for (Token token : tokens) {
if (token.isAtomic()) {
newTokens.add(token);
} else {
String[] splitTokens = token.split(delimiterRegx);
boolean fFirstToken = true;
for (String t : splitTokens) {
if (!fFirstToken) {
newTokens.add(new Token(delimiter, true));
}
if (t.length() > 0) {
newTokens.add(new Token(t));
}
fFirstToken = false;
}
while (token.endsWith(delimiter)) {
newTokens.add(new Token(delimiter, true));
token = token.substring(0, token.length() - 1);
}
}
}
return newTokens;
}
private ArrayList<Token> splitByDoubleQuotation(String line) {
ArrayList<Token> newTokens = new ArrayList<>();
String[] tokens = line.split(DOUBLE_QUOT);
boolean fFirstToken = true;
for (int i = 0; i < tokens.length; i++) {
String token = tokens[i];
if (!fFirstToken) {
newTokens.add(new Token(DOUBLE_QUOT, true));
}
if (!fFirstToken || token.length() > 0) {
if (i % 2 == 0) {
for (String t : token.split("[ \t]")) {
newTokens.add(new Token(t));
}
} else {
// string literal
newTokens.add(new Token(token, true));
}
}
fFirstToken = false;
}
if (line.endsWith(DOUBLE_QUOT)) {
newTokens.add(new Token(DOUBLE_QUOT, true));
}
return newTokens;
}
public String next() {
if (line >= tokens.size()) return null;
while (n >= tokens.get(line).size()) {
line++;
n = 0;
if (line >= tokens.size()) return null;
}
String token = tokens.get(line).get(n).getTokenStr();
n++;
return token;
}
public String checkNext() {
if (line >= tokens.size()) return null;
while (n >= tokens.get(line).size()) {
line++;
n = 0;
if (line >= tokens.size()) return null;
}
return tokens.get(line).get(n).getTokenStr();
}
public boolean hasNext() {
if (line >= tokens.size()) return false;
while (n >= tokens.get(line).size()) {
line++;
n = 0;
if (line >= tokens.size()) return false;
}
return true;
}
public int getLine() {
return line;
}
public String getSourceText(int from, int to) {
String text = "";
for (int l = from; l <= to; l++) {
text += lines.get(l) + "\n";
}
return text;
}
}
public static class Token {
String token;
boolean isAtomic = false;
public Token(String token) {
this.token = token;
}
public Token(String token, boolean isAtomic) {
this.token = token;
this.isAtomic = isAtomic;
}
public String getTokenStr() {
return token;
}
public boolean isAtomic() {
return isAtomic;
}
public String[] split(String delimiterRegx) {
return token.split(delimiterRegx);
}
public boolean endsWith(String delimiter) {
return token.endsWith(delimiter);
}
public int length() {
return token.length();
}
public Token substring(int beginIdx, int endIdx) {
return new Token(token.substring(beginIdx, endIdx));
}
}
}