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/models/RDLSpecDependency.java b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecDependency.java new file mode 100644 index 0000000..1890648 --- /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.ArrayList; +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..aa7d0ef --- /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..d70f617 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecDependencyTerm.java @@ -0,0 +1,62 @@ +package org.ntlab.rdlworkbench.models; + +import exceptions.SyntaxException; +import models.algebra.Type; +import models.terms.DependencyTerm; +import models.terms.EvaluatableTerm; + +import java.util.List; + +public class RDLSpecDependencyTerm extends DependencyTerm implements Typable, RDLSpecEvaluatableTerm { + private Type structuralType; + private Type valuableType; + + public RDLSpecDependencyTerm(RDLSpecEvaluatableTerm dependingTerm, List terms) { + super((EvaluatableTerm) dependingTerm, terms.stream().map(item -> (EvaluatableTerm) item).toList()); + this.structuralType = ((Typable)dependingTerm).getStructuralType(); + this.valuableType = ((Typable)dependingTerm).getValuableType(); + + for (int i = 0; i < terms.size(); i += 2) { + if (!typeChecker(terms.get(i), terms.get(i+1))) { + throw new SyntaxException("the type is different"); + } + } + } + + private boolean typeChecker(RDLSpecEvaluatableTerm left, RDLSpecEvaluatableTerm right) { + String leftStructuralType = ((Typable)left).getStructuralType().getTypeName(); + String rightStructuralType = ((Typable)right).getStructuralType().getTypeName(); + + if (leftStructuralType.equals("struct") || leftStructuralType.equals("map")) { + if (leftStructuralType.equals(rightStructuralType)) { + return true; + } else { + return false; + } + } else { + String leftValuableType = ((Typable)left).getValuableType().getTypeName(); + String rightValuableType = ((Typable)right).getValuableType().getTypeName(); + + if (leftValuableType.equals(rightValuableType)) { + return true; + } else { + return false; + } + } + } + + @Override + public Type getStructuralType() { + return structuralType; + } + + @Override + public Type getValuableType() { + 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..c4c01b6 --- /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) { + String leftStructuralType = ((Typable)left).getStructuralType().getTypeName(); + String rightStructuralType = ((Typable)right).getStructuralType().getTypeName(); + + if (leftStructuralType.equals("struct") || leftStructuralType.equals("map")) { + if (leftStructuralType.equals(rightStructuralType)) { + return true; + } else { + return false; + } + } else { + String leftValuableType = ((Typable)left).getValuableType().getTypeName(); + String rightValuableType = ((Typable)right).getValuableType().getTypeName(); + + if (leftValuableType.equals(rightValuableType)) { + 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..81dc3e7 --- /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/RDLSpecResource.java b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecResource.java new file mode 100644 index 0000000..4aeb70d --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecResource.java @@ -0,0 +1,44 @@ +package org.ntlab.rdlworkbench.models; + +import models.algebra.Type; +import models.terms.Resource; + +public class RDLSpecResource extends Resource implements Typable, RDLSpecEvaluatableTerm { + private Type structuralType; + private Type valuableType; + + public RDLSpecResource(String name, int order, Type structuralType, Type valuableType) { + super(name, order); + if (!(structuralType.getTypeName().equals("struct") || structuralType.getTypeName().equals("id") || structuralType.getTypeName().equals("primitive") || structuralType.getTypeName().equals("map") || structuralType.getTypeName().equals("value"))) { + throw new IllegalArgumentException(structuralType.getTypeName() + " is not expected structural type."); + } + + if (structuralType.getTypeName().equals("id") || structuralType.getTypeName().equals("primitive") || structuralType.getTypeName().equals("value")) { + if (!(valuableType.getTypeName().equals("int") || valuableType.getTypeName().equals("double") || valuableType.getTypeName().equals("string") || valuableType.getTypeName().equals("boolean"))) { + throw new IllegalArgumentException(structuralType.getTypeName() + " is not expected valuable Type."); + } + } else { + if (valuableType != null) { + throw new IllegalArgumentException("It does not have a type"); + } + } + + this.structuralType = structuralType; + this.valuableType = valuableType; + } + + @Override + public Type getStructuralType() { + return structuralType; + } + + @Override + public Type getValuableType() { + return valuableType; + } + + @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..37819f5 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecResourceConstant.java @@ -0,0 +1,39 @@ +package org.ntlab.rdlworkbench.models; + +import models.algebra.Type; +import models.terms.ResourceConstant; + +public class RDLSpecResourceConstant extends ResourceConstant implements Typable, RDLSpecEvaluatableTerm { + private Type structuralType; + private Type valuableType; + + public RDLSpecResourceConstant(String name, Type structuralType, Type valuableType) { + super(name); + this.structuralType = structuralType; + this.valuableType = valuableType; + } + + @Override + public Type getStructuralType() { + return structuralType; + } + + @Override + public Type getValuableType() { + return valuableType; + } + + @Override + public boolean isDependencyTerm() { + return false; + } + + @Override + public String toString() { + if (valuableType.getTypeName().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..ccb6ab4 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/RDLSpecResourceDeclaration.java @@ -0,0 +1,80 @@ +package org.ntlab.rdlworkbench.models; + +import models.algebra.Type; + +import java.util.*; + +public class RDLSpecResourceDeclaration implements RDLSpecStatement{ + private Map resourceMap = new TreeMap<>(); + private Map primeResourceMap = new TreeMap<>(); + + public boolean containsResource(String name) { + return resourceMap.containsKey(name); + } + + public void putRDLSpecResource(String name, int order, Type structuralType, Type valuableType) { + resourceMap.put(name, new RDLSpecResource(name, order, structuralType, valuableType)); + if (structuralType.getTypeName().equals("id")) { + primeResourceMap.put(name, new RDLSpecResource(name + "'", order, structuralType, valuableType)); + } + } + + public RDLSpecResource getRDLSpecResource(String name, boolean isPrime) { + if (isPrime) { + if (!resourceMap.get(name).getStructuralType().getTypeName().equals("id")) { + throw new IllegalArgumentException("prime is only id type : " + name); + } + return primeResourceMap.get(name); + } else { + return resourceMap.get(name); + } + } + + public Map getResourceMap() { + return resourceMap; + } + + public Map getPrimeResourceMap() { + return primeResourceMap; + } + + @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; + } + + return resourceMap.equals(rdlSpecResourceDeclaration.getResourceMap()) && primeResourceMap.equals(rdlSpecResourceDeclaration.getPrimeResourceMap()); + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (String key : resourceMap.keySet()) { + RDLSpecResource resource = resourceMap.get(key); + sb.append(resource).append("(").append(resource.getOrder()).append("):: "); + sb.append(resource.getStructuralType().getTypeName()); + if (resource.getValuableType() != null) { + sb.append(", ").append(resource.getValuableType().getTypeName()).append("\n"); + } else { + sb.append("\n"); + } + } + 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/Typable.java b/src/main/java/org/ntlab/rdlworkbench/models/Typable.java new file mode 100644 index 0000000..2ca26c0 --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/models/Typable.java @@ -0,0 +1,8 @@ +package org.ntlab.rdlworkbench.models; + +import models.algebra.Type; + +public interface Typable { + Type getStructuralType(); + Type getValuableType(); +} 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..26c6eaf --- /dev/null +++ b/src/main/java/org/ntlab/rdlworkbench/rdlparser/RDLParser.java @@ -0,0 +1,606 @@ +package org.ntlab.rdlworkbench.rdlparser; + +import exceptions.SyntaxException; +import models.algebra.Type; +import models.formulas.*; +import models.terms.*; +import org.ntlab.rdlworkbench.models.*; + +import java.util.*; + +public class RDLParser { + static RDLSpecResourceDeclaration resourceDeclaration = new RDLSpecResourceDeclaration(); + static List statements = new ArrayList<>(); + 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 static void main(String[] args) { + Scanner sc = new Scanner(System.in); + while (true) { + String S = sc.nextLine(); + if (S.equals("")) { + break; + } + tokenStream = new TokenStream(); + tokenStream.addLine(S); + if (S.contains(LEFT_BRACKET)) { + RDLSpecResource resource = parseResourceDeclaration(); + } else if (S.contains(COLON_EQUAL)) { + RDLSpecInitialization initialization = parseRDLSpecInitialization(); + statements.add(initialization); + } else if (S.contains(EQUAL)) { + RDLSpecEquationFormula equationFormula = parseEquationFormula(); + statements.add(equationFormula); + } else { + RDLSpecDependency dependency = parseDependency(); + RDLSpecDependencyFormula dependencyFormula = new RDLSpecDependencyFormula(dependency); + statements.add(dependencyFormula); + } + } + statements.add(resourceDeclaration); + statements.sort(Comparator.comparing(obj -> { + if (obj.isRDLSpecResourceDeclaration()) { + return 1; + } + if (obj.isRDLSpecInitialization()) { + return 2; + } + return 3; + })); + for (int i = 0; i < statements.size(); i++) { + System.out.println(statements.get(i)); + } + } + + private static RDLSpecInitialization parseRDLSpecInitialization() { + RDLSpecEvaluatableTerm leftSideHand; + + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + leftSideHand = parseDependencyTerm(); + expect(RIGHT_SQUARE_BRACKET); + } else { + leftSideHand = parseResource(); + } + + expect(COLON_EQUAL); + RDLSpecEvaluatableTerm rightSideHand; + + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + rightSideHand = parseDependencyTerm(); + expect(RIGHT_SQUARE_BRACKET); + } else { + rightSideHand = parseResource(); + } + + return new RDLSpecInitialization(leftSideHand, rightSideHand); + } + + private static RDLSpecEquationFormula parseEquationFormula() { + RDLSpecEvaluatableTerm leftEvaluatableTerm; + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + leftEvaluatableTerm = parseDependencyTerm(); + expect(RIGHT_SQUARE_BRACKET); + } else { + leftEvaluatableTerm = parseResource(); + } + + 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(); + expect(RIGHT_SQUARE_BRACKET); + } else { + rightEvaluatableTerm = parseResource(); + } + + return new RDLSpecEquationFormula(leftEvaluatableTerm,rightEvaluatableTerm); + } + + private static RDLSpecDependency parseDependency() { + RDLSpecEvaluatableTerm dependingTerm = null; + RDLSpecDependency dependingTermDependency = null; + + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + tokenStream.markLine(); + try { + dependingTerm = parseDependencyTerm(); + } catch (RuntimeException e) { + tokenStream.backLastLine(); + dependingTermDependency = parseDependency(); + } + expect(RIGHT_SQUARE_BRACKET); + } else { + dependingTerm = parseResource(); + } + + expect(COLON); + + List dependedTerms = new ArrayList<>(); + while(true) { + RDLSpecEvaluatableTerm dependedTerm; + + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + dependedTerm = parseDependencyTerm(); + expect(RIGHT_SQUARE_BRACKET); + } else { + dependedTerm = parseResource(); + } + + 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 RDLTerm parseRDLTerm() { + RDLTerm leftEvaluatableTerm; + boolean isDependency = false; + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + leftEvaluatableTerm = parseRDLTerm(); + expect(RIGHT_SQUARE_BRACKET); + } else { + leftEvaluatableTerm = (RDLTerm) parseResource(); + } + + expect(COLON); + List terms = new ArrayList<>(); + + while (true) { + RDLSpecEvaluatableTerm dependedTerm; + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + dependedTerm = parseDependencyTerm(); + expect(RIGHT_SQUARE_BRACKET); + } else { + dependedTerm = parseResource(); + } + + if (tokenStream.checkNext().equals(ARROW)) { + expect(ARROW); + RDLSpecEvaluatableTerm argTerm; + + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + argTerm = parseDependencyTerm(); + expect(RIGHT_SQUARE_BRACKET); + } else { + argTerm = parseResource(); + } + + terms.add(dependedTerm); + terms.add(argTerm); + } else { + isDependency = true; + terms.add(dependedTerm); + } + + if (!tokenStream.checkNext().equals(COMMA)) { + break; + } else { + expect(COMMA); + } + } + + if (isDependency) { + if (leftEvaluatableTerm instanceof RDLSpecEvaluatableTerm) { + return new RDLSpecDependency((RDLSpecEvaluatableTerm) leftEvaluatableTerm, terms); + } + if (leftEvaluatableTerm instanceof RDLSpecDependency) { + return new RDLSpecDependency((RDLSpecDependency) leftEvaluatableTerm, terms); + } + throw new SyntaxException(); + } else { + return new RDLSpecDependencyTerm((RDLSpecEvaluatableTerm) leftEvaluatableTerm, terms); + } + } + + private static RDLSpecEvaluatableTerm parseDependencyTerm() { + RDLSpecEvaluatableTerm leftEvaluatableTerm; + + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + leftEvaluatableTerm = parseDependencyTerm(); + expect(RIGHT_SQUARE_BRACKET); + } else { + leftEvaluatableTerm = parseResource(); + } + + expect(COLON); + List terms = new ArrayList<>(); + + while (true) { + RDLSpecEvaluatableTerm dependedTerm; + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + dependedTerm = parseDependencyTerm(); + expect(RIGHT_SQUARE_BRACKET); + } else { + dependedTerm = parseResource(); + } + + expect(ARROW); + + RDLSpecEvaluatableTerm argTerm; + if (tokenStream.checkNext().equals(LEFT_SQUARE_BRACKET)) { + expect(LEFT_SQUARE_BRACKET); + argTerm = parseDependencyTerm(); + expect(RIGHT_SQUARE_BRACKET); + } else { + argTerm = parseResource(); + } + + terms.add(dependedTerm); + terms.add(argTerm); + + if (!tokenStream.checkNext().equals(COMMA)) { + break; + } else { + expect(COMMA); + } + } + return new RDLSpecDependencyTerm(leftEvaluatableTerm, terms); + } + + private static RDLSpecEvaluatableTerm parseResource() { + if (tokenStream.checkNext().equals(DOUBLE_QUOT)) { + expect(DOUBLE_QUOT); + String name; + + if (tokenStream.checkNext().equals(DOUBLE_QUOT)) { + name = ""; + } else { + name = tokenStream.next(); + } + + RDLSpecResourceConstant resourceConstant = new RDLSpecResourceConstant(name, new Type("primitive","primitive"), new Type("string","string")); + expect(DOUBLE_QUOT); + return resourceConstant; + } + + String resourceName = tokenStream.next(); + + if (resourceName == null) { + throw new NullPointerException("need resource"); + } + + RDLSpecResource resource; + + if (resourceName.equals("true") || resourceName.equals("false")) { + return new RDLSpecResourceConstant(resourceName, new Type("primitive","primitive"), new Type("boolean","boolean")); + } + + if (isInt(resourceName)) { + return new RDLSpecResourceConstant(resourceName, new Type("primitive","primitive"), new Type("int","int")); + } + + if (!isInt(resourceName) && isDouble(resourceName)) { + return new RDLSpecResourceConstant(resourceName, new Type("primitive","primitive"), new Type("double","double")); + } + + if (!resourceDeclaration.containsResource(resourceName)) { + throw new RuntimeException("resourceが存在しません : " + resourceName); + } + + if (tokenStream.checkNext() != null && tokenStream.checkNext().equals(PRIME)) { + //id型判定はresourceDeclarationクラスに書いた + expect(PRIME); + resource = resourceDeclaration.getRDLSpecResource(resourceName, true); + } else { + resource = resourceDeclaration.getRDLSpecResource(resourceName, false); + } + + return resource; + } + + //TODO staticは後で消す. + private static RDLSpecResource parseResourceDeclaration() { + 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 valuableType = tokenStream.next(); + resourceDeclaration.putRDLSpecResource(resourceName, order, new Type(structuralType, structuralType), new Type(valuableType, valuableType)); + return resourceDeclaration.getRDLSpecResource(resourceName, false); + } else if (tokenStream.checkNext().equals("struct")) { + String structuralType = tokenStream.next(); + resourceDeclaration.putRDLSpecResource(resourceName, order, new Type(structuralType, structuralType), null); + return resourceDeclaration.getRDLSpecResource(resourceName, false); + } else { + String structuralType = "primitive"; + String valuableType = tokenStream.next(); + + if (valuableType == null) { + throw new NullPointerException("need valuableType"); + } + + resourceDeclaration.putRDLSpecResource(resourceName, order, new Type(structuralType, structuralType), new Type(valuableType, valuableType)); + return resourceDeclaration.getRDLSpecResource(resourceName, false); + } + } + + 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); + 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 void markLine() { + markLines.add(line); + markNs.add(n); + } + + public void backLastLine() { + 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; + } + } +}