diff --git a/RDLProofSystem b/RDLProofSystem index 895f156..9d09c2a 160000 --- a/RDLProofSystem +++ b/RDLProofSystem @@ -1 +1 @@ -Subproject commit 895f1569549c3c761bede6d23ea96711b59cd60c +Subproject commit 9d09c2a0a43b6b6efd4baadbe6f3ca81b5bdb4a4 diff --git a/src/main/java/org/ntlab/rdlworkbench/Main.java b/src/main/java/org/ntlab/rdlworkbench/Main.java index 48adc9a..56afc33 100644 --- a/src/main/java/org/ntlab/rdlworkbench/Main.java +++ b/src/main/java/org/ntlab/rdlworkbench/Main.java @@ -1,8 +1,5 @@ package org.ntlab.rdlworkbench; -import org.ntlab.rdl.applicationruntime.ApplicationRuntime; -import org.ntlab.rdl.swingadapter.SwingAdapter; - public class Main { public static void main(String[] args) { diff --git a/src/main/java/org/ntlab/rdlworkbench/models/RDLSpec.java b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpec.java new file mode 100644 index 0000000..7a71c09 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpec.java @@ -0,0 +1,90 @@ +package org.ntlab.rdlworkbench.models; + +import java.util.*; + +public class RDLSpec { + private Map resourceMap; + private List rdlSpecStatements; + private Map> rdlSpecResourceConstantMap; + + public RDLSpec() { + resourceMap = new HashMap<>(); + rdlSpecStatements = new ArrayList<>(); + rdlSpecResourceConstantMap = new HashMap<>(); + } + + public void addRDLSpecResourceDeclaration(String name, int order, StructuralType structuralType, ValueType valueType) { + resourceMap.put(name, new RDLSpecResourceDeclaration(name, order, structuralType, valueType)); + } + + public void addRDLSpecResourceDeclaration(String name, int order, ValueType valueType) { + resourceMap.put(name, new RDLSpecResourceDeclaration(name, order, valueType)); + } + + public RDLSpecResourceDeclaration getRDLSpecResourceDeclaration(String name) { + if (!resourceMap.containsKey(name)) { + return null; + } + return resourceMap.get(name); + } + + public RDLSpecResourceConstant getConstant(String value, ValueType valueType) { + if (rdlSpecResourceConstantMap.containsKey(value)) { + if (rdlSpecResourceConstantMap.get(value).containsKey(valueType)) { + return rdlSpecResourceConstantMap.get(value).get(valueType); + } else { + rdlSpecResourceConstantMap.get(value).put(valueType,new RDLSpecResourceConstant(value, valueType)); + } + } else { + rdlSpecResourceConstantMap.put(value, new HashMap<>()); + rdlSpecResourceConstantMap.get(value).put(valueType, new RDLSpecResourceConstant(value, valueType)); + } + return rdlSpecResourceConstantMap.get(value).get(valueType); + } + + public RDLSpecResourceConstant getTrue() { + if (!rdlSpecResourceConstantMap.containsKey("true")) { + rdlSpecResourceConstantMap.put("true", new HashMap<>()); + if (!rdlSpecResourceConstantMap.get("true").containsKey(RDLSpecLang.typeBoolean)) { + rdlSpecResourceConstantMap.get("true").put(RDLSpecLang.typeBoolean, new RDLSpecResourceConstant("true", RDLSpecLang.typeBoolean)); + } + } + return rdlSpecResourceConstantMap.get("true").get(RDLSpecLang.typeBoolean); + } + + public RDLSpecResourceConstant getFalse() { + if (!rdlSpecResourceConstantMap.containsKey("false")) { + rdlSpecResourceConstantMap.put("false", new HashMap<>()); + if (!rdlSpecResourceConstantMap.get("false").containsKey(RDLSpecLang.typeBoolean)) { + rdlSpecResourceConstantMap.get("false").put(RDLSpecLang.typeBoolean, new RDLSpecResourceConstant("false", RDLSpecLang.typeBoolean)); + } + } + return rdlSpecResourceConstantMap.get("false").get(RDLSpecLang.typeBoolean); + } + + public void addRDLSpecStatement(RDLSpecStatement rdlSpecStatement) { + rdlSpecStatements.add(rdlSpecStatement); + rdlSpecStatements.sort(Comparator.comparing(obj -> { + if (obj.isRDLSpecResourceDeclaration()) { + return 1; + } + if (obj.isRDLSpecInitialization()) { + return 2; + } + return 3; + })); + } + + public List getRDLSpecStatements() { + return rdlSpecStatements; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < rdlSpecStatements.size(); i++) { + sb.append(rdlSpecStatements.get(i)).append("\n"); + } + return sb.toString(); + } +} diff --git a/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecDependency.java b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecDependency.java new file mode 100644 index 0000000..1855017 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecDependency.java @@ -0,0 +1,19 @@ +package org.ntlab.rdlworkbench.models; + +import models.terms.Dependency; +import models.terms.EvaluatableTerm; +import models.terms.RDLTerm; + +import java.util.List; + +public class RDLSpecDependency extends Dependency { + + public RDLSpecDependency(RDLSpecDependency dependingTerm, List dependedTerms) { + super(dependingTerm, dependedTerms.stream().map(item -> (EvaluatableTerm) item).toList()); + } + + public RDLSpecDependency(RDLSpecEvaluatableTerm dependingTerm, List dependedTerms) { + super((RDLTerm) dependingTerm, dependedTerms.stream().map(item -> (EvaluatableTerm) item).toList()); + } + +} diff --git a/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecDependencyFormula.java b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecDependencyFormula.java new file mode 100644 index 0000000..08029d3 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecDependencyFormula.java @@ -0,0 +1,20 @@ +package org.ntlab.rdlworkbench.models; + +import models.formulas.DependencyFormula; + +public class RDLSpecDependencyFormula extends DependencyFormula implements RDLSpecStatement { + + public RDLSpecDependencyFormula(RDLSpecDependency dependency) { + super(dependency); + } + + @Override + public boolean isRDLSpecInitialization() { + return false; + } + + @Override + public boolean isRDLSpecResourceDeclaration() { + return false; + } +} diff --git a/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecDependencyTerm.java b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecDependencyTerm.java new file mode 100644 index 0000000..363a328 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecDependencyTerm.java @@ -0,0 +1,61 @@ +package org.ntlab.rdlworkbench.models; + +import exceptions.SyntaxException; +import models.terms.DependencyTerm; +import models.terms.EvaluatableTerm; + +import java.util.List; + +public class RDLSpecDependencyTerm extends DependencyTerm implements Typable, RDLSpecEvaluatableTerm { + private StructuralType structuralType; + private ValueType valuableType; + + public RDLSpecDependencyTerm(RDLSpecEvaluatableTerm dependingTerm, List dependedTerms, List argumentTerms) { + super((EvaluatableTerm) dependingTerm, dependedTerms.stream().map(item -> (EvaluatableTerm) item).toList(), argumentTerms.stream().map(item -> (EvaluatableTerm) item).toList()); + this.structuralType = ((Typable) dependingTerm).getStructuralType(); + this.valuableType = ((Typable) dependingTerm).getValueType(); + + for (int i = 0; i < dependedTerms.size(); i ++) { + if (!typeChecker(dependedTerms.get(i), argumentTerms.get(i))) { + throw new SyntaxException("the type is different"); + } + } + } + + private boolean typeChecker(RDLSpecEvaluatableTerm left, RDLSpecEvaluatableTerm right) { + StructuralType leftStructuralType = ((Typable) left).getStructuralType(); + StructuralType rightStructuralType = ((Typable) right).getStructuralType(); + + if (leftStructuralType == StructuralType.structure || leftStructuralType == StructuralType.map) { + if (leftStructuralType == rightStructuralType) { + return true; + } else { + return false; + } + } else { + ValueType leftValueType = ((Typable) left).getValueType(); + ValueType rightValueType = ((Typable) right).getValueType(); + + if (leftValueType.equals(rightValueType)) { + return true; + } else { + return false; + } + } + } + + @Override + public StructuralType getStructuralType() { + return structuralType; + } + + @Override + public ValueType getValueType() { + return valuableType; + } + + @Override + public boolean isDependencyTerm() { + return true; + } +} diff --git a/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecEquationFormula.java b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecEquationFormula.java new file mode 100644 index 0000000..ab3fbbb --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecEquationFormula.java @@ -0,0 +1,47 @@ +package org.ntlab.rdlworkbench.models; + +import exceptions.SyntaxException; +import models.formulas.EquationFormula; +import models.terms.EvaluatableTerm; + +public class RDLSpecEquationFormula extends EquationFormula implements RDLSpecStatement { + + public RDLSpecEquationFormula(RDLSpecEvaluatableTerm leftSideHand, RDLSpecEvaluatableTerm rightSideHand) { + super((EvaluatableTerm) leftSideHand, (EvaluatableTerm) rightSideHand); + if (!typeChecker(leftSideHand, rightSideHand)) { + throw new SyntaxException("the type is different"); + } + } + + private boolean typeChecker(RDLSpecEvaluatableTerm left, RDLSpecEvaluatableTerm right) { + StructuralType leftStructuralType = ((Typable) left).getStructuralType(); + StructuralType rightStructuralType = ((Typable) right).getStructuralType(); + + if (leftStructuralType == StructuralType.structure || leftStructuralType == StructuralType.map) { + if (leftStructuralType == rightStructuralType) { + return true; + } else { + return false; + } + } else { + ValueType leftValueType = ((Typable) left).getValueType(); + ValueType rightValueType = ((Typable) right).getValueType(); + + if (leftValueType.equals(rightValueType)) { + return true; + } else { + return false; + } + } + } + + @Override + public boolean isRDLSpecInitialization() { + return false; + } + + @Override + public boolean isRDLSpecResourceDeclaration() { + return false; + } +} diff --git a/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecEvaluatableTerm.java b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecEvaluatableTerm.java new file mode 100644 index 0000000..d045f6f --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecEvaluatableTerm.java @@ -0,0 +1,5 @@ +package org.ntlab.rdlworkbench.models; + +public interface RDLSpecEvaluatableTerm { + boolean isDependencyTerm(); +} diff --git a/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecInitialization.java b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecInitialization.java new file mode 100644 index 0000000..cb1f48c --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecInitialization.java @@ -0,0 +1,47 @@ +package org.ntlab.rdlworkbench.models; + +public class RDLSpecInitialization implements RDLSpecStatement { + RDLSpecEvaluatableTerm leftSideHand; + RDLSpecEvaluatableTerm rightSideHand; + + public RDLSpecInitialization(RDLSpecEvaluatableTerm leftSideHand, RDLSpecEvaluatableTerm rightSideHand) { + this.leftSideHand = leftSideHand; + this.rightSideHand = rightSideHand; + } + + public RDLSpecEvaluatableTerm getLeftSideHand() { + return leftSideHand; + } + + public RDLSpecEvaluatableTerm getRightSideHand() { + return rightSideHand; + } + + @Override + public boolean isRDLSpecInitialization() { + return true; + } + + @Override + public boolean isRDLSpecResourceDeclaration() { + return false; + } + + @Override + public String toString() { + return leftSideHand + " := " + rightSideHand; + } + + @Override + public boolean equals(Object another) { + if (!(another instanceof RDLSpecInitialization anotherInitialization)) { + return false; + } + return leftSideHand.equals(anotherInitialization.getLeftSideHand()) && rightSideHand.equals(anotherInitialization.getRightSideHand()); + } + + @Override + public int hashCode() { + return toString().hashCode(); + } +} diff --git a/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecLang.java b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecLang.java new file mode 100644 index 0000000..230176d --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecLang.java @@ -0,0 +1,8 @@ +package org.ntlab.rdlworkbench.models; + +public class RDLSpecLang { + public static final ValueType typeString = new ValueType("string"); + public static final ValueType typeInt = new ValueType("int"); + public static final ValueType typeBoolean = new ValueType("boolean"); + public static final ValueType typeDouble = new ValueType("double"); +} diff --git a/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecResource.java b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecResource.java new file mode 100644 index 0000000..88f36d1 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecResource.java @@ -0,0 +1,49 @@ +package org.ntlab.rdlworkbench.models; + +import models.terms.Resource; + +public class RDLSpecResource extends Resource implements Typable, RDLSpecEvaluatableTerm { + private StructuralType structuralType; + private ValueType valueType; + + public RDLSpecResource(String name, int order, StructuralType structuralType, ValueType valueType) { + super(name, order); + if (!(structuralType == StructuralType.structure || structuralType == StructuralType.id || structuralType == StructuralType.primitive || structuralType == StructuralType.map || structuralType == StructuralType.value)) { + throw new IllegalArgumentException(structuralType + " is not expected structural type."); + } + + if (structuralType == StructuralType.id || structuralType == StructuralType.primitive || structuralType == StructuralType.value) { + if (!(valueType.equals(RDLSpecLang.typeInt) || valueType.equals(RDLSpecLang.typeDouble) || valueType.equals(RDLSpecLang.typeString) || valueType.equals(RDLSpecLang.typeBoolean))) { + throw new IllegalArgumentException(structuralType + " is not expected valuable Type."); + } + } else { + if (valueType != null) { + throw new IllegalArgumentException("It does not have a type"); + } + } + + this.structuralType = structuralType; + this.valueType = valueType; + } + + public RDLSpecResource(String name, int order, ValueType valueType) { + super(name, order); + structuralType = StructuralType.primitive; + this.valueType = valueType; + } + + @Override + public StructuralType getStructuralType() { + return structuralType; + } + + @Override + public ValueType getValueType() { + return valueType; + } + + @Override + public boolean isDependencyTerm() { + return false; + } +} diff --git a/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecResourceConstant.java b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecResourceConstant.java new file mode 100644 index 0000000..b682ba2 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecResourceConstant.java @@ -0,0 +1,38 @@ +package org.ntlab.rdlworkbench.models; + +import models.terms.ResourceConstant; + +public class RDLSpecResourceConstant extends ResourceConstant implements Typable, RDLSpecEvaluatableTerm { + private StructuralType structuralType; + private ValueType valueType; + + public RDLSpecResourceConstant(String value, ValueType valueType) { + super(value); + this.structuralType = StructuralType.primitive; + this.valueType = valueType; + } + + @Override + public StructuralType getStructuralType() { + return structuralType; + } + + @Override + public ValueType getValueType() { + return valueType; + } + + @Override + public boolean isDependencyTerm() { + return false; + } + + @Override + public String toString() { + if (valueType.getName().equals("string")) { + return "\"" + getName() + "\""; + } else { + return getName(); + } + } +} diff --git a/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecResourceDeclaration.java b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecResourceDeclaration.java new file mode 100644 index 0000000..c488099 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecResourceDeclaration.java @@ -0,0 +1,78 @@ +package org.ntlab.rdlworkbench.models; + +import java.util.*; + +public class RDLSpecResourceDeclaration implements RDLSpecStatement { + private RDLSpecResource resource; + private RDLSpecResource primedResource; + + public RDLSpecResourceDeclaration(String name, int order, StructuralType structuralType, ValueType valueType) { + resource = new RDLSpecResource(name, order, structuralType, valueType); + if (structuralType == StructuralType.id) { + primedResource = new RDLSpecResource(name + "'", order, structuralType, valueType); + } else { + primedResource = null; + } + } + + public RDLSpecResourceDeclaration(String name, int order, ValueType valueType) { + resource = new RDLSpecResource(name, order, valueType); + primedResource = null; + } + + public RDLSpecResource getResource() { + return resource; + } + + public RDLSpecResource getPrimedResource() { + return primedResource; + } + + @Override + public boolean isRDLSpecInitialization() { + return false; + } + + @Override + public boolean isRDLSpecResourceDeclaration() { + return true; + } + + @Override + public boolean equals(Object another) { + if (!(another instanceof RDLSpecResourceDeclaration rdlSpecResourceDeclaration)) { + return false; + } + + if (rdlSpecResourceDeclaration.getResource().equals(resource) && ((rdlSpecResourceDeclaration.getPrimedResource() == null && primedResource == null) || rdlSpecResourceDeclaration.getPrimedResource().equals(primedResource))) { + return true; + } else { + return false; + } + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(resource).append("(").append(resource.getOrder()).append("):: "); + + if (resource.getStructuralType() == StructuralType.primitive) { + sb.append(resource.getValueType().getName()); + return sb.toString(); + } + + if (resource.getValueType() == null) { + sb.append(resource.getStructuralType()); + return sb.toString(); + } else { + sb.append(resource.getStructuralType()); + sb.append(", ").append(resource.getValueType().getName()); + return sb.toString(); + } + } +} diff --git a/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecStatement.java b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecStatement.java new file mode 100644 index 0000000..f9b3a09 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecStatement.java @@ -0,0 +1,6 @@ +package org.ntlab.rdlworkbench.models; + +public interface RDLSpecStatement { + boolean isRDLSpecResourceDeclaration(); + boolean isRDLSpecInitialization(); +} diff --git a/src/main/java/org/ntlab/rdlworkbench/models/StructuralType.java b/src/main/java/org/ntlab/rdlworkbench/models/StructuralType.java new file mode 100644 index 0000000..0dee3e4 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/StructuralType.java @@ -0,0 +1,26 @@ +package org.ntlab.rdlworkbench.models; + +public enum StructuralType { + id, + value, + structure, + map, + primitive; + + @Override + public String toString() { + switch (this) { + case id: + return "id"; + case value: + return "value"; + case structure: + return "struct"; + case map: + return "map"; + case primitive: + default: + return ""; + } + } +} diff --git a/src/main/java/org/ntlab/rdlworkbench/models/Typable.java b/src/main/java/org/ntlab/rdlworkbench/models/Typable.java new file mode 100644 index 0000000..f7dbbb8 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/Typable.java @@ -0,0 +1,7 @@ +package org.ntlab.rdlworkbench.models; + + +public interface Typable { + StructuralType getStructuralType(); + ValueType getValueType(); +} diff --git a/src/main/java/org/ntlab/rdlworkbench/models/ValueType.java b/src/main/java/org/ntlab/rdlworkbench/models/ValueType.java new file mode 100644 index 0000000..f989e11 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/ValueType.java @@ -0,0 +1,21 @@ +package org.ntlab.rdlworkbench.models; + +public class ValueType { + private String name; + + public ValueType(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ValueType)) { + return false; + } + return name.equals(((ValueType) obj).name); + } +} diff --git a/src/main/java/org/ntlab/rdlworkbench/rdlparser/RDLParser.java b/src/main/java/org/ntlab/rdlworkbench/rdlparser/RDLParser.java new file mode 100644 index 0000000..d2f0689 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/rdlparser/RDLParser.java @@ -0,0 +1,575 @@ +package org.ntlab.rdlworkbench.rdlparser; + +import org.ntlab.rdlworkbench.models.*; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.*; + +public class RDLParser { + public static TokenStream tokenStream; + 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 COLON_COLON = "::"; + public static final String COLON_EQUAL = ":="; + public static final String EQUAL = "="; + public static final String LEFT_BRACKET = "("; + public static final String RIGHT_BRACKET = ")"; + public static final String LEFT_BRACKET_REGX = "\\("; + public static final String RIGHT_BRACKET_REGX = "\\)"; + public static final String DOUBLE_QUOT = "\""; + public static final String PRIME = "'"; + public static final String ARROW = "->"; + + public RDLSpec parseRDL(final BufferedReader reader) { + RDLSpec rdlSpec = new RDLSpec(); + try { + String line; + while ((line = reader.readLine()) != null) { + tokenStream = new TokenStream(); + tokenStream.addLine(line); + if (line.contains(LEFT_BRACKET)) { + RDLSpecResourceDeclaration resourceDeclaration = parseResourceDeclaration(rdlSpec); + rdlSpec.addRDLSpecStatement(resourceDeclaration); + } else if (line.contains(COLON_EQUAL)) { + RDLSpecInitialization initialization = parseRDLSpecInitialization(rdlSpec); + rdlSpec.addRDLSpecStatement(initialization); + } else if (line.contains(EQUAL)) { + RDLSpecEquationFormula equationFormula = parseEquationFormula(rdlSpec); + rdlSpec.addRDLSpecStatement(equationFormula); + } else { + RDLSpecDependency dependency = parseDependency(rdlSpec); + RDLSpecDependencyFormula dependencyFormula = new RDLSpecDependencyFormula(dependency); + rdlSpec.addRDLSpecStatement(dependencyFormula); + } + } + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return rdlSpec; + } + + public RDLSpec parseRDL() { + Scanner sc = new Scanner(System.in); + RDLSpec rdlSpec = new RDLSpec(); + while (true) { + String S = sc.nextLine(); + if (S.equals("")) { + break; + } + + tokenStream = new TokenStream(); + tokenStream.addLine(S); + + if (S.contains(LEFT_BRACKET)) { + RDLSpecResourceDeclaration resourceDeclaration = parseResourceDeclaration(rdlSpec); + rdlSpec.addRDLSpecStatement(resourceDeclaration); + } else if (S.contains(COLON_EQUAL)) { + RDLSpecInitialization initialization = parseRDLSpecInitialization(rdlSpec); + rdlSpec.addRDLSpecStatement(initialization); + } else if (S.contains(EQUAL)) { + RDLSpecEquationFormula equationFormula = parseEquationFormula(rdlSpec); + rdlSpec.addRDLSpecStatement(equationFormula); + } else { + RDLSpecDependency dependency = parseDependency(rdlSpec); + RDLSpecDependencyFormula dependencyFormula = new RDLSpecDependencyFormula(dependency); + rdlSpec.addRDLSpecStatement(dependencyFormula); + } + } + return rdlSpec; + } + + private static RDLSpecInitialization parseRDLSpecInitialization(RDLSpec rdlSpec) { + RDLSpecEvaluatableTerm leftSideHand; + + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + leftSideHand = parseDependencyTerm(rdlSpec); + expect(RIGHT_SQUARE_BRACKET); + } else { + leftSideHand = parseResource(rdlSpec); + } + + expect(COLON_EQUAL); + RDLSpecEvaluatableTerm rightSideHand; + + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + rightSideHand = parseDependencyTerm(rdlSpec); + expect(RIGHT_SQUARE_BRACKET); + } else { + rightSideHand = parseResource(rdlSpec); + } + + return new RDLSpecInitialization(leftSideHand, rightSideHand); + } + + private static RDLSpecEquationFormula parseEquationFormula(RDLSpec rdlSpec) { + RDLSpecEvaluatableTerm leftEvaluatableTerm; + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + leftEvaluatableTerm = parseDependencyTerm(rdlSpec); + expect(RIGHT_SQUARE_BRACKET); + } else { + leftEvaluatableTerm = parseResource(rdlSpec); + } + + if (!(tokenStream.checkNext().equals(EQUAL))) { + throw new RuntimeException("Syntax Error"); + } else { + expect(EQUAL); + } + + RDLSpecEvaluatableTerm rightEvaluatableTerm; + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + rightEvaluatableTerm = parseDependencyTerm(rdlSpec); + expect(RIGHT_SQUARE_BRACKET); + } else { + rightEvaluatableTerm = parseResource(rdlSpec); + } + + return new RDLSpecEquationFormula(leftEvaluatableTerm, rightEvaluatableTerm); + } + + private static RDLSpecDependency parseDependency(RDLSpec rdlSpec) { + RDLSpecEvaluatableTerm dependingTerm = null; + RDLSpecDependency dependingTermDependency = null; + + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + tokenStream.markLine(); + try { + dependingTerm = parseDependencyTerm(rdlSpec); + } catch (RuntimeException e) { + tokenStream.recoverLastLine(); + dependingTermDependency = parseDependency(rdlSpec); + } + expect(RIGHT_SQUARE_BRACKET); + } else { + dependingTerm = parseResource(rdlSpec); + } + + expect(COLON); + + List dependedTerms = new ArrayList<>(); + while (true) { + RDLSpecEvaluatableTerm dependedTerm; + + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + dependedTerm = parseDependencyTerm(rdlSpec); + expect(RIGHT_SQUARE_BRACKET); + } else { + dependedTerm = parseResource(rdlSpec); + } + + dependedTerms.add(dependedTerm); + + if (tokenStream.checkNext() == null || !tokenStream.checkNext().equals(COMMA)) { + break; + } else { + expect(COMMA); + } + } + + if (dependingTerm != null) { + return new RDLSpecDependency(dependingTerm, dependedTerms); + } else { + return new RDLSpecDependency(dependingTermDependency, dependedTerms); + } + } + + private static RDLSpecEvaluatableTerm parseDependencyTerm(RDLSpec rdlSpec) { + RDLSpecEvaluatableTerm leftEvaluatableTerm; + + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + leftEvaluatableTerm = parseDependencyTerm(rdlSpec); + expect(RIGHT_SQUARE_BRACKET); + } else { + leftEvaluatableTerm = parseResource(rdlSpec); + } + + expect(COLON); + List dependedTerms = new ArrayList<>(); + List argumentTerms = new ArrayList<>(); + while (true) { + RDLSpecEvaluatableTerm dependedTerm; + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + dependedTerm = parseDependencyTerm(rdlSpec); + expect(RIGHT_SQUARE_BRACKET); + } else { + dependedTerm = parseResource(rdlSpec); + } + + expect(ARROW); + + RDLSpecEvaluatableTerm argTerm; + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + argTerm = parseDependencyTerm(rdlSpec); + expect(RIGHT_SQUARE_BRACKET); + } else { + argTerm = parseResource(rdlSpec); + } + + dependedTerms.add(dependedTerm); + argumentTerms.add(argTerm); + + if (!tokenStream.checkNext().equals(COMMA)) { + break; + } else { + expect(COMMA); + } + } + return new RDLSpecDependencyTerm(leftEvaluatableTerm, dependedTerms, argumentTerms); + } + + private static RDLSpecEvaluatableTerm parseResource(RDLSpec rdlSpec) { + if (tokenStream.checkNext().equals(DOUBLE_QUOT)) { + expect(DOUBLE_QUOT); + String name; + + if (tokenStream.checkNext().equals(DOUBLE_QUOT)) { + name = ""; + } else { + name = tokenStream.next(); + } + + expect(DOUBLE_QUOT); + return rdlSpec.getConstant(name, RDLSpecLang.typeString); + } + + String resourceName = tokenStream.next(); + + if (resourceName == null) { + throw new NullPointerException("need resource"); + } + + RDLSpecResource resource; + + if (resourceName.equals("true")) { + return rdlSpec.getTrue(); + } + + if (resourceName.equals("false")) { + return rdlSpec.getFalse(); + } + + if (isInt(resourceName)) { + return rdlSpec.getConstant(resourceName, RDLSpecLang.typeInt); + } + + if (!isInt(resourceName) && isDouble(resourceName)) { + return rdlSpec.getConstant(resourceName, RDLSpecLang.typeDouble); + } + + if (rdlSpec.getRDLSpecResourceDeclaration(resourceName) == null) { + throw new RuntimeException("resourceが存在しません : " + resourceName); + } + + if (tokenStream.checkNext() != null && tokenStream.checkNext().equals(PRIME)) { + //id型判定はresourceDeclarationクラスに書いた + expect(PRIME); + resource = rdlSpec.getRDLSpecResourceDeclaration(resourceName).getPrimedResource(); + } else { + resource = rdlSpec.getRDLSpecResourceDeclaration(resourceName).getResource(); + } + + return resource; + } + + private static RDLSpecResourceDeclaration parseResourceDeclaration(RDLSpec rdlSpec) { + String resourceName = tokenStream.next(); + + if (resourceName == null) { + throw new NullPointerException(); + } + + expect(LEFT_BRACKET); + //order + int order = expectDigit(tokenStream.next()); + expect(RIGHT_BRACKET); + expect(COLON_COLON); + + if (tokenStream.checkNext() == null) { + throw new NullPointerException("need type"); + } + + if (tokenStream.checkNext().equals("id")) { + String structuralType = tokenStream.next(); + expect(COMMA); + String valueType = tokenStream.next(); + rdlSpec.addRDLSpecResourceDeclaration(resourceName, order, StructuralType.id, new ValueType(valueType)); + return rdlSpec.getRDLSpecResourceDeclaration(resourceName); + } else if (tokenStream.checkNext().equals("struct")) { + String structuralType = tokenStream.next(); + rdlSpec.addRDLSpecResourceDeclaration(resourceName, order, StructuralType.structure, null); + return rdlSpec.getRDLSpecResourceDeclaration(resourceName); + } else { + String structuralType = "primitive"; + String valueType = tokenStream.next(); + + if (valueType == null) { + throw new NullPointerException("need valueType"); + } + + rdlSpec.addRDLSpecResourceDeclaration(resourceName, order, new ValueType(valueType)); + return rdlSpec.getRDLSpecResourceDeclaration(resourceName); + } + } + + private static boolean isDouble(String str) { + try { + Double.parseDouble(str); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + private static boolean isInt(String str) { + try { + Integer.parseInt(str); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + private static int expectDigit(String expectDigit) { + try { + return Integer.parseInt(expectDigit); + } catch (NumberFormatException e) { + throw new RuntimeException(e); + } + } + + private static void expect(String expect) { + if (tokenStream.checkNext() == null || !tokenStream.checkNext().equals(expect)) { + throw new RuntimeException("expect : " + expect + " but : " + tokenStream.checkNext() + "."); + } else { + tokenStream.next(); + } + } + + public static class TokenStream { + private ArrayList> tokens = new ArrayList<>(); + private ArrayList lines = new ArrayList<>(); + private int line = 0; + private int n = 0; + private ArrayDeque markLines = new ArrayDeque<>(); + private ArrayDeque markNs = new ArrayDeque<>(); + + public TokenStream() { + line = 0; + n = 0; + } + + public void addLine(String line) { + lines.add(line); + line = line.trim(); + ArrayList tokenList = splitByDoubleQuotation(line); + tokenList = splitBy(tokenList, COLON_EQUAL, COLON_EQUAL); + tokenList = splitBy(tokenList, COLON_COLON, COLON_COLON); + tokenList = splitBy(tokenList, EQUAL, EQUAL); + tokenList = splitBy(tokenList, COMMA, COMMA); + tokenList = splitBy(tokenList, COLON, COLON); + tokenList = splitBy(tokenList, LEFT_BRACKET, LEFT_BRACKET_REGX); + tokenList = splitBy(tokenList, RIGHT_BRACKET, RIGHT_BRACKET_REGX); + tokenList = splitBy(tokenList, LEFT_SQUARE_BRACKET, LEFT_SQUARE_BRACKET_REGX); + tokenList = splitBy(tokenList, RIGHT_SQUARE_BRACKET, RIGHT_SQUARE_BRACKET_REGX); + tokenList = splitBy(tokenList, PRIME, PRIME); + tokenList = splitBy(tokenList, ARROW, ARROW); + 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); + System.out.println(line); + 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)) { + int pos = line.length() - 1; + for (int i = line.length() - 1; i >= 0; i--) { + if (!(line.charAt(i) == '\"')) { + pos = i + 1; + break; + } + } + for (int i = pos; i < line.length(); i++) { + newTokens.add(new Token(DOUBLE_QUOT, true)); + if (i != line.length() - 1) { + newTokens.add(new Token("", 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 void markLine() { + markLines.add(line); + markNs.add(n); + } + + public void recoverLastLine() { + if (markLines.isEmpty()) { + throw new NullPointerException("mark is empty"); + } + line = markLines.pollLast(); + if (markNs.isEmpty()) { + throw new NullPointerException("mark is empty"); + } + n = markNs.pollLast(); + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + for (ArrayList tokenArrayList : tokens) { + for (Token token : tokenArrayList) { + str.append(token.toString() + "\n"); + } + } + return str.toString(); + } + + } + + 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)); + } + + @Override + public String toString() { + return token; + } + } +}