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); + } +}