diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ba02942 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "RDLProofSystem"] + path = RDLProofSystem + url = http://nitta-lab-www.is.konan-u.ac.jp/gitbucket/git/nitta-lab/RDLProofSystem.git diff --git a/RDLProofSystem b/RDLProofSystem new file mode 160000 index 0000000..0381337 --- /dev/null +++ b/RDLProofSystem @@ -0,0 +1 @@ +Subproject commit 0381337f440eba77ac594c81a06122f8ef9b8d54 diff --git a/build.gradle b/build.gradle index fc13742..43909be 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,7 @@ dependencies { implementation project(':RDLApplicationRuntime') + implementation project(':RDLProofSystem') testImplementation platform('org.junit:junit-bom:5.10.0') testImplementation 'org.junit.jupiter:junit-jupiter' } diff --git a/settings.gradle b/settings.gradle index 2a4a31c..cb5e93d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,4 @@ rootProject.name = 'RDLCanvas' -include 'RDLApplicationRuntime' \ No newline at end of file +include 'RDLApplicationRuntime' +include 'RDLProofSystem' \ No newline at end of file diff --git a/src/main/java/org/ntlab/rdlcanvas/Main.java b/src/main/java/org/ntlab/rdlcanvas/Main.java index 7f648e8..a5bddc1 100644 --- a/src/main/java/org/ntlab/rdlcanvas/Main.java +++ b/src/main/java/org/ntlab/rdlcanvas/Main.java @@ -1,7 +1,22 @@ package org.ntlab.rdlcanvas; +import org.ntlab.rdlcanvas.parser.JsonValue; +import org.ntlab.rdlcanvas.parser.Parser; +import org.ntlab.rdlcanvas.parser.StringValue; +import org.ntlab.rdlcanvas.parser.Value; + +import java.util.Map; + public class Main { public static void main(String[] args) { + Parser parser = new Parser(); + Value value = parser.getValue(); + System.out.println(value.toString()); +// Map map = ((JsonValue)value).getJson(); +// for (StringValue key : map.keySet()){ +// String keyName = key.getStringValue(); +// System.out.println(keyName); +// } } } diff --git a/src/main/java/org/ntlab/rdlcanvas/parser/ArrayValue.java b/src/main/java/org/ntlab/rdlcanvas/parser/ArrayValue.java new file mode 100644 index 0000000..66f1029 --- /dev/null +++ b/src/main/java/org/ntlab/rdlcanvas/parser/ArrayValue.java @@ -0,0 +1,24 @@ +package org.ntlab.rdlcanvas.parser; + +import java.util.ArrayList; +import java.util.List; + +public class ArrayValue extends Value { + List values = new ArrayList<>(); + + // 与えられたValue(String, Integer, Array, Json)を配列に追加 + public void addValue(Value value) { + values.add(value); + } + + // 保持している値(Value)のリストを返す + public List getValues() { + return values; + } + + // 文字列として値を返す + @Override + public String toString() { + return values.toString(); + } +} diff --git a/src/main/java/org/ntlab/rdlcanvas/parser/IntegerValue.java b/src/main/java/org/ntlab/rdlcanvas/parser/IntegerValue.java new file mode 100644 index 0000000..feb5bc4 --- /dev/null +++ b/src/main/java/org/ntlab/rdlcanvas/parser/IntegerValue.java @@ -0,0 +1,21 @@ +package org.ntlab.rdlcanvas.parser; + +public class IntegerValue extends Value { + Integer intValue; + + // 与えられた整数を代入するコンストラクタ + public void setIntValue(Integer intValue) { + this.intValue = intValue; + } + + // 保持している値(Integer)を返す + public Integer getIntValue() { + return intValue; + } + + // 文字列として値を返す + @Override + public String toString() { + return String.valueOf(intValue); + } +} diff --git a/src/main/java/org/ntlab/rdlcanvas/parser/JsonValue.java b/src/main/java/org/ntlab/rdlcanvas/parser/JsonValue.java new file mode 100644 index 0000000..ae29b55 --- /dev/null +++ b/src/main/java/org/ntlab/rdlcanvas/parser/JsonValue.java @@ -0,0 +1,40 @@ +package org.ntlab.rdlcanvas.parser; + +import java.util.HashMap; +import java.util.Map; + +public class JsonValue extends Value { + //JsonのKeyとValueの対応を保持するMap(Keyは文字列、ValueはValueクラスのインスタンス) + Map json = new HashMap<>(); + + //KeyとValueの対応(Map丸ごと)を返す + public Map getJson() { + return json; + } + + // 与えられたKeyに対応するValueを返す + public Value getValue(StringValue key) { + return json.get(key); + } + + // 与えられたKeyとValueの対応をMapに追加 + public void setJsonValue(StringValue key, Value value) { + json.put(key, value); + } + + // MapからJson文字列を生成する。形式は{key1 : value1 , key2 : value2 , ...} + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("{"); + for (StringValue key : json.keySet()) { + stringBuilder.append(key).append(" : "); + stringBuilder.append(json.get(key)).append(" ,"); + } + if (stringBuilder.length() >= 2 && stringBuilder.substring(stringBuilder.length() - 2, stringBuilder.length()).equals(" ,")) { + stringBuilder.delete(stringBuilder.length() - 2, stringBuilder.length()); + } + stringBuilder.append(" }"); + return stringBuilder.toString(); + } +} diff --git a/src/main/java/org/ntlab/rdlcanvas/parser/Parser.java b/src/main/java/org/ntlab/rdlcanvas/parser/Parser.java index fd22ade..f9e7895 100644 --- a/src/main/java/org/ntlab/rdlcanvas/parser/Parser.java +++ b/src/main/java/org/ntlab/rdlcanvas/parser/Parser.java @@ -1,4 +1,331 @@ package org.ntlab.rdlcanvas.parser; +import org.ntlab.rdlcanvas.parser.exceptions.ExpectedArrayValue; +import org.ntlab.rdlcanvas.parser.exceptions.ExpectedJsonValue; +import org.ntlab.rdlcanvas.parser.exceptions.ExpectedStringValue; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + 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 = "\""; + + // Json文字列を標準入力から受け取るコンストラクタ + 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()); + } + + // Json文字列をBufferedReader(ファイル)から受け取るコンストラクタ + 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(); + } + } + + // 入力されたJson文字列からValueとしてパースされた後のJson文字列を生成する + public Value getValue() { + return parseValue(tokenStream); + } + + // 値のパース(構文解析) + public Value parseValue(TokenStream tokenStream) throws ExpectedJsonValue, ExpectedArrayValue, ExpectedStringValue { + // 次のトークンを見て、どの型の値をパースするかを決定する + // "{"のとき、JsonValue, "["のとき、ArrayValue, "\""のとき、StringValueとしてパースへ流す + 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 ExpectedJsonValue(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 ExpectedArrayValue(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 ExpectedStringValue(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) throws ExpectedStringValue { + 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 ExpectedStringValue(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> tokens = new ArrayList<>(); + private ArrayList 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 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 splitBy(final List tokens, final String delimiter, final String delimiterRegx) { + ArrayList 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 splitByDoubleQuotation(String line) { + ArrayList 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)); + } + } } diff --git a/src/main/java/org/ntlab/rdlcanvas/parser/StringValue.java b/src/main/java/org/ntlab/rdlcanvas/parser/StringValue.java new file mode 100644 index 0000000..649b82c --- /dev/null +++ b/src/main/java/org/ntlab/rdlcanvas/parser/StringValue.java @@ -0,0 +1,21 @@ +package org.ntlab.rdlcanvas.parser; + +public class StringValue extends Value { + String stringValue; + + // 与えられた文字列を保持するコンストラクタ + public void setStringValue(String stringValue) { + this.stringValue = stringValue; + } + + // 保持している文字列を返す + public String getStringValue() { + return stringValue; + } + + // 文字列をtoStringメゾットとして返す + @Override + public String toString() { + return stringValue; + } +} diff --git a/src/main/java/org/ntlab/rdlcanvas/parser/Value.java b/src/main/java/org/ntlab/rdlcanvas/parser/Value.java new file mode 100644 index 0000000..a59c891 --- /dev/null +++ b/src/main/java/org/ntlab/rdlcanvas/parser/Value.java @@ -0,0 +1,7 @@ +package org.ntlab.rdlcanvas.parser; + +// Jsonを構成する値(String, Integer, Array, Json)の抽象クラス +public abstract class Value { + + public abstract String toString(); +} diff --git a/src/main/java/org/ntlab/rdlcanvas/parser/exceptions/ExpectedArrayValue.java b/src/main/java/org/ntlab/rdlcanvas/parser/exceptions/ExpectedArrayValue.java new file mode 100644 index 0000000..bd821c2 --- /dev/null +++ b/src/main/java/org/ntlab/rdlcanvas/parser/exceptions/ExpectedArrayValue.java @@ -0,0 +1,7 @@ +package org.ntlab.rdlcanvas.parser.exceptions; + +public class ExpectedArrayValue extends RuntimeException { + public ExpectedArrayValue(String message) { + super(message); + } +} diff --git a/src/main/java/org/ntlab/rdlcanvas/parser/exceptions/ExpectedJsonValue.java b/src/main/java/org/ntlab/rdlcanvas/parser/exceptions/ExpectedJsonValue.java new file mode 100644 index 0000000..62ee71a --- /dev/null +++ b/src/main/java/org/ntlab/rdlcanvas/parser/exceptions/ExpectedJsonValue.java @@ -0,0 +1,7 @@ +package org.ntlab.rdlcanvas.parser.exceptions; + +public class ExpectedJsonValue extends RuntimeException { + public ExpectedJsonValue(String message) { + super(message); + } +} diff --git a/src/main/java/org/ntlab/rdlcanvas/parser/exceptions/ExpectedStringValue.java b/src/main/java/org/ntlab/rdlcanvas/parser/exceptions/ExpectedStringValue.java new file mode 100644 index 0000000..77a34cc --- /dev/null +++ b/src/main/java/org/ntlab/rdlcanvas/parser/exceptions/ExpectedStringValue.java @@ -0,0 +1,7 @@ +package org.ntlab.rdlcanvas.parser.exceptions; + +public class ExpectedStringValue extends RuntimeException { + public ExpectedStringValue(String message) { + super(message); + } +}