diff --git a/src/main/java/ast/ASTNode.java b/src/main/java/ast/ASTNode.java
new file mode 100644
index 0000000..4c18ffe
--- /dev/null
+++ b/src/main/java/ast/ASTNode.java
@@ -0,0 +1,13 @@
+package ast;
+
+public abstract class ASTNode {
+ private ASTNode parent;
+
+ public ASTNode getParent() {
+ return parent;
+ }
+
+ public void setParent(ASTNode parent) {
+ this.parent = parent;
+ }
+}
diff --git a/src/main/java/ast/AbstractTypeDeclaration.java b/src/main/java/ast/AbstractTypeDeclaration.java
new file mode 100644
index 0000000..1ede942
--- /dev/null
+++ b/src/main/java/ast/AbstractTypeDeclaration.java
@@ -0,0 +1,13 @@
+package ast;
+
+public class AbstractTypeDeclaration extends BodyDeclaration {
+ protected String typeName = null;
+
+ public String getTypeName() {
+ return typeName;
+ }
+
+ public void setTypeName(String typeName) {
+ this.typeName = typeName;
+ }
+}
diff --git a/src/main/java/ast/AnnotatableType.java b/src/main/java/ast/AnnotatableType.java
new file mode 100644
index 0000000..aa016e8
--- /dev/null
+++ b/src/main/java/ast/AnnotatableType.java
@@ -0,0 +1,26 @@
+package ast;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents an abstract base class for AST types that can have annotations.
+ * This class extends the functionality of {@link Type} by introducing support
+ * for attaching annotations to the type.
+ *
+ * Subclasses of this class represent specific kinds of types in the AST that
+ * allow annotations, such as primitive types or other specialized types.
+ *
+ * @author s-yamagiwa
+ */
+public abstract class AnnotatableType extends Type {
+ private final List annotations = new ArrayList<>();
+
+ public void addAnnotation(Annotation annotation) {
+ annotations.add(annotation);
+ }
+
+ public List getAnnotations() {
+ return annotations;
+ }
+}
diff --git a/src/main/java/ast/Annotation.java b/src/main/java/ast/Annotation.java
new file mode 100644
index 0000000..80d4a32
--- /dev/null
+++ b/src/main/java/ast/Annotation.java
@@ -0,0 +1,57 @@
+package ast;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class Annotation extends ASTNode {
+ private String name = null;
+ private Map keyValueMap = null;
+
+ public Annotation(String name) {
+ this.name = name;
+ keyValueMap = new HashMap<>();
+ }
+
+ public Annotation(String name, String value) {
+ this.name = name;
+ keyValueMap = new HashMap<>();
+ keyValueMap.put("value", value);
+ }
+
+ public String getElementName() {
+ return name;
+ }
+
+ public Map getParams() {
+ return keyValueMap;
+ }
+
+ public Object getValue(String key) {
+ return keyValueMap.get(key);
+ }
+
+ public void addParam(String key, Object value) {
+ keyValueMap.put(key, value);
+ }
+
+ public String toString() {
+ String code = "@" + name;
+ Set keySet = keyValueMap.keySet();
+ if (keySet.size() == 0) {
+ return code;
+ } else if (keySet.size() == 1 && keySet.iterator().next().equals("value")) {
+ code += "(" + keyValueMap.get("value").toString() + ")";
+ } else {
+ code += "(";
+ String delimitar = "";
+ for (String key: keySet) {
+ Object value = keyValueMap.get(key);
+ code += delimitar + key + " = \"" + value.toString() + "\"";
+ delimitar = ", ";
+ }
+ code += ")";
+ }
+ return code;
+ }
+}
diff --git a/src/main/java/ast/Assignment.java b/src/main/java/ast/Assignment.java
new file mode 100644
index 0000000..98f87a0
--- /dev/null
+++ b/src/main/java/ast/Assignment.java
@@ -0,0 +1,42 @@
+package ast;
+
+/**
+ * Represents an assignment expression node in AST (Abstract Syntax Tree)
+ *
+ * @author s-yamagiwa
+ */
+public class Assignment extends Expression {
+ private Expression left;
+ private Expression right;
+
+ public Assignment(Expression left, Expression right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ @Override
+ public Expression replace(Variable variable, Expression expression) {
+ return new Assignment(left.replace(variable, expression), right.replace(variable, expression));
+ }
+
+ public Expression getLeft() {
+ return left;
+ }
+
+ public void setLeft(Expression left) {
+ this.left = left;
+ }
+
+ public Expression getRight() {
+ return right;
+ }
+
+ public void setRight(Expression right) {
+ this.right = right;
+ }
+
+ @Override
+ public String toString() {
+ return left.toString() + " " + "+" + " " + right.toString();
+ }
+}
diff --git a/src/main/java/ast/Block.java b/src/main/java/ast/Block.java
new file mode 100644
index 0000000..0d021da
--- /dev/null
+++ b/src/main/java/ast/Block.java
@@ -0,0 +1,108 @@
+package ast;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.stream.Collectors;
+
+public class Block extends Statement {
+ private List statements = new ArrayList<>();
+
+ public List getStatements2() {
+ return statements;
+ }
+
+ public void setStatements(List statements) {
+ this.statements = statements;
+ }
+
+ public void addFirstStatement(Statement statement) {
+ statements.add(0, statement);
+ }
+
+ public void addStatement(Statement statement) {
+ statements.add(statement);
+ }
+
+ public void addFirstStatements(List statements) {
+ this.statements.addAll(0, statements);
+ }
+
+ public void addStatements(List statements) {
+ this.statements.addAll(statements);
+ }
+
+ public boolean contains(List statements) {
+ if (statements.size() == 0) return true;
+ for (int i = 0; i < this.statements.size(); i++) {
+ Statement st = this.statements.get(i);
+ if (st.equals(statements.get(0))) {
+ if (statements.size() == 1) return true;
+ int j = 1;
+ for (int k = i + 1; k < this.statements.size(); k++) {
+ Statement st2 = this.statements.get(k);
+ if (st2.equals(statements.get(j))) {
+ j++;
+ if (j == statements.size()) return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ //====================================================
+ //TODO: CodeGenerator修正後削除
+
+ public List getStatements() {
+ List strings = new ArrayList<>();
+ for (Statement stmt : statements) {
+ if (stmt != null) {
+ strings.add(stmt.toString());
+ }
+ }
+ return strings;
+ }
+
+ public void addFirstStatement(String statement) {
+ if (statement != null) {
+ this.addFirstStatement(new Statement() {
+ @Override
+ public String toString() {
+ return statement;
+ }
+ });
+ }
+ }
+
+ public void addStatement(String statement) {
+ if (statement != null) {
+ this.addStatement(new PlainStatement(statement));
+ }
+ }
+
+ //====================================================
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("{\n");
+
+ for (Statement statement : statements) {
+ if (statement != null) {
+ String content = statement.toString();
+
+ // split statement
+ String[] lines = content.split("\n");
+
+ // Tab
+ for (String line : lines) {
+ sb.append("\t").append(line).append("\n");
+ }
+ }
+ }
+
+ sb.append("}");
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/ast/BodyDeclaration.java b/src/main/java/ast/BodyDeclaration.java
new file mode 100644
index 0000000..6a5eece
--- /dev/null
+++ b/src/main/java/ast/BodyDeclaration.java
@@ -0,0 +1,13 @@
+package ast;
+
+public abstract class BodyDeclaration extends ASTNode {
+ private int modifiers = 0;
+
+ public int getModifiers() {
+ return modifiers;
+ }
+
+ public void setModifiers(int modifiers) {
+ this.modifiers = modifiers;
+ }
+}
diff --git a/src/main/java/ast/ClassInstanceCreation.java b/src/main/java/ast/ClassInstanceCreation.java
new file mode 100644
index 0000000..98841af
--- /dev/null
+++ b/src/main/java/ast/ClassInstanceCreation.java
@@ -0,0 +1,71 @@
+package ast;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ClassInstanceCreation extends Expression {
+ private Type type;
+
+ private List arguments;
+
+ public ClassInstanceCreation(Type type) {
+ this(type, List.of());
+ }
+
+ public ClassInstanceCreation(Type type, List arguments) {
+ this.type = type;
+ this.arguments = arguments;
+ }
+
+ @Override
+ public Expression replace(Variable variable, Expression expression) {
+ List replacedExpressions = new ArrayList<>();
+
+ for (Expression argument : arguments) {
+ replacedExpressions.add(argument.replace(variable, expression));
+ }
+
+ return new ClassInstanceCreation(type, replacedExpressions);
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public void setType(Type type) {
+ this.type = type;
+ }
+
+ public List getArguments() {
+ return arguments;
+ }
+
+ public void setArguments(List arguments) {
+ this.arguments = arguments;
+ }
+
+ public void addArgument(Expression expression) {
+ arguments.add(expression);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("new ");
+ builder.append(type.toString());
+ builder.append("(");
+ for (int i = 0; i < arguments.size(); i++) {
+ Expression argument = arguments.get(i);
+
+ builder.append(argument.toString());
+
+ if (i < arguments.size() - 1) {
+ builder.append(", ");
+ }
+ }
+ builder.append(")");
+
+ return builder.toString();
+ }
+}
diff --git a/src/main/java/ast/CodeUtil.java b/src/main/java/ast/CodeUtil.java
new file mode 100644
index 0000000..09c1c76
--- /dev/null
+++ b/src/main/java/ast/CodeUtil.java
@@ -0,0 +1,13 @@
+package ast;
+
+public class CodeUtil {
+
+ public static String insertTab(String code) {
+ String newString = "";
+ String[] lines = code.split("\n");
+ for (String line: lines) {
+ newString = newString + "\t" + line + "\n";
+ }
+ return newString;
+ }
+}
diff --git a/src/main/java/ast/CompilationUnit.java b/src/main/java/ast/CompilationUnit.java
new file mode 100644
index 0000000..68403a1
--- /dev/null
+++ b/src/main/java/ast/CompilationUnit.java
@@ -0,0 +1,50 @@
+package ast;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CompilationUnit extends ASTNode {
+ private String fileName = null;
+ private List imports = new ArrayList<>();
+ private List types = new ArrayList<>();
+
+ public CompilationUnit(TypeDeclaration type) {
+ types.add(type);
+ if(type.getTypeName().contains("<"))
+ fileName = type.getTypeName().split("<")[0] + ".java";
+ else
+ fileName = type.getTypeName() + ".java";
+ }
+
+ public List imports() {
+ return imports;
+ }
+
+ public List types() {
+ return types;
+ }
+
+ public void addImport(ImportDeclaration imp) {
+ imports.add(imp);
+ }
+
+ public void addType(TypeDeclaration type) {
+ types.add(type);
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public String toString() {
+ String result = "";
+ for (ImportDeclaration imp: imports) {
+ result += imp.toString();
+ }
+ result +="\n";
+ for (TypeDeclaration type: types) {
+ result += type.toString();
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/ast/Constant.java b/src/main/java/ast/Constant.java
new file mode 100644
index 0000000..0c56081
--- /dev/null
+++ b/src/main/java/ast/Constant.java
@@ -0,0 +1,32 @@
+package ast;
+
+/**
+ * Represents a constant in the AST (Abstract Syntax Tree)
+ *
+ * @author s-yamagiwa
+ */
+public class Constant extends Expression {
+ private String value;
+
+ public Constant(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public Expression replace(Variable variable, Expression expression) {
+ return this;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+}
diff --git a/src/main/java/ast/EnhancedForStatement.java b/src/main/java/ast/EnhancedForStatement.java
new file mode 100644
index 0000000..4460ddf
--- /dev/null
+++ b/src/main/java/ast/EnhancedForStatement.java
@@ -0,0 +1,23 @@
+package ast;
+
+public class EnhancedForStatement extends Statement {
+
+ private VariableDeclaration singleVariableDeclaration;
+ private Expression expression;
+ private Statement body;
+
+ public VariableDeclaration getParameter() { return singleVariableDeclaration; }
+ public void setParameter(VariableDeclaration parameter) { this.singleVariableDeclaration = parameter; }
+
+ public Expression getExpression() { return expression; }
+ public void setExpression(Expression expression) { this.expression = expression; }
+
+ public Statement getBody() { return body; }
+ public void setBody(Statement body) { this.body = body; }
+
+ @Override
+ public String toString() {
+ String typeName = singleVariableDeclaration.getType().getImplementationTypeName();
+ return "for (" + typeName + " " + singleVariableDeclaration.getName() + " : " + expression + ") " + body;
+ }
+}
diff --git a/src/main/java/ast/Expression.java b/src/main/java/ast/Expression.java
new file mode 100644
index 0000000..bcf593b
--- /dev/null
+++ b/src/main/java/ast/Expression.java
@@ -0,0 +1,19 @@
+package ast;
+
+/**
+ * Abstract base class for all expression nodes in the abstract syntax tree (AST).
+ *
+ * @author s-yamagiwa
+ */
+public abstract class Expression extends ASTNode {
+ /**
+ * Replace {@code variable} with {@code expression} in AST.
+ *
+ * @param variable The variable to be replaced
+ * @param expression The expression that {@code variable} is replaced to
+ * @return A duplicated expression that is replaced with a given {@code expression}
+ * @implNote The instance of any member must be immutable
+ * @apiNote All variables match to the given one will be replaced with the given {@code expression}
+ */
+ public abstract Expression replace(Variable variable, Expression expression);
+}
diff --git a/src/main/java/ast/ExpressionStatement.java b/src/main/java/ast/ExpressionStatement.java
new file mode 100644
index 0000000..062998f
--- /dev/null
+++ b/src/main/java/ast/ExpressionStatement.java
@@ -0,0 +1,17 @@
+package ast;
+
+public class ExpressionStatement extends Statement{
+ private Expression expression;
+
+ public ExpressionStatement(Expression expression) {
+ this.expression = expression;
+ }
+
+ public Expression getExpression() { return expression; }
+ public void setExpression(Expression expression) { this.expression = expression; }
+
+ @Override
+ public String toString() {
+ return expression + ";";
+ }
+}
diff --git a/src/main/java/ast/FieldAccess.java b/src/main/java/ast/FieldAccess.java
new file mode 100644
index 0000000..ff22302
--- /dev/null
+++ b/src/main/java/ast/FieldAccess.java
@@ -0,0 +1,50 @@
+package ast;
+
+/**
+ * Represents field accesses in AST (Abstract Syntax Tree)
+ *
+ * @author s-yamagiwa
+ */
+public class FieldAccess extends Expression {
+ private Expression expression;
+
+ private String fieldName;
+
+ public FieldAccess(String fieldName) {
+ this(null, fieldName);
+ }
+
+ public FieldAccess(Expression expression, String fieldName) {
+ this.expression = expression;
+ this.fieldName = fieldName;
+ }
+
+ @Override
+ public Expression replace(Variable variable, Expression expression) {
+ return new FieldAccess(expression.replace(variable, expression), fieldName);
+ }
+
+ public Expression getExpression() {
+ return expression;
+ }
+
+ public void setExpression(Expression expression) {
+ this.expression = expression;
+ }
+
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ public void setFieldName(String fieldName) {
+ this.fieldName = fieldName;
+ }
+
+ @Override
+ public String toString() {
+ if (expression == null) {
+ return fieldName;
+ }
+ return expression + "." + fieldName;
+ }
+}
diff --git a/src/main/java/ast/FieldDeclaration.java b/src/main/java/ast/FieldDeclaration.java
new file mode 100644
index 0000000..98ea8cc
--- /dev/null
+++ b/src/main/java/ast/FieldDeclaration.java
@@ -0,0 +1,90 @@
+package ast;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import models.algebra.Type;
+
+public class FieldDeclaration extends BodyDeclaration implements IAnnotatable {
+ private Type type;
+ private String fieldName;
+ private String initializer = null;
+ private String initializationBlock = null;
+ private Map annotations = new HashMap<>();
+
+ public FieldDeclaration(Type type, String fieldName) {
+ this.type = type;
+ this.fieldName = fieldName;
+ }
+
+ public FieldDeclaration(Type type, String fieldName, String initializer) {
+ this.type = type;
+ this.fieldName = fieldName;
+ this.initializer = initializer;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public void setType(Type type) {
+ this.type = type;
+ }
+
+ public String getName() {
+ return fieldName;
+ }
+
+ public void setName(String fieldName) {
+ this.fieldName = fieldName;
+ }
+
+ public String getInitializer() {
+ return initializer;
+ }
+
+ public void setInitializer(String initializer) {
+ this.initializer = initializer;
+ }
+
+ public String getInitializationBlock() {
+ return initializationBlock;
+ }
+
+ public void setInitializationBlock(String initializationBlock) {
+ this.initializationBlock = initializationBlock;
+ }
+
+ @Override
+ public Annotation getAnnotation(String name) {
+ return annotations.get(name);
+ }
+
+ @Override
+ public Collection getAnnotations() {
+ return annotations.values();
+ }
+
+ @Override
+ public void addAnnotation(Annotation annotation) {
+ annotations.put(annotation.getElementName(), annotation);
+ }
+
+ public String toString() {
+ String code = "";
+ for (Annotation annotation: getAnnotations()) {
+ code += annotation.toString() + "\n";
+ }
+ if (initializationBlock != null) {
+ code += "private " + type.getInterfaceTypeName() + " " + fieldName + ";\n" + initializationBlock + "\n";
+ } else {
+ if (initializer == null) {
+ code += "private " + type.getInterfaceTypeName() + " " + fieldName + ";\n";
+ } else {
+ code += "private " + type.getInterfaceTypeName() + " " + fieldName + " = " + initializer + ";\n";
+ }
+ }
+ return code;
+ }
+}
diff --git a/src/main/java/ast/ForStatement.java b/src/main/java/ast/ForStatement.java
new file mode 100644
index 0000000..47c6d1d
--- /dev/null
+++ b/src/main/java/ast/ForStatement.java
@@ -0,0 +1,70 @@
+package ast;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ForStatement extends Statement {
+
+ private List initializers = new ArrayList<>();
+ private Expression optionalConditionExpression;
+ private List updaters = new ArrayList<>();
+ private Statement body;
+
+ public List getInitializers() {
+ return initializers;
+ }
+
+ public void setInitializers(List initializers) {
+ this.initializers = initializers;
+ }
+
+ public Expression getExpression() {
+ return optionalConditionExpression;
+ }
+
+ public void setExpression(Expression expression) {
+ this.optionalConditionExpression = expression;
+ }
+
+ public List getUpdaters() {
+ return updaters;
+ }
+
+ public void setUpdaters(List updaters) {
+ this.updaters = updaters;
+ }
+
+ public Statement getBody() {
+ return body;
+ }
+
+ public void setBody(Statement body) {
+ this.body = body;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("for (");
+
+ for (int i = 0; i < initializers.size(); i++) {
+ String init = initializers.get(i).toString();
+ sb.append(init.endsWith(";") ? init.substring(0, init.length() - 1) : init);
+ if (i < initializers.size() - 1) sb.append(", ");
+ }
+ sb.append("; ");
+
+ if (optionalConditionExpression != null) sb.append(optionalConditionExpression);
+ sb.append("; ");
+
+ for (int i = 0; i < updaters.size(); i++) {
+ String update = updaters.get(i).toString();
+ sb.append(update.endsWith(";") ? update.substring(0, update.length() - 1) : update);
+ if (i < updaters.size() - 1) sb.append(", ");
+ }
+ sb.append(") ");
+
+ if (body != null) sb.append(body);
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ast/IAnnotatable.java b/src/main/java/ast/IAnnotatable.java
new file mode 100644
index 0000000..6d650f7
--- /dev/null
+++ b/src/main/java/ast/IAnnotatable.java
@@ -0,0 +1,9 @@
+package ast;
+
+import java.util.Collection;
+
+public interface IAnnotatable {
+ Annotation getAnnotation(String name);
+ Collection getAnnotations();
+ void addAnnotation(Annotation annotation);
+}
diff --git a/src/main/java/ast/IfStatement.java b/src/main/java/ast/IfStatement.java
new file mode 100644
index 0000000..94e3286
--- /dev/null
+++ b/src/main/java/ast/IfStatement.java
@@ -0,0 +1,43 @@
+package ast;
+
+public class IfStatement extends Statement {
+
+ private Expression expression;
+ private Statement thenStatement;
+ private Statement elseStatement;
+
+ public Expression getExpression() {
+ return expression;
+ }
+
+ public void setExpression(Expression expression) {
+ this.expression = expression;
+ }
+
+ public Statement getThenStatement() {
+ return thenStatement;
+ }
+
+ public void setThenStatement(Statement thenStatement) {
+ this.thenStatement = thenStatement;
+ }
+
+ public Statement getElseStatement() {
+ return elseStatement;
+ }
+
+ public void setElseStatement(Statement elseStatement) {
+ this.elseStatement = elseStatement;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("if ").append(expression);
+ sb.append(thenStatement);
+ if (elseStatement != null) {
+ sb.append(" else ").append(elseStatement);
+ }
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ast/ImportDeclaration.java b/src/main/java/ast/ImportDeclaration.java
new file mode 100644
index 0000000..c9b4b44
--- /dev/null
+++ b/src/main/java/ast/ImportDeclaration.java
@@ -0,0 +1,21 @@
+package ast;
+
+public class ImportDeclaration {
+ private String name;
+
+ public ImportDeclaration(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String toString() {
+ return "import " + name + ";\n";
+ }
+}
diff --git a/src/main/java/ast/InfixExpression.java b/src/main/java/ast/InfixExpression.java
new file mode 100644
index 0000000..39a0441
--- /dev/null
+++ b/src/main/java/ast/InfixExpression.java
@@ -0,0 +1,55 @@
+package ast;
+
+import models.algebra.Symbol;
+
+/**
+ * Represents an infix expression in AST (Abstract Syntax Tree)
+ *
+ * @author s-yamagiwa
+ */
+public class InfixExpression extends Expression {
+ private Symbol operator;
+
+ private Expression leftOperand;
+ private Expression rightOperand;
+
+ public InfixExpression(Symbol operator, Expression leftOperand, Expression rightOperand) {
+ this.operator = operator;
+ this.leftOperand = leftOperand;
+ this.rightOperand = rightOperand;
+ }
+
+ @Override
+ public Expression replace(Variable variable, Expression expression) {
+ return new InfixExpression(operator, leftOperand.replace(variable, expression), rightOperand.replace(variable, expression));
+ }
+
+ public Symbol getOperator() {
+ return this.operator;
+ }
+
+ public void setOperator(Symbol operator) {
+ this.operator = operator;
+ }
+
+ public Expression getLeftOperand() {
+ return leftOperand;
+ }
+
+ public void setLeftOperand(Expression expression) {
+ this.leftOperand = expression;
+ }
+
+ public Expression getRightOperand() {
+ return rightOperand;
+ }
+
+ public void setRightOperand(Expression expression) {
+ this.rightOperand = expression;
+ }
+
+ @Override
+ public String toString() {
+ return leftOperand.toString() + " " + operator.toString() + " " + rightOperand.toString();
+ }
+}
diff --git a/src/main/java/ast/Lexer.java b/src/main/java/ast/Lexer.java
new file mode 100644
index 0000000..e07d224
--- /dev/null
+++ b/src/main/java/ast/Lexer.java
@@ -0,0 +1,55 @@
+package ast;
+
+/**
+ * The Lexer class provides functionalities for parsing and iterating through
+ * a source string of text character by character.
+ *
+ * @author s-yamagiwa;
+ */
+public class Lexer {
+ private final String source;
+ private int position;
+
+ public Lexer(String source) {
+ this.source = source;
+ this.position = 0;
+ }
+
+ /**
+ * Retrieves the next character without advancing the position.
+ *
+ * @return The next character.
+ */
+ public char peek() {
+ if (position >= source.length()) {
+ return '\0'; // End of line
+ }
+
+ return source.charAt(position);
+ }
+
+ /**
+ * Retrieves the next character after advancing the position.
+ *
+ * @return The next character.
+ */
+ public char peekNext() {
+ if (position + 1 >= source.length()) {
+ return '\0'; // End of line
+ }
+
+ return source.charAt(position + 1);
+ }
+
+ /**
+ * Advances the position by one character.
+ *
+ * @return The character that was previously at the current position.
+ */
+ public char advance() {
+ char current = peek();
+ position++;
+
+ return current;
+ }
+}
diff --git a/src/main/java/ast/MethodDeclaration.java b/src/main/java/ast/MethodDeclaration.java
new file mode 100644
index 0000000..df8d29e
--- /dev/null
+++ b/src/main/java/ast/MethodDeclaration.java
@@ -0,0 +1,176 @@
+package ast;
+
+import java.util.List;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+
+import models.algebra.Type;
+
+public class MethodDeclaration extends BodyDeclaration implements IAnnotatable {
+ private String name = null;
+ private boolean isConstructor = false;
+ private Type returnType = null;
+ private List parameters = null;
+ private Block body = null;
+ private Map annotations = new HashMap<>();
+ private Throws thrws = null;
+
+ public MethodDeclaration(String methodName) {
+ this(methodName, false);
+ }
+
+ public MethodDeclaration(String methodName, Type returnType) {
+ this(methodName, false);
+ this.returnType = returnType;
+ }
+
+ public MethodDeclaration(String methodName, boolean isConstructor) {
+ this.name = methodName;
+ this.isConstructor = isConstructor;
+ }
+
+ public MethodDeclaration(String methodName, boolean isConstructor, Type returnType, List parameters) {
+ this(methodName, isConstructor, returnType, parameters, null);
+ }
+
+ public MethodDeclaration(String methodName, boolean isConstructor, Type returnType, List parameters, Block body) {
+ this(methodName, isConstructor);
+ this.returnType = returnType;
+ this.parameters = parameters;
+ this.body = body;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isConstructor() {
+ return isConstructor;
+ }
+
+ public void setConstructor(boolean isConstructor) {
+ this.isConstructor = isConstructor;
+ }
+
+ public Type getReturnType() {
+ return returnType;
+ }
+
+ public void setReturnType(Type returnType) {
+ this.returnType = returnType;
+ }
+
+ public List getParameters() {
+ return parameters;
+ }
+
+ public void setParameters(List parameters) {
+ this.parameters = parameters;
+ }
+
+ public void addParameter(VariableDeclaration parameter) {
+ if (parameters == null) {
+ parameters = new ArrayList<>();
+ }
+ parameters.add(parameter);
+ }
+
+ public Block getBody() {
+ if (body == null) {
+ body = new Block();
+ }
+ return body;
+ }
+
+ public void setBody(Block body) {
+ this.body = body;
+ }
+
+ public void addStatement(Statement statement) {
+ if (body == null) {
+ body = new Block();
+ }
+ body.addStatement(statement);
+ }
+
+ public void addStatement(String statement) {
+ if (body == null) {
+ body = new Block();
+ }
+ body.addStatement(statement);
+ }
+
+ public void addFirstStatement(Statement statement) {
+ if (body == null) {
+ body = new Block();
+ }
+ body.addFirstStatement(statement);
+ }
+
+ public void addFirstStatement(String statement) {
+ if (body == null) {
+ body = new Block();
+ }
+ body.addFirstStatement(statement);
+ }
+
+ public void addThrow(String exception) {
+ if (thrws == null) {
+ thrws = new Throws();
+ }
+ thrws.addException(exception);
+ }
+
+ public Throws getThrows() {
+ return thrws;
+ }
+
+ @Override
+ public Annotation getAnnotation(String name) {
+ return annotations.get(name);
+ }
+
+ @Override
+ public Collection getAnnotations() {
+ return annotations.values();
+ }
+
+ @Override
+ public void addAnnotation(Annotation annotation) {
+ annotations.put(annotation.getElementName(), annotation);
+ }
+
+ public String toString() {
+ String code = "";
+ for (Annotation annotation: getAnnotations()) {
+ code += annotation.toString() + "\n";
+ }
+ code += "public ";
+ if (returnType == null) {
+ if(!isConstructor) code += "void ";
+ }else {
+ code += returnType.getInterfaceTypeName() + " ";
+ }
+ code += (name + "(");
+ if (parameters != null) {
+ for (int i = 0; i < parameters.size(); i++) {
+ code += parameters.get(i).toString();
+ if (i < parameters.size() - 1) code += ", ";
+ }
+ }
+ code += ") ";
+
+ if (body != null) {
+ code += body.toString();
+ } else {
+ code += ";";
+ }
+ return code;
+ }
+}
diff --git a/src/main/java/ast/MethodInvocation.java b/src/main/java/ast/MethodInvocation.java
new file mode 100644
index 0000000..40e5235
--- /dev/null
+++ b/src/main/java/ast/MethodInvocation.java
@@ -0,0 +1,107 @@
+package ast;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a method invocation in AST (Abstract Syntax Tree)
+ *
+ * @author s-yamagiwa
+ * @apiNote Type arguments aren't supported because it isn't necessary in DTRAM code generator.
+ */
+public class MethodInvocation extends Expression {
+ /**
+ * The receiver expression of the invocation
+ * defaults to {@code null}
+ */
+ private Expression receiver;
+
+ /**
+ * The method name to be called by this invocation
+ */
+ private String methodName;
+
+ /**
+ * All arguments used in the called method
+ */
+ private List arguments;
+
+ public MethodInvocation(String methodName) {
+ this(null, methodName);
+ }
+
+ public MethodInvocation(Expression receiver, String methodName) {
+ this(receiver, methodName, List.of());
+ }
+
+ public MethodInvocation(Expression receiver, String methodName, List arguments) {
+ this.receiver = receiver;
+ this.methodName = methodName;
+ this.arguments = arguments;
+ }
+
+ @Override
+ public Expression replace(Variable variable, Expression expression) {
+ List replacedExpressions = new ArrayList<>();
+
+ for (Expression argument : arguments) {
+ replacedExpressions.add(argument.replace(variable, expression));
+ }
+
+ if (receiver == null) {
+ return new MethodInvocation(null, methodName, replacedExpressions);
+ }
+
+ return new MethodInvocation(receiver.replace(variable, expression), methodName, replacedExpressions);
+ }
+
+ public Expression getReceiver() {
+ return receiver;
+ }
+
+ public void setReceiver(Expression receiver) {
+ this.receiver = receiver;
+ }
+
+ public String getMethodName() {
+ return methodName;
+ }
+
+ public void setMethodName(String methodName) {
+ this.methodName = methodName;
+ }
+
+ public List getArguments() {
+ return arguments;
+ }
+
+ public void setArguments(List arguments) {
+ this.arguments = arguments;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (receiver != null) {
+ builder.append(receiver.toString()).append(".");
+ }
+
+ builder.append(methodName).append("(");
+
+ if (arguments != null && !arguments.isEmpty()) {
+ for (int i = 0; i < arguments.size(); i++) {
+ Expression argument = arguments.get(i);
+
+ builder.append(argument.toString());
+
+ if (i < arguments.size() - 1) {
+ builder.append(", ");
+ }
+ }
+ }
+
+ builder.append(")");
+
+ return builder.toString();
+ }
+}
diff --git a/src/main/java/ast/Modifier.java b/src/main/java/ast/Modifier.java
new file mode 100644
index 0000000..10ea845
--- /dev/null
+++ b/src/main/java/ast/Modifier.java
@@ -0,0 +1,29 @@
+package ast;
+
+public class Modifier extends ASTNode {
+ public static final int ABSTRACT = 0x0400;
+ public static final int PRIVATE = 0x0002;
+ public static final int PROTECTED = 0x0004;
+ public static final int PUBLIC = 0x0001;
+ public static final int STATIC = 0x0008;
+
+ public static boolean isAbstract(int flags) {
+ return (flags & ABSTRACT) != 0;
+ }
+
+ public static boolean isPrivate(int flags) {
+ return (flags & PRIVATE) != 0;
+ }
+
+ public static boolean isProtected(int flags) {
+ return (flags & PROTECTED) != 0;
+ }
+
+ public static boolean isPublic(int flags) {
+ return (flags & PUBLIC) != 0;
+ }
+
+ public static boolean isStatic(int flags) {
+ return (flags & STATIC) != 0;
+ }
+}
diff --git a/src/main/java/ast/ParameterizedType.java b/src/main/java/ast/ParameterizedType.java
new file mode 100644
index 0000000..d0a125d
--- /dev/null
+++ b/src/main/java/ast/ParameterizedType.java
@@ -0,0 +1,109 @@
+package ast;
+
+import java.util.List;
+
+/**
+ * Represents a parameterized type in an abstract syntax tree (AST).
+ * A parameterized type consists of a base type and a set of type arguments.
+ *
+ * For example, List<String> is a parameterized type where
+ * List is the base type and String is the type argument.
+ *
+ * @author s-yamagiwa
+ */
+public class ParameterizedType extends Type {
+ /**
+ * The base type of the parameterized type.
+ *
+ * For example, List in List<String> is a base type.
+ */
+ private Type type;
+
+ /**
+ * The type arguments of the parameterized type.
+ * Defaults to an empty list.
+ *
+ * For example, String in List<String> is a type argument.
+ */
+ private List typeArguments;
+
+ public ParameterizedType(Type type, List typeArguments) {
+ this.type = type;
+ this.typeArguments = typeArguments;
+ }
+
+ public ParameterizedType(Type type) {
+ this(type, List.of());
+ }
+
+ /**
+ * Adds a type argument to the parameterized type.
+ *
+ * @param type The type argument to add. Only {@link SimpleType}s are allowed for now.
+ */
+ public void addTypeArgument(Type type) {
+ typeArguments.add(type);
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public void setType(Type type) {
+ this.type = type;
+ }
+
+ /**
+ * Returns the type arguments of the parameterized type.
+ * Only {@link SimpleType}s are allowed for now.
+ *
+ * It can be empty if it is the type of created instances like in the following example.
+ * new List<>() or new HashMap<>()
+ *
+ * @return The type arguments of the parameterized type.
+ */
+ public List getTypeArguments() {
+ return typeArguments;
+ }
+
+ public void setTypeArguments(List typeArguments) {
+ this.typeArguments = typeArguments;
+ }
+
+
+ /**
+ * Replace all type arguments and their descendant types that match the replacedType with the replacingType.
+ * @param replacedType the type to be replaced
+ * @param replacingType the type to replace with
+ */
+ public void replaceSubTypes(Type replacedType, Type replacingType) {
+ for (int i = 0; i < typeArguments.size(); i++) {
+ Type typeArgment = typeArguments.get(i);
+ if (typeArgment.equals(replacedType)) {
+ typeArguments.set(i, replacingType);
+ } else if (typeArgment instanceof ParameterizedType) {
+ ((ParameterizedType) typeArgment).replaceSubTypes(replacedType, replacingType);
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ if (typeArguments.isEmpty()) {
+ return type.toString();
+ }
+
+ StringBuilder builder = new StringBuilder();
+ builder.append(type.toString());
+ builder.append("<");
+ for (int i = 0; i < typeArguments.size(); i++) {
+ builder.append(typeArguments.get(i).toString());
+ if (i < typeArguments.size() - 1) {
+ builder.append(", ");
+ }
+ }
+ builder.append(">");
+
+ return builder.toString();
+ }
+}
diff --git a/src/main/java/ast/ParenthesizedExpression.java b/src/main/java/ast/ParenthesizedExpression.java
new file mode 100644
index 0000000..0a5d6f2
--- /dev/null
+++ b/src/main/java/ast/ParenthesizedExpression.java
@@ -0,0 +1,33 @@
+package ast;
+
+/**
+ * Represents a parenthesized expression in AST (Abstract Syntax Tree)
+ * This class is used to save the priority of each expression
+ *
+ * @author s-yamagiwa
+ */
+public class ParenthesizedExpression extends Expression {
+ private Expression expression;
+
+ public ParenthesizedExpression(Expression expression) {
+ this.expression = expression;
+ }
+
+ @Override
+ public Expression replace(Variable variable, Expression expression) {
+ return new ParenthesizedExpression(this.expression.replace(variable, expression));
+ }
+
+ public Expression getExpression() {
+ return expression;
+ }
+
+ public void setExpression(Expression expression) {
+ this.expression = expression;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + expression.toString() + ")";
+ }
+}
diff --git a/src/main/java/ast/PlainExpression.java b/src/main/java/ast/PlainExpression.java
new file mode 100644
index 0000000..c5ffcbd
--- /dev/null
+++ b/src/main/java/ast/PlainExpression.java
@@ -0,0 +1,23 @@
+package ast;
+
+//====================================================
+//TODO: CodeGenerator修正後削除
+//====================================================
+
+public class PlainExpression extends Expression {
+ private String expression;
+
+ public PlainExpression(String expression) {
+ this.expression = expression;
+ }
+
+ @Override
+ public Expression replace(Variable variable, Expression newExpression) {
+ return new PlainExpression(expression.replace(variable.toString(), newExpression.toString()));
+ }
+
+ @Override
+ public String toString() {
+ return expression;
+ }
+}
diff --git a/src/main/java/ast/PlainStatement.java b/src/main/java/ast/PlainStatement.java
new file mode 100644
index 0000000..9424f1b
--- /dev/null
+++ b/src/main/java/ast/PlainStatement.java
@@ -0,0 +1,18 @@
+package ast;
+
+//====================================================
+//TODO: CodeGenerator修正後削除
+//====================================================
+
+public class PlainStatement extends Statement {
+ private String code;
+
+ public PlainStatement(String code) {
+ this.code = code;
+ }
+
+ @Override
+ public String toString() {
+ return code;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ast/PostfixExpression.java b/src/main/java/ast/PostfixExpression.java
new file mode 100644
index 0000000..8205bc0
--- /dev/null
+++ b/src/main/java/ast/PostfixExpression.java
@@ -0,0 +1,58 @@
+package ast;
+
+/**
+ * Represents a postfix expression in AST (Abstract Syntax Tree)
+ *
+ * @author s-yamagiwa
+ */
+public class PostfixExpression extends Expression {
+ public enum Operator {
+ INCREMENT("++"), DECREMENT("--");
+
+ Operator(String symbol) {
+ this.symbol = symbol;
+ }
+
+ private final String symbol;
+
+ @Override
+ public String toString() {
+ return symbol;
+ }
+ }
+
+ private Expression operand;
+
+ private Operator operator;
+
+ public PostfixExpression(Expression operand, Operator operator) {
+ this.operand = operand;
+ this.operator = operator;
+ }
+
+ @Override
+ public Expression replace(Variable variable, Expression expression) {
+ return new PostfixExpression(operand.replace(variable, expression), operator);
+ }
+
+ public Expression getOperand() {
+ return operand;
+ }
+
+ public void setOperand(Expression operand) {
+ this.operand = operand;
+ }
+
+ public Operator getOperator() {
+ return operator;
+ }
+
+ public void setOperator(Operator operator) {
+ this.operator = operator;
+ }
+
+ @Override
+ public String toString() {
+ return operand.toString() + operator.toString();
+ }
+}
diff --git a/src/main/java/ast/PrefixExpression.java b/src/main/java/ast/PrefixExpression.java
new file mode 100644
index 0000000..d1444e3
--- /dev/null
+++ b/src/main/java/ast/PrefixExpression.java
@@ -0,0 +1,58 @@
+package ast;
+
+/**
+ * Represents a prefix expression in AST (Abstract Syntax Tree)
+ *
+ * @author s-yamagiwa
+ */
+public class PrefixExpression extends Expression {
+ public enum Operator {
+ INCREMENT("++"), DECREMENT("--"), PLUS("+"), MINUS("-"), NOT("!");
+
+ Operator(String symbol) {
+ this.symbol = symbol;
+ }
+
+ private final String symbol;
+
+ @Override
+ public String toString() {
+ return symbol;
+ }
+ }
+
+ private Expression operand;
+
+ private Operator operator;
+
+ public PrefixExpression(Expression operand, Operator operator) {
+ this.operand = operand;
+ this.operator = operator;
+ }
+
+ @Override
+ public Expression replace(Variable variable, Expression expression) {
+ return new PrefixExpression(operand.replace(variable, expression), operator);
+ }
+
+ public Expression getOperand() {
+ return operand;
+ }
+
+ public void setOperand(Expression operand) {
+ this.operand = operand;
+ }
+
+ public Operator getOperator() {
+ return operator;
+ }
+
+ public void setOperator(Operator operator) {
+ this.operator = operator;
+ }
+
+ @Override
+ public String toString() {
+ return operator.toString() + operand.toString();
+ }
+}
diff --git a/src/main/java/ast/PrimitiveType.java b/src/main/java/ast/PrimitiveType.java
new file mode 100644
index 0000000..dfebba5
--- /dev/null
+++ b/src/main/java/ast/PrimitiveType.java
@@ -0,0 +1,34 @@
+package ast;
+
+/**
+ * Represents a primitive type in the abstract syntax tree (AST).
+ * This class extends the {@code AnnotatableType}, allowing annotations
+ * to be attached to primitive types.
+ *
+ * Primitive types are: {@code boolean}, {@code byte}, {@code char}, {@code short}, {@code int}, {@code long}, {@code float}, {@code double} and {@code void}
+ *
+ * @author s-yamagiwa
+ */
+public class PrimitiveType extends AnnotatableType {
+ private String typeName;
+
+ public PrimitiveType(String typeName) {
+ this.typeName = typeName;
+ }
+
+ @Override
+ public String toString() {
+ if (getAnnotations().isEmpty()) {
+ return typeName;
+ }
+
+ StringBuilder builder = new StringBuilder();
+ for (Annotation annotation : getAnnotations()) {
+ builder.append(annotation.toString());
+ builder.append(" ");
+ }
+ builder.append(typeName);
+
+ return builder.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ast/ReturnStatement.java b/src/main/java/ast/ReturnStatement.java
new file mode 100644
index 0000000..4d6cbbe
--- /dev/null
+++ b/src/main/java/ast/ReturnStatement.java
@@ -0,0 +1,21 @@
+package ast;
+
+public class ReturnStatement extends Statement{
+ private Expression expression;
+
+ public Expression getExpression() {
+ return expression;
+ }
+
+ public void setExpression(Expression expression) {
+ this.expression = expression;
+ }
+
+ @Override
+ public String toString() {
+ if (expression != null) {
+ return "return " + expression + ";";
+ }
+ return "return;";
+ }
+}
diff --git a/src/main/java/ast/SimpleType.java b/src/main/java/ast/SimpleType.java
new file mode 100644
index 0000000..0eb0d6a
--- /dev/null
+++ b/src/main/java/ast/SimpleType.java
@@ -0,0 +1,39 @@
+package ast;
+
+/**
+ * Represents a simple type in the AST, which is a type with a single identifier.
+ * For example, String, List, Map or MyClass.
+ *
+ * @author s-yamagiwa
+ */
+public class SimpleType extends AnnotatableType {
+ private String name;
+
+ public SimpleType(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ if (getAnnotations().isEmpty()) {
+ return name;
+ }
+
+ StringBuilder builder = new StringBuilder();
+ for (Annotation annotation : getAnnotations()) {
+ builder.append(annotation.toString());
+ builder.append(" ");
+ }
+ builder.append(name);
+
+ return builder.toString();
+ }
+}
diff --git a/src/main/java/ast/Statement.java b/src/main/java/ast/Statement.java
new file mode 100644
index 0000000..9c3fad6
--- /dev/null
+++ b/src/main/java/ast/Statement.java
@@ -0,0 +1,7 @@
+package ast;
+
+public abstract class Statement extends ASTNode {
+
+ @Override
+ public abstract String toString();
+}
diff --git a/src/main/java/ast/SuperMethodInvocation.java b/src/main/java/ast/SuperMethodInvocation.java
new file mode 100644
index 0000000..421a0dc
--- /dev/null
+++ b/src/main/java/ast/SuperMethodInvocation.java
@@ -0,0 +1,74 @@
+package ast;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a super method invocation in AST (Abstract Syntax Tree)
+ *
+ * @author s-yamagiwa
+ * @apiNote Type arguments aren't supported because it isn't necessary in DTRAM code generator.
+ */
+public class SuperMethodInvocation extends Expression {
+ private String methodName;
+ private List arguments;
+
+ public SuperMethodInvocation(String methodName) {
+ this(methodName, List.of());
+ }
+
+ public SuperMethodInvocation(String methodName, List arguments) {
+ this.methodName = methodName;
+ this.arguments = arguments;
+ }
+
+ @Override
+ public Expression replace(Variable variable, Expression expression) {
+ List replacedExpressions = new ArrayList<>();
+
+ for (Expression argument : arguments) {
+ replacedExpressions.add(argument.replace(variable, expression));
+ }
+
+ return new SuperMethodInvocation(methodName, replacedExpressions);
+ }
+
+ public String getMethodName() {
+ return methodName;
+ }
+
+ public void setMethodName(String methodName) {
+ this.methodName = methodName;
+ }
+
+ public List getArguments() {
+ return arguments;
+ }
+
+ public void setArguments(List arguments) {
+ this.arguments = arguments;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("super.").append(methodName).append("(");
+
+ if (!arguments.isEmpty()) {
+ for (int i = 0; i < arguments.size(); i++) {
+ Expression argument = arguments.get(i);
+
+ builder.append(argument.toString());
+
+ if (i < arguments.size() - 1) {
+ builder.append(", ");
+ }
+ }
+ }
+
+ builder.append(");");
+
+ return builder.toString();
+ }
+}
diff --git a/src/main/java/ast/ThisExpression.java b/src/main/java/ast/ThisExpression.java
new file mode 100644
index 0000000..11f0cea
--- /dev/null
+++ b/src/main/java/ast/ThisExpression.java
@@ -0,0 +1,13 @@
+package ast;
+
+public class ThisExpression extends Expression {
+ @Override
+ public Expression replace(Variable variable, Expression expression) {
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "this";
+ }
+}
diff --git a/src/main/java/ast/Throws.java b/src/main/java/ast/Throws.java
new file mode 100644
index 0000000..c32592e
--- /dev/null
+++ b/src/main/java/ast/Throws.java
@@ -0,0 +1,29 @@
+package ast;
+
+import java.util.Set;
+import java.util.HashSet;
+
+public class Throws extends ASTNode {
+ private Set exceptions = new HashSet<>();
+
+ public Throws() {
+ }
+
+ public void addException(String exception) {
+ exceptions.add(exception);
+ }
+
+ public Set getExceptions() {
+ return exceptions;
+ }
+
+ public String toString() {
+ String code = "throws ";
+ String delimiter = "";
+ for (String exception: exceptions) {
+ code += delimiter + exception;
+ delimiter = ", ";
+ }
+ return code;
+ }
+}
diff --git a/src/main/java/ast/Type.java b/src/main/java/ast/Type.java
new file mode 100644
index 0000000..9f0266b
--- /dev/null
+++ b/src/main/java/ast/Type.java
@@ -0,0 +1,37 @@
+package ast;
+
+/**
+ * Represents an abstract base class for all types in an abstract syntax tree (AST).
+ * A type can represent various forms such as primitive types, simple types,
+ * parameterized types, or others as defined by subclasses.
+ *
+ * @author s-yamagiwa
+ */
+public abstract class Type extends ASTNode implements models.algebra.Type.ITypeImpl {
+ /**
+ * Returns whether this type is a primitive type or not.
+ *
+ * @return true if this type is a primitive type, false otherwise.
+ */
+ public final boolean isPrimitiveType() {
+ return (this instanceof PrimitiveType);
+ }
+
+ /**
+ * Returns whether this type is a simple type or not.
+ *
+ * @return true if this type is a simple type, false otherwise.
+ */
+ public final boolean isSimpleType() {
+ return (this instanceof SimpleType);
+ }
+
+ /**
+ * Returns whether this type is a parameterized type or not.
+ *
+ * @return true if this type is a parameterized type, false otherwise.
+ */
+ public final boolean isParameterizedType() {
+ return (this instanceof ParameterizedType);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ast/TypeDeclaration.java b/src/main/java/ast/TypeDeclaration.java
new file mode 100644
index 0000000..4d4a3e5
--- /dev/null
+++ b/src/main/java/ast/TypeDeclaration.java
@@ -0,0 +1,85 @@
+package ast;
+
+import java.util.List;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+
+public class TypeDeclaration extends AbstractTypeDeclaration implements IAnnotatable {
+ private List fields = new ArrayList<>();
+ private List methods = new ArrayList<>();
+ private Map annotations = new HashMap<>();
+
+ public TypeDeclaration(String typeName) {
+ this.typeName = typeName;
+ }
+
+ public TypeDeclaration(String typeName, List fields) {
+ this.typeName = typeName;
+ this.fields = fields;
+ }
+
+ public TypeDeclaration(String typeName, List fields, List methods) {
+ this.typeName = typeName;
+ this.fields = fields;
+ this.methods = methods;
+ }
+
+ public void addField(FieldDeclaration field) {
+ fields.add(field);
+ }
+
+ public void addMethod(MethodDeclaration method) {
+ methods.add(method);
+ }
+
+ public void removeMethod(MethodDeclaration method) {
+ methods.remove(method);
+ }
+
+ public List getFields() {
+ return fields;
+ }
+
+ public List getMethods() {
+ return methods;
+ }
+
+ public MethodDeclaration createConstructor() {
+ MethodDeclaration constructor = new MethodDeclaration(typeName, true);
+ addMethod(constructor);
+ return constructor;
+ }
+
+ @Override
+ public Annotation getAnnotation(String name) {
+ return annotations.get(name);
+ }
+
+ @Override
+ public Collection getAnnotations() {
+ return annotations.values();
+ }
+
+ @Override
+ public void addAnnotation(Annotation annotation) {
+ annotations.put(annotation.getElementName(), annotation);
+ }
+
+ public String toString() {
+ String code = "";
+ for (Annotation annotation: getAnnotations()) {
+ code += annotation.toString() + "\n";
+ }
+ code += "public class " + typeName + " {\n";
+ for (FieldDeclaration f: fields) {
+ code += "\t" + f.toString();
+ }
+ for (MethodDeclaration m: methods) {
+ code += CodeUtil.insertTab(m.toString());
+ }
+ code += "}";
+ return code;
+ }
+}
diff --git a/src/main/java/ast/TypeLiteral.java b/src/main/java/ast/TypeLiteral.java
new file mode 100644
index 0000000..bc67baa
--- /dev/null
+++ b/src/main/java/ast/TypeLiteral.java
@@ -0,0 +1,32 @@
+package ast;
+
+/**
+ * Represents a type literal expression in the AST.
+ *
+ * @author s-yamagiwa
+ */
+public class TypeLiteral extends Expression {
+ private Type type;
+
+ public TypeLiteral(Type type) {
+ this.type = type;
+ }
+
+ @Override
+ public Expression replace(Variable variable, Expression expression) {
+ return this;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public void setType(Type type) {
+ this.type = type;
+ }
+
+ @Override
+ public String toString() {
+ return type.toString();
+ }
+}
diff --git a/src/main/java/ast/Variable.java b/src/main/java/ast/Variable.java
new file mode 100644
index 0000000..983870c
--- /dev/null
+++ b/src/main/java/ast/Variable.java
@@ -0,0 +1,35 @@
+package ast;
+
+/**
+ * Represents a variable in the AST (Abstract Syntax Tree)
+ *
+ * @author s-yamagiwa
+ */
+public class Variable extends Expression {
+ private String name;
+
+ public Variable(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public Expression replace(Variable variable, Expression expression) {
+ if (this == variable) {
+ return expression;
+ }
+ return this;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/src/main/java/ast/VariableDeclaration.java b/src/main/java/ast/VariableDeclaration.java
new file mode 100644
index 0000000..0b0a1e2
--- /dev/null
+++ b/src/main/java/ast/VariableDeclaration.java
@@ -0,0 +1,68 @@
+package ast;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import models.algebra.Type;
+
+public class VariableDeclaration extends ASTNode implements IAnnotatable {
+ private Type type;
+ private String variableName;
+ private Expression optionalInitializer;
+ private Map annotations = new HashMap<>();
+
+ public VariableDeclaration(Type type, String variableName) {
+ this.type = type;
+ this.variableName = variableName;
+ }
+
+ public VariableDeclaration(Type type, String variableName, Expression initializer) {
+ this(type, variableName);
+ this.optionalInitializer = initializer;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public void setType(Type type) {
+ this.type = type;
+ }
+
+ public String getName() {
+ return variableName;
+ }
+
+ public void setName(String variableName) {
+ this.variableName = variableName;
+ }
+
+ public Expression getInitializer() { return optionalInitializer; }
+
+ public void setInitializer(Expression initializer) { this.optionalInitializer = initializer; }
+
+ @Override
+ public Annotation getAnnotation(String name) {
+ return annotations.get(name);
+ }
+
+ @Override
+ public Collection getAnnotations() {
+ return annotations.values();
+ }
+
+ @Override
+ public void addAnnotation(Annotation annotation) {
+ annotations.put(annotation.getElementName(), annotation);
+ }
+
+ public String toString() {
+ String code = "";
+ code += type.getInterfaceTypeName() + " " + variableName;
+ if (optionalInitializer != null) {
+ code += " = " + optionalInitializer;
+ }
+ return code;
+ }
+}
diff --git a/src/main/java/ast/VariableDeclarationStatement.java b/src/main/java/ast/VariableDeclarationStatement.java
new file mode 100644
index 0000000..0bf64c4
--- /dev/null
+++ b/src/main/java/ast/VariableDeclarationStatement.java
@@ -0,0 +1,81 @@
+package ast;
+
+import java.util.ArrayList;
+import java.util.List;
+import models.algebra.Type;
+
+public class VariableDeclarationStatement extends Statement {
+
+ private List modifiers = new ArrayList<>();
+ private Type type = null;
+ private List fragments = new ArrayList<>();
+
+ public List getModifiers() {
+ return modifiers;
+ }
+
+ public void setModifiers(List modifiers) {
+ this.modifiers = modifiers;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public void setType(Type type) {
+ this.type = type;
+ }
+
+ public List getFragments() {
+ return fragments;
+ }
+
+ public void addFragment(VariableDeclaration fragment) {
+ if (fragment == null) return;
+
+ if (this.type == null) {
+ this.type = fragment.getType();
+ this.fragments.add(fragment);
+ } else {
+ if (this.type.equals(fragment.getType())) {
+ this.fragments.add(fragment);
+ } else {
+ System.err.println("Type mismatch: " + fragment);
+ }
+ }
+ }
+
+ public void setFragments(List fragments) {
+ this.fragments = fragments;
+
+ if (fragments != null && !fragments.isEmpty()) {
+ this.type = fragments.get(0).getType();
+ } else {
+ this.type = null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ for (Integer mod : modifiers) {
+ if (mod == Modifier.PRIVATE) sb.append("private ");
+ else if (mod == Modifier.PUBLIC) sb.append("public ");
+ else if (mod == Modifier.PROTECTED) sb.append("protected ");
+ else if (mod == Modifier.STATIC) sb.append("static ");
+ }
+
+ if (this.type != null) {
+ sb.append(this.type.getInterfaceTypeName()).append(" ");
+ }
+
+ for (int i = 0; i < fragments.size(); i++) {
+ sb.append(fragments.get(i).toString());
+ if (i < fragments.size() - 1) sb.append(", ");
+ }
+
+ sb.append(";");
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ast/WhileStatement.java b/src/main/java/ast/WhileStatement.java
new file mode 100644
index 0000000..2cd2aee
--- /dev/null
+++ b/src/main/java/ast/WhileStatement.java
@@ -0,0 +1,33 @@
+package ast;
+
+public class WhileStatement extends Statement {
+
+ private Expression expression;
+ private Statement body;
+
+ public Expression getExpression() {
+ return expression;
+ }
+
+ public void setExpression(Expression expression) {
+ this.expression = expression;
+ }
+
+ public Statement getBody() {
+ return body;
+ }
+
+ public void setBody(Statement body) {
+ this.body = body;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("while (").append(expression).append(") ");
+ if (body != null) {
+ sb.append(body);
+ }
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/models/DirectedGraph.java b/src/main/java/models/DirectedGraph.java
new file mode 100644
index 0000000..c9be668
--- /dev/null
+++ b/src/main/java/models/DirectedGraph.java
@@ -0,0 +1,71 @@
+package models;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class DirectedGraph {
+ private Set nodes = null;
+ private Set edges = null;
+
+ public DirectedGraph() {
+ nodes = new HashSet<>();
+ edges = new HashSet<>();
+ }
+
+ public Set getNodes() {
+ return nodes;
+ }
+
+ public void setNodes(Set nodes) {
+ this.nodes = nodes;
+ }
+
+ public void addNode(Node node) {
+ nodes.add(node);
+ }
+
+ public void removeNode(Node node) {
+ nodes.remove(node);
+ node.clearInEdges();
+ node.clearOutEdges();
+ for (Edge edge: edges) {
+ if (edge.getSource().equals(node)) {
+ edges.remove(edge);
+ } else if (edge.getDestination().equals(node)) {
+ edges.remove(edge);
+ }
+ }
+ }
+
+ public Set getEdges() {
+ return edges;
+ }
+
+ public void setEdges(Set edges) {
+ this.edges = edges;
+ for (Edge edge: edges) {
+ if (!nodes.contains(edge.getSource())) nodes.add(edge.getSource());
+ if (!nodes.contains(edge.getDestination())) nodes.add(edge.getDestination());
+ edge.getSource().addOutEdge(edge);
+ edge.getDestination().addInEdge(edge);
+ }
+ }
+
+ public void addEdge(Edge edge) {
+ edges.add(edge);
+ if (!nodes.contains(edge.getSource())) nodes.add(edge.getSource());
+ if (!nodes.contains(edge.getDestination())) nodes.add(edge.getDestination());
+ edge.getSource().addOutEdge(edge);
+ edge.getDestination().addInEdge(edge);
+ }
+
+ public void removeEdge(Edge edge) {
+ edges.remove(edge);
+ edge.getSource().removeOutEdge(edge);
+ edge.getDestination().removeInEdge(edge);
+ }
+
+ protected void simpleAddEdge(Edge edge) {
+ edges.add(edge);
+ }
+}
diff --git a/src/main/java/models/Edge.java b/src/main/java/models/Edge.java
new file mode 100644
index 0000000..8dd7cc0
--- /dev/null
+++ b/src/main/java/models/Edge.java
@@ -0,0 +1,36 @@
+package models;
+
+public class Edge {
+ protected Node source;
+ protected Node destination;
+ private EdgeAttribute attribute;
+
+ public Edge(Node src, Node dst) {
+ source = src;
+ destination = dst;
+ }
+
+ public Node getSource() {
+ return source;
+ }
+
+ public void setSource(Node source) {
+ this.source = source;
+ }
+
+ public Node getDestination() {
+ return destination;
+ }
+
+ public void setDestination(Node destination) {
+ this.destination = destination;
+ }
+
+ public EdgeAttribute getAttribute() {
+ return attribute;
+ }
+
+ public void setAttribute(EdgeAttribute attribute) {
+ this.attribute = attribute;
+ }
+}
diff --git a/src/main/java/models/EdgeAttribute.java b/src/main/java/models/EdgeAttribute.java
new file mode 100644
index 0000000..377b889
--- /dev/null
+++ b/src/main/java/models/EdgeAttribute.java
@@ -0,0 +1,5 @@
+package models;
+
+public class EdgeAttribute {
+
+}
diff --git a/src/main/java/models/Node.java b/src/main/java/models/Node.java
new file mode 100644
index 0000000..2eda554
--- /dev/null
+++ b/src/main/java/models/Node.java
@@ -0,0 +1,87 @@
+package models;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class Node implements Cloneable {
+ private Set inEdges = null;
+ private Set outEdges = null;
+ private NodeAttribute attribute;
+
+ public Node() {
+ inEdges = new HashSet<>();
+ outEdges = new HashSet<>();
+ }
+
+ public Set getInEdges() {
+ return inEdges;
+ }
+
+ public void setInEdges(Set inEdges) {
+ this.inEdges = inEdges;
+ }
+
+ public Set getOutEdges() {
+ return outEdges;
+ }
+
+ public void setOutEdges(Set outEdges) {
+ this.outEdges = outEdges;
+ }
+
+ public void addInEdge(Edge edge) {
+ inEdges.add(edge);
+ }
+
+ public void addOutEdge(Edge edge) {
+ outEdges.add(edge);
+ }
+
+ public void removeInEdge(Edge edge) {
+ inEdges.remove(edge);
+ }
+
+ public void removeOutEdge(Edge edge) {
+ outEdges.remove(edge);
+ }
+
+ public void clearInEdges() {
+ inEdges.clear();
+ }
+
+ public void clearOutEdges() {
+ outEdges.clear();
+ }
+
+ public int getIndegree() {
+ return inEdges.size();
+ }
+
+ public int getOutdegree() {
+ return outEdges.size();
+ }
+
+ public Set getPredecessors() {
+ Set predecessors = new HashSet();
+ for (Edge edge: inEdges) {
+ predecessors.add(edge.getSource());
+ }
+ return predecessors;
+ }
+
+ public Set getSuccessors() {
+ Set successors = new HashSet();
+ for (Edge edge: outEdges) {
+ successors.add(edge.getDestination());
+ }
+ return successors;
+ }
+
+ public NodeAttribute getAttribute() {
+ return attribute;
+ }
+
+ public void setAttribute(NodeAttribute attribute) {
+ this.attribute = attribute;
+ }
+}
diff --git a/src/main/java/models/NodeAttribute.java b/src/main/java/models/NodeAttribute.java
new file mode 100644
index 0000000..47b14d3
--- /dev/null
+++ b/src/main/java/models/NodeAttribute.java
@@ -0,0 +1,5 @@
+package models;
+
+public class NodeAttribute {
+
+}
diff --git a/src/main/java/models/algebra/Constant.java b/src/main/java/models/algebra/Constant.java
new file mode 100644
index 0000000..cec5666
--- /dev/null
+++ b/src/main/java/models/algebra/Constant.java
@@ -0,0 +1,54 @@
+package models.algebra;
+
+import generators.JavaImplementationVisitor;
+
+import java.util.ArrayList;
+
+public class Constant extends Term {
+
+ public Constant(String value) {
+ super(new Symbol(value, 0), new ArrayList());
+ }
+
+ public Constant(String value, Type type) {
+ super(new Symbol((type == null ? value : type.valueToRepresentation(value)), 0), new ArrayList());
+ symbol.setSignature(new Type[]{type});
+ }
+
+ public Constant(Symbol symbol) {
+ super(symbol);
+ }
+
+ @Override
+ public boolean equals(Object another) {
+ if (!(another instanceof Constant)) return false;
+ return symbol.equals(((Constant) another).symbol);
+ }
+
+ @Override
+ public Object clone() {
+ Constant c = new Constant(symbol);
+ c.setType(type);
+ return c;
+ }
+
+ public String toString() {
+ return symbol.getName();
+ }
+
+ public Object getValue() {
+ if (getType() != null) {
+ return getType().representationToValue(symbol.getName());
+ }
+ return symbol.getName();
+ }
+
+ public String toImplementation(String[] sideEffects) {
+ return accept(new JavaImplementationVisitor(), sideEffects).toString();
+ }
+
+ @Override
+ public T accept(IExpressionVisitor visitor, String[] sideEffects) {
+ return visitor.visit(this, sideEffects);
+ }
+}
diff --git a/src/main/java/models/algebra/Expression.java b/src/main/java/models/algebra/Expression.java
new file mode 100644
index 0000000..664cadb
--- /dev/null
+++ b/src/main/java/models/algebra/Expression.java
@@ -0,0 +1,46 @@
+package models.algebra;
+
+import java.util.HashMap;
+
+public abstract class Expression implements Cloneable {
+ public abstract Expression getSubTerm(Position pos);
+
+ /**
+ * Get the unification between this expression and another expression.
+ *
+ * @param another another expression
+ * @return unified expression
+ */
+ public abstract Expression unify(Expression another);
+
+ /**
+ * Get the inverse map to obtain a sub-term of a given output value back from the output value itself.
+ *
+ * @param outputValue an output value (usually a term)
+ * @param targetPos a position in outputValue
+ * @return inverse map
+ */
+ public abstract Expression getInverseMap(Expression outputValue, Position targetPos);
+
+ public abstract boolean contains(Expression exp);
+
+ public abstract Object clone();
+
+ public abstract HashMap getSubTerms(Class clazz);
+
+ public HashMap getVariables() {
+ return getSubTerms(Variable.class);
+ }
+
+ public abstract T accept(IExpressionVisitor visitor, String[] sideEffects);
+
+ /**
+ * Get the implementation of this expression.
+ *
+ * @param sideEffects an array with an optional implementation that should be written before the evaluation of this expression
+ * @return the implementation to represent the value of this expression
+ */
+ public String toImplementation(String[] sideEffects) {
+ return toString();
+ }
+}
diff --git a/src/main/java/models/algebra/Field.java b/src/main/java/models/algebra/Field.java
new file mode 100644
index 0000000..ff7b339
--- /dev/null
+++ b/src/main/java/models/algebra/Field.java
@@ -0,0 +1,52 @@
+package models.algebra;
+
+import generators.JavaImplementationVisitor;
+
+/**
+ * A field in the implementation (regarded as a constant in the algebraic system)
+ *
+ * @author Nitta
+ *
+ */
+public class Field extends Constant {
+
+ public Field(String name) {
+ super(name);
+ }
+
+ public Field(String name, Type type) {
+ super(name);
+ symbol.setSignature(new Type[]{type});
+ }
+
+ public Field(Symbol symbol) {
+ super(symbol);
+ }
+
+ public Type getType() {
+ if (symbol.getSignature() != null && symbol.getSignature().length >= 1) {
+ return symbol.getSignature()[0];
+ }
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object another) {
+ if (!(another instanceof Field)) return false;
+ return symbol.equals(((Field) another).symbol);
+ }
+
+ @Override
+ public Object clone() {
+ return new Field(symbol);
+ }
+
+ public String toImplementation(String[] sideEffects) {
+ return accept(new JavaImplementationVisitor(), sideEffects).toString();
+ }
+
+ @Override
+ public T accept(IExpressionVisitor visitor, String[] sideEffects) {
+ return visitor.visit(this, sideEffects);
+ }
+}
diff --git a/src/main/java/models/algebra/FutureWorkException.java b/src/main/java/models/algebra/FutureWorkException.java
new file mode 100644
index 0000000..0dad4bb
--- /dev/null
+++ b/src/main/java/models/algebra/FutureWorkException.java
@@ -0,0 +1,5 @@
+package models.algebra;
+
+public class FutureWorkException extends Exception {
+
+}
diff --git a/src/main/java/models/algebra/IExpressionVisitor.java b/src/main/java/models/algebra/IExpressionVisitor.java
new file mode 100644
index 0000000..4c30c09
--- /dev/null
+++ b/src/main/java/models/algebra/IExpressionVisitor.java
@@ -0,0 +1,18 @@
+package models.algebra;
+
+import models.dataConstraintModel.JsonAccessor;
+import models.dataConstraintModel.JsonTerm;
+
+public interface IExpressionVisitor {
+ T visit(Term term, String[] sideEffects);
+
+ T visit(Field field, String[] sideEffects);
+
+ T visit(Constant constant, String[] sideEffects);
+
+ T visit(Variable variable, String[] sideEffects);
+
+ T visit(JsonTerm jsonTerm, String[] sideEffects);
+
+ T visit(JsonAccessor jsonAccessor, String[] sideEffects);
+}
diff --git a/src/main/java/models/algebra/InvalidMessage.java b/src/main/java/models/algebra/InvalidMessage.java
new file mode 100644
index 0000000..de909e5
--- /dev/null
+++ b/src/main/java/models/algebra/InvalidMessage.java
@@ -0,0 +1,5 @@
+package models.algebra;
+
+public class InvalidMessage extends Exception {
+
+}
diff --git a/src/main/java/models/algebra/LambdaAbstraction.java b/src/main/java/models/algebra/LambdaAbstraction.java
new file mode 100644
index 0000000..9898224
--- /dev/null
+++ b/src/main/java/models/algebra/LambdaAbstraction.java
@@ -0,0 +1,30 @@
+package models.algebra;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LambdaAbstraction extends Symbol {
+ private List variables = null;
+ private Term term = null;
+
+ public LambdaAbstraction(Variable variable, Term term) {
+ super("($" + variable.getName() + ")->" + term.toString(), 1, Type.LAMBDA);
+ this.variables = new ArrayList<>();
+ this.variables.add(variable);
+ this.term = term;
+ }
+
+ public LambdaAbstraction(List variables, Term term) {
+ super("($" + variables + ")->" + term.toString(), variables.size(), Type.LAMBDA);
+ this.variables = variables;
+ this.term = term;
+ }
+
+ public List getVariables() {
+ return variables;
+ }
+
+ public Term getTerm() {
+ return term;
+ }
+}
diff --git a/src/main/java/models/algebra/Parameter.java b/src/main/java/models/algebra/Parameter.java
new file mode 100644
index 0000000..5403bc1
--- /dev/null
+++ b/src/main/java/models/algebra/Parameter.java
@@ -0,0 +1,40 @@
+package models.algebra;
+
+/**
+ * A parameter in the implementation (regarded as a constant in the algebraic system)
+ * @author Nitta
+ *
+ */
+public class Parameter extends Constant {
+
+ public Parameter(String name) {
+ super(name);
+ }
+
+ public Parameter(String name, Type type) {
+ super(name);
+ symbol.setSignature(new Type[] {type});
+ }
+
+ public Parameter(Symbol symbol) {
+ super(symbol);
+ }
+
+ public Type getType() {
+ if (symbol.getSignature() != null && symbol.getSignature().length >= 1) {
+ return symbol.getSignature()[0];
+ }
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object another) {
+ if (!(another instanceof Parameter)) return false;
+ return symbol.equals(((Parameter) another).symbol);
+ }
+
+ @Override
+ public Object clone() {
+ return new Parameter(symbol);
+ }
+}
diff --git a/src/main/java/models/algebra/ParameterizedIdentifierIsFutureWork.java b/src/main/java/models/algebra/ParameterizedIdentifierIsFutureWork.java
new file mode 100644
index 0000000..3a58863
--- /dev/null
+++ b/src/main/java/models/algebra/ParameterizedIdentifierIsFutureWork.java
@@ -0,0 +1,5 @@
+package models.algebra;
+
+public class ParameterizedIdentifierIsFutureWork extends FutureWorkException {
+
+}
diff --git a/src/main/java/models/algebra/Position.java b/src/main/java/models/algebra/Position.java
new file mode 100644
index 0000000..243e274
--- /dev/null
+++ b/src/main/java/models/algebra/Position.java
@@ -0,0 +1,52 @@
+package models.algebra;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Position implements Cloneable {
+ private ArrayList orders = new ArrayList();
+
+ public Position() {
+ }
+
+ public Position(ArrayList orders) {
+ this.orders = orders;
+ }
+
+ public void addHeadOrder(int order) {
+ orders.add(0, order);
+ }
+
+ public int removeHeadOrder() {
+ return orders.remove(0);
+ }
+
+ public List getOrders() {
+ return orders;
+ }
+
+ public boolean isEmpty() {
+ return (orders == null || orders.size() == 0);
+ }
+
+ public boolean isAncestorOf(Position another) {
+ if (another.orders.size() < this.orders.size()) return false;
+ for (int i = 0; i < orders.size(); i++) {
+ if (this.orders.get(i) != another.orders.get(i)) return false;
+ }
+ return true;
+ }
+
+ public Object clone() {
+ return new Position((ArrayList) orders.clone());
+ }
+
+ public boolean equals(Object another) {
+ if (!(another instanceof Position)) return false;
+ return orders.equals(((Position) another).orders);
+ }
+
+ public int hashCode() {
+ return orders.hashCode();
+ }
+}
diff --git a/src/main/java/models/algebra/Symbol.java b/src/main/java/models/algebra/Symbol.java
new file mode 100644
index 0000000..181f116
--- /dev/null
+++ b/src/main/java/models/algebra/Symbol.java
@@ -0,0 +1,333 @@
+package models.algebra;
+
+import java.util.List;
+
+import models.algebra.Symbol.IImplGenerator;
+import models.algebra.Symbol.Type;
+
+public class Symbol {
+ protected String name;
+ protected int arity = 0; // -1: variable number
+ protected Type operatorType = Type.PREFIX;
+ protected Symbol[] inverses = null;
+ protected models.algebra.Type[] signature = null;
+ protected ICalculator calculator = null;
+ protected SymbolImpl symbolImpl = null;
+
+ public Symbol(String name) {
+ this.name = name;
+ this.arity = 0;
+ this.symbolImpl = new SymbolImpl(name);
+ }
+
+ public Symbol(String name, int arity) {
+ this.name = name;
+ this.arity = arity;
+ this.symbolImpl = new SymbolImpl(name, arity);
+ }
+
+ public Symbol(String name, int arity, Type operatorType) {
+ this.name = name;
+ this.arity = arity;
+ this.operatorType = operatorType;
+ this.symbolImpl = new SymbolImpl(name, arity, operatorType);
+ }
+
+ public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType) {
+ this.name = name;
+ this.arity = arity;
+ this.operatorType = operatorType;
+ this.symbolImpl = new SymbolImpl(implName, arity, implOperatorType);
+ }
+
+ public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType, int[] implParamOrder) {
+ this(name, arity, operatorType, implName, implOperatorType);
+ this.symbolImpl.setImplParamOrder(implParamOrder);
+ }
+
+ public Symbol(String name, int arity, Type operatorType, IImplGenerator generator) {
+ this(name, arity, operatorType, name, Type.GENERATIVE);
+ this.symbolImpl.setGenerator(generator);
+ }
+
+ public Symbol(String name, int arity, Type operatorType, IImplGenerator generator, boolean bSideEffect) {
+ this(name, arity, operatorType, name, Type.GENERATIVE);
+ this.symbolImpl.setGenerator(generator);
+ if (bSideEffect) {
+ this.symbolImpl.setImplOperatorType(Type.GENERATIVE_WITH_SIDE_EFFECT);
+ }
+ }
+
+ public Symbol(String name, int arity, ICalculator calculator) {
+ this(name, arity);
+ this.calculator = calculator;
+ }
+
+ public Symbol(String name, int arity, Type operatorType, ICalculator calculator) {
+ this(name, arity, operatorType, name, operatorType);
+ this.calculator = calculator;
+ }
+
+ public Symbol(String name, int arity, Type operatorType, IImplGenerator generator, ICalculator calculator) {
+ this(name, arity, operatorType, name, Type.GENERATIVE);
+ this.calculator = calculator;
+ this.symbolImpl.setGenerator(generator);
+ }
+
+ public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType, ICalculator calculator) {
+ this(name, arity, operatorType, implName, implOperatorType);
+ this.calculator = calculator;
+ }
+
+ public void setArity(int arity) {
+ this.arity = arity;
+ }
+
+ public int getArity() {
+ return arity;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void changeName(String name) {
+ this.name = name;
+ this.symbolImpl.setImplName(name);
+ }
+
+ public Type getOperatorType() {
+ return operatorType;
+ }
+
+ public boolean isInfix() {
+ return (operatorType == Type.INFIX);
+ }
+
+ public boolean isMethod() {
+ return (operatorType == Type.METHOD || operatorType == Type.METHOD_WITH_SIDE_EFFECT);
+ }
+
+ public boolean isLambda() {
+ return (operatorType == Type.LAMBDA);
+ }
+
+ public Symbol[] getInverses() {
+ return inverses;
+ }
+
+ public void setInverses(Symbol[] inverses) {
+ this.inverses = inverses;
+ }
+
+ public models.algebra.Type[] getSignature() {
+ return signature;
+ }
+
+ public void setSignature(models.algebra.Type[] signature) {
+ this.signature = signature;
+ }
+
+ public String getImplName() {
+ return symbolImpl.getImplName();
+ }
+
+ public void setImplName(String implName) {
+ this.symbolImpl.setImplName(implName);
+ }
+
+ public Type getImplOperatorType() {
+ return symbolImpl.getImplOperatorType();
+ }
+
+ public boolean isImplInfix() {
+ return (symbolImpl.getImplOperatorType() == Type.INFIX);
+ }
+
+ public boolean isImplMethod() {
+ return (symbolImpl.getImplOperatorType() == Type.METHOD || symbolImpl.getImplOperatorType() == Type.METHOD_WITH_SIDE_EFFECT);
+ }
+
+ public boolean isImplLambda() {
+ return (symbolImpl.getImplOperatorType() == Type.LAMBDA || symbolImpl.getImplOperatorType() == Type.LAMBDA_WITH_SIDE_EFFECT);
+ }
+
+ public boolean isImplGenerative() {
+ return (symbolImpl.getImplOperatorType() == Type.GENERATIVE || symbolImpl.getImplOperatorType() == Type.GENERATIVE_WITH_SIDE_EFFECT);
+ }
+
+ public boolean isImplWithSideEffect() {
+ return (symbolImpl.getImplOperatorType() == Type.METHOD_WITH_SIDE_EFFECT
+ || symbolImpl.getImplOperatorType() == Type.LAMBDA_WITH_SIDE_EFFECT
+ || symbolImpl.getImplOperatorType() == Type.GENERATIVE_WITH_SIDE_EFFECT);
+ }
+
+ public void setImplOperatorType(Type implOperatorType) {
+ this.symbolImpl.setImplOperatorType(implOperatorType);
+ }
+
+ public int[] getImplParamOrder() {
+ return symbolImpl.getImplParamOrder();
+ }
+
+ public void setGenerator(IImplGenerator generator) {
+ this.symbolImpl.setGenerator(generator);
+ }
+
+ /**
+ * Generate the implementation of this symbol
+ * @param type the type of this symbol
+ * @param childrenTypes
+ * @param childrenImpl the implementations of the children
+ * @param childrenSideEffects (input) an array of the side effects of the children
+ * @param sideEffect (output) an array of the side effect of this symbol
+ * @return the implementation
+ */
+ public String generate(models.algebra.Type type, models.algebra.Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) {
+ if (symbolImpl.getGenerator() != null) {
+ return symbolImpl.getGenerator().generate(type, childrenTypes, childrenImpl, childrenSideEffects, sideEffect);
+ }
+ return null;
+ }
+
+ public boolean isCalculatable() {
+ return (calculator != null);
+ }
+
+ public Expression calculate(List args) {
+ if (calculator != null) {
+ return calculator.calculate(args);
+ }
+ return null;
+ }
+
+ public boolean equals(Object another) {
+ if (!(another instanceof Symbol)) return false;
+ return name.equals(((Symbol) another).name) && arity == ((Symbol) another).arity;
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ public String toString() {
+ return name;
+ }
+
+ public String toImplementation() {
+ return symbolImpl.getImplName();
+ }
+
+ public enum Type {
+ PREFIX,
+ INFIX,
+ METHOD,
+ METHOD_WITH_SIDE_EFFECT,
+ LAMBDA,
+ LAMBDA_WITH_SIDE_EFFECT,
+ GENERATIVE,
+ GENERATIVE_WITH_SIDE_EFFECT
+ }
+
+ public static class SymbolImpl {
+ private String implName;
+ protected int implArity = 0; // -1: variable number
+ private Type implOperatorType;
+ private int[] implParamOrder;
+ private IImplGenerator generator;
+
+ public SymbolImpl(String implName) {
+ this.implName = implName;
+ this.implArity = 0;
+ }
+
+ public SymbolImpl(String implName, int implArity) {
+ this.implName = implName;
+ this.implArity = implArity;
+ }
+
+ public SymbolImpl(String implName, int implArity, Type implOperatorType) {
+ this(implName, implArity);
+ this.implOperatorType = implOperatorType;
+ }
+
+ public SymbolImpl(String implName, int implArity, Type implOperatorType, int[] implParamOrder) {
+ this(implName, implArity, implOperatorType);
+ this.implParamOrder = implParamOrder;
+ }
+
+ public SymbolImpl(String implName, int implArity, Type implOperatorType, int[] implParamOrder, IImplGenerator generator) {
+ this(implName, implArity, implOperatorType, implParamOrder);
+ this.generator = generator;
+ }
+
+ public String getImplName() {
+ return implName;
+ }
+
+ public void setImplName(String implName) {
+ this.implName = implName;
+ }
+
+ public Type getImplOperatorType() {
+ return implOperatorType;
+ }
+
+ public void setImplOperatorType(Type implOperatorType) {
+ this.implOperatorType = implOperatorType;
+ }
+
+ public int[] getImplParamOrder() {
+ return implParamOrder;
+ }
+
+ public void setImplParamOrder(int[] implParamOrder) {
+ this.implParamOrder = implParamOrder;
+ }
+
+ public IImplGenerator getGenerator() {
+ return generator;
+ }
+
+ public void setGenerator(IImplGenerator generator) {
+ this.generator = generator;
+ }
+ }
+
+ public Memento createMemento() {
+ return new Memento(symbolImpl.getImplName(), symbolImpl.getImplOperatorType());
+ }
+
+ public void setMemento(Memento memento) {
+ this.symbolImpl.setImplName(memento.implName);
+ this.symbolImpl.setImplOperatorType(memento.implOperatorType);
+ }
+
+ public static class Memento {
+ private String implName;
+ private Type implOperatorType = Type.PREFIX;
+
+ public Memento(String implName, Type implOperatorType) {
+ this.implName = implName;
+ this.implOperatorType = implOperatorType;
+ }
+ }
+
+ public interface IImplGenerator {
+ /**
+ * Generate the implementation
+ * @param type the type of this expression
+ * @param childrenTypes
+ * @param children the implementations of the children
+ * @param childrenSideEffects (input) an array of the side effects of the children
+ * @param sideEffect (output) an array of the side effect of this generator
+ * @return the generated implementation
+ */
+ public String generate(models.algebra.Type type, models.algebra.Type[] childrenTypes, String children[], String[] childrenSideEffects, String[] sideEffect);
+ }
+
+ public interface ICalculator {
+ public Expression calculate(List args);
+ }
+}
diff --git a/src/main/java/models/algebra/Term.java b/src/main/java/models/algebra/Term.java
new file mode 100644
index 0000000..3a74b89
--- /dev/null
+++ b/src/main/java/models/algebra/Term.java
@@ -0,0 +1,322 @@
+package models.algebra;
+
+import generators.JavaImplementationVisitor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map.Entry;
+
+public class Term extends Expression {
+ protected Symbol symbol = null;
+ protected List children = new ArrayList<>();
+ protected Type type = null;
+
+ public Term(Symbol symbol) {
+ super();
+ this.symbol = symbol;
+ }
+
+ public Term(Symbol symbol, List children) {
+ super();
+ this.symbol = symbol;
+ this.children = children;
+ }
+
+ public Term(Symbol symbol, Expression[] children) {
+ super();
+ this.symbol = symbol;
+ this.children = new ArrayList<>(Arrays.asList(children));
+ }
+
+ public Symbol getSymbol() {
+ return symbol;
+ }
+
+ public int getArity() {
+ return symbol.getArity();
+ }
+
+ public void setType(Type type) {
+ this.type = type;
+ }
+
+ public Type getType() {
+ if (type == null) {
+ if (symbol.getSignature() == null) return null;
+ return symbol.getSignature()[0];
+ }
+ return type;
+ }
+
+ public boolean addChild(Expression child) {
+ if (getArity() != -1 && children.size() >= getArity()) return false;
+ children.add(child);
+ return true;
+ }
+
+ public boolean setChild(int n, Expression child) {
+ if (getArity() != -1 && n >= getArity()) return false;
+ children.set(n, child);
+ return true;
+ }
+
+ public void addChild(Expression child, boolean bForced) {
+ if (!bForced && getArity() != -1 && children.size() >= getArity()) return;
+ children.add(child);
+ }
+
+ public void addChild(int n, Expression child, boolean bForced) {
+ if (!bForced && getArity() != -1 && children.size() >= getArity()) return;
+ children.add(n, child);
+ }
+
+ public Expression getChild(int n) {
+ return children.get(n);
+ }
+
+ public List getChildren() {
+ return children;
+ }
+
+ public HashMap getSubTerms(Class clazz) {
+ HashMap subTerms = new HashMap<>();
+ Class thisClass = this.getClass();
+ while (thisClass != null) {
+ if (clazz == thisClass) {
+ subTerms.put(new Position(), (T) this);
+ break;
+ }
+ thisClass = thisClass.getSuperclass();
+ }
+ for (int i = 0; i < children.size(); i++) {
+ if (children.get(i) != null) {
+ HashMap terms = children.get(i).getSubTerms(clazz);
+ for (Entry term : terms.entrySet()) {
+ Position pos = term.getKey();
+ pos.addHeadOrder(i);
+ subTerms.put(pos, term.getValue());
+ }
+ }
+ }
+ return subTerms;
+ }
+
+ public Expression getSubTerm(Position pos) {
+ if (pos.isEmpty()) return this;
+ pos = (Position) pos.clone();
+ int i = pos.removeHeadOrder();
+ if (i >= children.size()) return null;
+ if (children.get(i) == null) return null;
+ return children.get(i).getSubTerm(pos);
+ }
+
+ public Term substitute(Variable variable, Expression value) {
+ Term newTerm = (Term) this.clone();
+ HashMap variables = getVariables();
+ for (Entry varEnt : variables.entrySet()) {
+ if (varEnt.getValue().equals(variable)) {
+ newTerm.replaceSubTerm(varEnt.getKey(), value);
+ }
+ }
+ return newTerm;
+ }
+
+ public void replaceSubTerm(Position pos, Expression newSubTerm) {
+ if (pos.isEmpty()) return;
+ pos = (Position) pos.clone();
+ int i = pos.removeHeadOrder();
+ if (pos.isEmpty()) {
+ children.set(i, newSubTerm);
+ } else {
+ if (!(children.get(i) instanceof Term)) return;
+ ((Term) children.get(i)).replaceSubTerm(pos, newSubTerm);
+ }
+ }
+
+ @Override
+ public Expression unify(Expression another) {
+ if (another instanceof Variable) return (Expression) this.clone();
+ if (this instanceof Constant) return (Expression) this.clone();
+ if (another instanceof Constant) return (Expression) another.clone();
+ if (another instanceof Term) {
+ Term anotherTerm = (Term) another;
+ if (!symbol.equals(anotherTerm.symbol)) return null;
+ if (children.size() != anotherTerm.children.size()) return null;
+ Term unifiedTerm = new Term(symbol);
+ for (int i = 0; i < children.size(); i++) {
+ if (children.get(i) != null) {
+ unifiedTerm.addChild(children.get(i).unify(anotherTerm.children.get(i)));
+ } else {
+ unifiedTerm.addChild(anotherTerm.children.get(i));
+ }
+ }
+ return unifiedTerm;
+ } else {
+ return null;
+ }
+ }
+
+ public Expression reduce() {
+ if (symbol.isLambda()) {
+ // Lambda beta-reduction
+ LambdaAbstraction newSymbol = ((LambdaAbstraction) symbol);
+ Term newTerm = newSymbol.getTerm();
+ List newVariables = newSymbol.getVariables();
+ List newChildren = children;
+ while (newVariables.size() > 0 && newChildren.size() > 0) {
+ newTerm = newTerm.substitute(newVariables.get(0), newChildren.get(0));
+ newVariables = newVariables.subList(1, newVariables.size());
+ newChildren = newChildren.subList(1, newChildren.size());
+ newSymbol = new LambdaAbstraction(newVariables, newTerm);
+ }
+ if (newSymbol.arity == 0 && newChildren.size() == 0) {
+ return newTerm;
+ } else {
+ return new Term(newSymbol, newChildren);
+ }
+ } else if (symbol.isCalculatable()) {
+ List newChildren = new ArrayList<>();
+ for (Expression child : children) {
+ if (child instanceof Term) {
+ child = ((Term) child).reduce();
+ }
+ newChildren.add(child);
+ }
+ Expression newTerm = symbol.calculate(newChildren);
+ if (newTerm == null) return this;
+ return newTerm;
+ } else {
+ // Calculate inverse map
+ List newChildren = new ArrayList<>();
+ boolean bReduced = false;
+ for (Expression child : children) {
+ if (child instanceof Term && !(child instanceof Constant)) {
+ Expression newChild = ((Term) (child)).reduce();
+ if (newChild != child) {
+ bReduced = true;
+ child = newChild;
+ }
+ }
+ newChildren.add(child);
+ }
+ if (symbol.arity == 1 && newChildren.size() == 1) {
+ Expression child = newChildren.get(0);
+ if (child instanceof Term && !(child instanceof Constant)) {
+ Symbol childSymbol = ((Term) child).getSymbol();
+ if (childSymbol.getInverses() != null) {
+ for (int i = 0; i < childSymbol.getInverses().length; i++) {
+ if (symbol.equals(childSymbol.getInverses()[i])) {
+ return ((Term) child).getChild(i);
+ }
+ }
+ }
+ }
+ }
+ if (!bReduced) return this;
+ Term newTerm = (Term) this.clone();
+ newTerm.children = newChildren;
+ return newTerm;
+ }
+ }
+
+ @Override
+ public Expression getInverseMap(Expression outputValue, Position targetPos) {
+ if (targetPos.isEmpty()) return outputValue;
+ targetPos = (Position) targetPos.clone();
+ int i = targetPos.removeHeadOrder();
+ Symbol[] inverseSymbols = symbol.getInverses();
+ if (inverseSymbols == null || i >= inverseSymbols.length || inverseSymbols[i] == null) return null;
+ Term inverseMap = new Term(inverseSymbols[i]);
+ inverseMap.addChild(outputValue);
+ for (int n = 0; n < inverseSymbols[i].getArity(); n++) {
+ if (n != i) {
+ inverseMap.addChild(children.get(n));
+ }
+ }
+ return children.get(i).getInverseMap(inverseMap, targetPos);
+ }
+
+ @Override
+ public boolean contains(Expression exp) {
+ if (equals(exp)) return true;
+ for (Expression e : children) {
+ if (e.contains(exp)) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object another) {
+ if (!(another instanceof Term)) return false;
+ if (this == another) return true;
+ Term anotherTerm = (Term) another;
+ if (!symbol.equals(anotherTerm.symbol)) return false;
+ if (children.size() != anotherTerm.children.size()) return false;
+ if (type != anotherTerm.type) return false;
+ for (int i = 0; i < children.size(); i++) {
+ Expression e = children.get(i);
+ Expression e2 = anotherTerm.children.get(i);
+ if (!e.equals(e2)) return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return symbol.hashCode();
+ }
+
+
+ @Override
+ public Object clone() {
+ Term newTerm = new Term(symbol);
+ for (Expression e : children) {
+ if (e != null) {
+ newTerm.addChild((Expression) e.clone());
+ } else {
+ newTerm.addChild(null);
+ }
+ }
+ newTerm.type = type;
+ return newTerm;
+ }
+
+ public String toString() {
+ if (getArity() == 2 && symbol.isInfix()) {
+ return "(" + children.get(0) + symbol.toString() + children.get(1) + ")";
+ }
+ if ((getArity() >= 1 || getArity() == -1) && symbol.isMethod()) {
+ String exp = children.get(0).toString() + "." + symbol.toString() + "(";
+ String delimiter = "";
+ for (int i = 1; i < children.size(); i++) {
+ Expression e = children.get(i);
+ exp += (delimiter + e.toString());
+ delimiter = ",";
+ }
+ return exp + ")";
+ } else {
+ String exp = symbol.toString() + "(";
+ String delimiter = "";
+ for (Expression e : children) {
+ if (e != null) {
+ exp += (delimiter + e.toString());
+ } else {
+ exp += (delimiter + "null");
+ }
+ delimiter = ",";
+ }
+ return exp + ")";
+ }
+ }
+
+ public String toImplementation(String[] sideEffects) {
+ return accept(new JavaImplementationVisitor(), sideEffects).toString();
+ }
+
+ @Override
+ public T accept(IExpressionVisitor visitor, String[] sideEffects) {
+ return visitor.visit(this, sideEffects);
+ }
+}
diff --git a/src/main/java/models/algebra/Type.java b/src/main/java/models/algebra/Type.java
new file mode 100644
index 0000000..287273f
--- /dev/null
+++ b/src/main/java/models/algebra/Type.java
@@ -0,0 +1,129 @@
+package models.algebra;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Type {
+ private String typeName;
+// private String implementationTypeName;
+// private String interfaceTypeName;
+ private List parentTypes = new ArrayList<>();
+ private ITypeImpl implementationType;
+ private ITypeImpl interfaceType;
+
+ public Type(String typeName, ITypeImpl implementationType) {
+ this.typeName = typeName;
+ this.implementationType = implementationType;
+ this.interfaceType = implementationType;
+ }
+
+ public Type(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType) {
+ this.typeName = typeName;
+ this.implementationType = implementationType;
+ this.interfaceType = interfaceType;
+ }
+
+ public Type(String typeName, ITypeImpl implementationType, Type parentType) {
+ this.typeName = typeName;
+ this.implementationType = implementationType;
+ this.interfaceType = implementationType;
+ this.parentTypes.add(parentType);
+ }
+
+ public Type(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentType) {
+ this.typeName = typeName;
+ this.implementationType = implementationType;
+ this.interfaceType = interfaceType;
+ this.parentTypes.add(parentType);
+ }
+
+ public String getTypeName() {
+ return typeName;
+ }
+
+ public void setTypeName(String typeName) {
+ this.typeName = typeName;
+ }
+
+ public ITypeImpl getImplementationType() {
+ return implementationType;
+ }
+
+ public String getImplementationTypeName() {
+ return implementationType.toString();
+ }
+
+ public ITypeImpl getInterfaceType() {
+ return interfaceType;
+ }
+
+ public String getInterfaceTypeName() {
+ return interfaceType.toString();
+ }
+
+ public List getParentTypes() {
+ return parentTypes;
+ }
+
+ public void addParentType(Type parentType) {
+ parentTypes.add(parentType);
+ }
+
+ public void replaceParentType(Type oldParentType, Type newParentType) {
+ parentTypes.set(parentTypes.indexOf(oldParentType), newParentType);
+ }
+
+ public boolean isAncestorOf(Type another) {
+ if (this.equals(another)) return true;
+ if (another == null || another.getParentTypes() == null) return false;
+ for (Type anothersParentType: another.getParentTypes()) {
+ if (isAncestorOf(anothersParentType)) return true;
+ }
+ return false;
+ }
+
+ public String valueToRepresentation(Object value) {
+ if (value instanceof String) return (String) value;
+ return value.toString();
+ }
+
+ public Object representationToValue(String representation) {
+ return representation;
+ }
+
+ @Override
+ public boolean equals(Object another) {
+ if (this == another) return true;
+ if (another == null) return false;
+ if (!(another instanceof Type)) return false;
+ if (!typeName.equals(((Type) another).typeName)) return false;
+ if (!implementationType.equals(((Type) another).implementationType)) return false;
+ if (!interfaceType.equals(((Type) another).interfaceType)) return false;
+ return true;
+ }
+
+ public interface ITypeImpl {
+ }
+
+ public Memento createMemento() {
+ return new Memento(implementationType, interfaceType, parentTypes);
+ }
+
+ public void setMemento(Memento memento) {
+ this.implementationType = memento.implementationType;
+ this.interfaceType = memento.interfaceType;
+ this.parentTypes = memento.parentTypes;
+ }
+
+ public static class Memento {
+ private ITypeImpl implementationType;
+ private ITypeImpl interfaceType;
+ private List parentTypes;
+
+ public Memento(ITypeImpl implementationType, ITypeImpl interfaceType, List parentTypes) {
+ this.implementationType = implementationType;
+ this.interfaceType = interfaceType;
+ this.parentTypes = parentTypes;
+ }
+ }
+}
diff --git a/src/main/java/models/algebra/UnificationFailed.java b/src/main/java/models/algebra/UnificationFailed.java
new file mode 100644
index 0000000..46e06a7
--- /dev/null
+++ b/src/main/java/models/algebra/UnificationFailed.java
@@ -0,0 +1,5 @@
+package models.algebra;
+
+public class UnificationFailed extends Exception {
+
+}
diff --git a/src/main/java/models/algebra/ValueUndefined.java b/src/main/java/models/algebra/ValueUndefined.java
new file mode 100644
index 0000000..61dab0e
--- /dev/null
+++ b/src/main/java/models/algebra/ValueUndefined.java
@@ -0,0 +1,5 @@
+package models.algebra;
+
+public class ValueUndefined extends Exception {
+
+}
diff --git a/src/main/java/models/algebra/Variable.java b/src/main/java/models/algebra/Variable.java
new file mode 100644
index 0000000..bc07e42
--- /dev/null
+++ b/src/main/java/models/algebra/Variable.java
@@ -0,0 +1,94 @@
+package models.algebra;
+
+import generators.JavaImplementationVisitor;
+
+import java.util.HashMap;
+
+public class Variable extends Expression {
+ private String name;
+ private Type type = null;
+
+ public Variable(String name) {
+ super();
+ this.name = name;
+ }
+
+ public Variable(String name, Type type) {
+ super();
+ this.name = name;
+ this.type = type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public void setType(Type type) {
+ this.type = type;
+ }
+
+ @Override
+ public HashMap getSubTerms(Class clazz) {
+ HashMap subTerms = new HashMap<>();
+ if (clazz == this.getClass()) {
+ subTerms.put(new Position(), (T) this);
+ }
+ return subTerms;
+ }
+
+ @Override
+ public Expression getSubTerm(Position pos) {
+ if (pos.isEmpty()) return this;
+ return null;
+ }
+
+ @Override
+ public Expression unify(Expression another) {
+ return (Expression) another.clone();
+ }
+
+ @Override
+ public Expression getInverseMap(Expression outputValue, Position targetPos) {
+ if (targetPos.isEmpty()) return outputValue;
+ return null;
+ }
+
+ @Override
+ public boolean contains(Expression exp) {
+ return equals(exp);
+ }
+
+ @Override
+ public boolean equals(Object another) {
+ if (!(another instanceof Variable)) return false;
+ return name.equals(((Variable) another).name);
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ @Override
+ public Object clone() {
+ return new Variable(name, type);
+ }
+
+ public String toString() {
+ if (type == null) return name;
+ return name + ":" + type.getTypeName();
+ }
+
+ public String toImplementation(String[] sideEffects) {
+ return accept(new JavaImplementationVisitor(), sideEffects).toString();
+ }
+
+ @Override
+ public T accept(IExpressionVisitor visitor, String[] sideEffects) {
+ return visitor.visit(this, sideEffects);
+ }
+}