From 561eafbf4c6da40f7b7553973b49017f84b2cd18 Mon Sep 17 00:00:00 2001 From: Bruder John Date: Tue, 2 Jul 2024 08:48:37 +0200 Subject: [PATCH 1/4] fixed constructor node parameter decleration --- .../java/ast/members/ConstructorNode.java | 5 +- src/main/java/semantic/Scope.java | 2 +- src/main/java/semantic/SemanticAnalyzer.java | 76 +++++++++---------- .../typedAstFeaturesTests/CorrectTest.java | 35 +-------- 4 files changed, 42 insertions(+), 76 deletions(-) diff --git a/src/main/java/ast/members/ConstructorNode.java b/src/main/java/ast/members/ConstructorNode.java index 2d5400d..b3fda52 100644 --- a/src/main/java/ast/members/ConstructorNode.java +++ b/src/main/java/ast/members/ConstructorNode.java @@ -9,13 +9,10 @@ import java.util.List; import java.util.Objects; public class ConstructorNode extends MethodNode { - public AccessModifierNode accessType; public String identifier; - public List parameters = new ArrayList<>(); - public BlockNode block; public ConstructorNode(String accessType, String identifier, BlockNode block) { - this.accessType = new AccessModifierNode(accessType); + this.accesModifier = new AccessModifierNode(accessType); this.identifier = identifier; this.block = block; } diff --git a/src/main/java/semantic/Scope.java b/src/main/java/semantic/Scope.java index b6b40c4..cde47c0 100644 --- a/src/main/java/semantic/Scope.java +++ b/src/main/java/semantic/Scope.java @@ -16,7 +16,7 @@ public class Scope { public void addLocalVar(String name, ITypeNode type) { if (this.contains(name)) { - throw new AlreadyDeclaredException("Variable " + name + " already exists in this scope"); + SemanticAnalyzer.errors.add(new AlreadyDeclaredException("Duplicate local variable " + name)); } localVars.peek().put(name, type); } diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index 6ebd124..06fe7e4 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -112,53 +112,49 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(MethodNode methodNode) { - if (methodNode instanceof ConstructorNode) { - return new TypeCheckResult(true, new BaseType(TypeEnum.VOID)); - } else { - var valid = true; + var valid = true; - for (var otherMethod : currentClass.getMethods()) { - if (Objects.equals(otherMethod, methodNode)) - break; - if (otherMethod.isSame(methodNode)) { - errors.add(new AlreadyDeclaredException( - "Method " + methodNode.getIdentifier() + " is already defined in class " - + currentClass.identifier)); - valid = false; - } + for (var otherMethod : currentClass.getMethods()) { + if (Objects.equals(otherMethod, methodNode)) + break; + if (otherMethod.isSame(methodNode)) { + errors.add(new AlreadyDeclaredException( + "Method " + methodNode.getIdentifier() + " is already defined in class " + + currentClass.identifier)); + valid = false; } + } - currentScope.pushScope(); - for (var parameter : methodNode.getParameters()) { - var result = parameter.accept(this); - valid = valid && result.isValid(); - try { - currentScope.addLocalVar(parameter.identifier, parameter.type); - } catch (AlreadyDeclaredException e) { - errors.add(new AlreadyDeclaredException(parameter.identifier)); - } - - } - - currentMethodReturnType = methodNode.getType(); - currentNullType = currentMethodReturnType; - - var result = methodNode.block.accept(this); + currentScope.pushScope(); + for (var parameter : methodNode.getParameters()) { + var result = parameter.accept(this); valid = valid && result.isValid(); - currentScope.popScope(); - ITypeNode resultType = result.getType(); - - if (resultType == null) { - resultType = new BaseType(TypeEnum.VOID); + try { + currentScope.addLocalVar(parameter.identifier, parameter.type); + } catch (AlreadyDeclaredException e) { + errors.add(new AlreadyDeclaredException(parameter.identifier)); } - if (methodNode.getType() == null) { - methodNode.setType(new BaseType(TypeEnum.VOID)); - } - - return new TypeCheckResult(valid, resultType); } + + currentMethodReturnType = methodNode.getType(); + currentNullType = currentMethodReturnType; + + var result = methodNode.block.accept(this); + valid = valid && result.isValid(); + currentScope.popScope(); + ITypeNode resultType = result.getType(); + + if (resultType == null) { + resultType = new BaseType(TypeEnum.VOID); + } + if (methodNode.getType() == null) { + methodNode.setType(new BaseType(TypeEnum.VOID)); + } + + return new TypeCheckResult(valid, resultType); + } @Override @@ -224,7 +220,7 @@ public class SemanticAnalyzer implements SemanticVisitor { } for (IStatementNode statementNode : blockNode.statements) { var result = statementNode.accept(this); - if(!(statementNode instanceof IncrementNode) && !(statementNode instanceof DecrementNode)){ + if (!(statementNode instanceof IncrementNode) && !(statementNode instanceof DecrementNode)) { if (result.getType() != null) { if (blockReturnType == null) { blockReturnType = result.getType(); diff --git a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java index 5ef0b26..828f6f3 100644 --- a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java +++ b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java @@ -1,38 +1,11 @@ public class AllFeaturesClassExample { - int a; - boolean b; - char c; - - public void controlStructures(int adf, boolean bool) { - if (a > (10 + 8)) { - } else { - } - - - while (a > adf) { - a--; - } - - for (int i = 0; i < 5; i++) { - } + public void controlStructures(int a, boolean b) { } -// void logicalOperations() { - // Logische UND-Operation -// if (b && a > 5) { -// System.out.println("a ist größer als 5 und b ist wahr"); -// } + public AllFeaturesClassExample(boolean b){ + + } - // Logische ODER-Operation -// if (b || a < 5) { -// System.out.println("b ist wahr oder a ist kleiner als 5"); -// } -// } - -// public static void main(String[] args) { -// AllFeaturesClassExample obj = new AllFeaturesClassExample(12, true, 'a'); -// obj.controlStructures(); -// } } From 82356ec189ee94936c41b2442bfa9ef6d5d8664e Mon Sep 17 00:00:00 2001 From: Bruder John Date: Tue, 2 Jul 2024 10:36:22 +0200 Subject: [PATCH 2/4] set types of expressions --- .../java/ast/members/ConstructorNode.java | 1 - src/main/java/ast/members/MethodNode.java | 2 +- src/main/java/semantic/SemanticAnalyzer.java | 18 +++++- .../DuplicatedConstructor.java | 12 ++++ .../ConstructorOverloading.java | 11 ++++ .../typedAstFeaturesTests/CorrectTest.java | 61 +++++++++++++++++-- 6 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 src/test/resources/input/typedAstExceptionsTests/DuplicatedConstructor.java create mode 100644 src/test/resources/input/typedAstFeaturesTests/ConstructorOverloading.java diff --git a/src/main/java/ast/members/ConstructorNode.java b/src/main/java/ast/members/ConstructorNode.java index b3fda52..71e6d89 100644 --- a/src/main/java/ast/members/ConstructorNode.java +++ b/src/main/java/ast/members/ConstructorNode.java @@ -9,7 +9,6 @@ import java.util.List; import java.util.Objects; public class ConstructorNode extends MethodNode { - public String identifier; public ConstructorNode(String accessType, String identifier, BlockNode block) { this.accesModifier = new AccessModifierNode(accessType); diff --git a/src/main/java/ast/members/MethodNode.java b/src/main/java/ast/members/MethodNode.java index 1345508..a083ca4 100644 --- a/src/main/java/ast/members/MethodNode.java +++ b/src/main/java/ast/members/MethodNode.java @@ -17,7 +17,7 @@ public class MethodNode implements MemberNode, Visitable { public AccessModifierNode accesModifier; private ITypeNode type; public Boolean voidType; - private String identifier; + protected String identifier; public List parameters = new ArrayList<>(); public BlockNode block; diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index 06fe7e4..5906d16 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -405,6 +405,7 @@ public class SemanticAnalyzer implements SemanticVisitor { case PLUS, MINUS: if (calcRes.getType() instanceof BaseType calcType && dotRes.getType() instanceof BaseType dotType && calcType.getTypeEnum().equals(TypeEnum.INT) && dotType.getTypeEnum().equals(TypeEnum.INT)) { + calcNode.setType(new BaseType(TypeEnum.INT)); return new TypeCheckResult(true, new BaseType(TypeEnum.INT)); } break; @@ -412,10 +413,12 @@ public class SemanticAnalyzer implements SemanticVisitor { } } else { + calcNode.setType(calcRes.getType()); return new TypeCheckResult(calcRes.isValid(), calcRes.getType()); } } else if (calcNode.dotExpression != null) { var dotRes = calcNode.dotExpression.accept(this); + calcNode.setType(dotRes.getType()); return new TypeCheckResult(dotRes.isValid(), dotRes.getType()); } return new TypeCheckResult(false, null); @@ -458,6 +461,7 @@ public class SemanticAnalyzer implements SemanticVisitor { case LESS, LESS_EQUAL, GREATER, GREATER_EQUAL: if (expResult.getType() instanceof BaseType expResultType && expResultType.getTypeEnum().equals(TypeEnum.INT) && unaryResult.getType() instanceof BaseType unaryResultType && unaryResultType.getTypeEnum().equals(TypeEnum.INT)) { + nonCalculationNode.setType(new BaseType(TypeEnum.BOOL)); return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL)); } else { errors.add(new TypeMismatchException("Both types must be Integer")); @@ -466,6 +470,7 @@ public class SemanticAnalyzer implements SemanticVisitor { case OR, AND: if (expResult.getType() instanceof BaseType expResultType && expResultType.getTypeEnum().equals(TypeEnum.INT) && unaryResult.getType() instanceof BaseType unaryResultType && unaryResultType.getTypeEnum().equals(TypeEnum.INT)) { + nonCalculationNode.setType(new BaseType(TypeEnum.BOOL)); return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL)); } else { errors.add(new TypeMismatchException("Both types must be Boolean")); @@ -474,6 +479,7 @@ public class SemanticAnalyzer implements SemanticVisitor { case EQUAL, NOT_EQUAL: if (expResult.getType() instanceof BaseType expResultType && unaryResult.getType() instanceof BaseType unaryResultType && Objects.equals(expResultType, unaryResultType)) { + nonCalculationNode.setType(new BaseType(TypeEnum.BOOL)); return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL)); } else { errors.add(new TypeMismatchException("Both types must be the same")); @@ -489,9 +495,13 @@ public class SemanticAnalyzer implements SemanticVisitor { if (unary.identifier != null) { if (currentScope.contains(unary.identifier)) { - return new TypeCheckResult(valid, currentScope.getLocalVar(unary.identifier)); + var type = currentScope.getLocalVar(unary.identifier); + unary.setType(type); + return new TypeCheckResult(valid, type); } else if (currentFields.get(unary.identifier) != null) { - return new TypeCheckResult(valid, currentFields.get(unary.identifier)); + var type = currentFields.get(unary.identifier); + unary.setType(type); + return new TypeCheckResult(valid, type); } else if (unary.statement != null) { var result = unary.statement.accept(this); unary.setType(result.getType()); @@ -501,15 +511,19 @@ public class SemanticAnalyzer implements SemanticVisitor { } } else if (unary.statement != null) { var result = unary.statement.accept(this); + unary.setType(result.getType()); return new TypeCheckResult(result.isValid(), result.getType()); } else if (unary.value != null) { var result = unary.value.accept(this); + unary.setType(result.getType()); return new TypeCheckResult(result.isValid(), result.getType()); } else if (unary.memberAccess != null) { var result = unary.memberAccess.accept(this); + unary.setType(result.getType()); return new TypeCheckResult(result.isValid(), result.getType()); } else if (unary.expression != null) { var result = unary.expression.accept(this); + unary.setType(result.getType()); return new TypeCheckResult(result.isValid(), result.getType()); } diff --git a/src/test/resources/input/typedAstExceptionsTests/DuplicatedConstructor.java b/src/test/resources/input/typedAstExceptionsTests/DuplicatedConstructor.java new file mode 100644 index 0000000..3d877a3 --- /dev/null +++ b/src/test/resources/input/typedAstExceptionsTests/DuplicatedConstructor.java @@ -0,0 +1,12 @@ +// @expected: AlreadyDeclaredException +public class AllFeaturesClassExample { + + public AllFeaturesClassExample(boolean b){ + + } + + public AllFeaturesClassExample(boolean b){ + + } + +} diff --git a/src/test/resources/input/typedAstFeaturesTests/ConstructorOverloading.java b/src/test/resources/input/typedAstFeaturesTests/ConstructorOverloading.java new file mode 100644 index 0000000..1e0bc49 --- /dev/null +++ b/src/test/resources/input/typedAstFeaturesTests/ConstructorOverloading.java @@ -0,0 +1,11 @@ +public class AllFeaturesClassExample { + + public AllFeaturesClassExample(boolean b){ + + } + + public AllFeaturesClassExample(boolean b, int a){ + + } + +} diff --git a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java index 828f6f3..5c3a97b 100644 --- a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java +++ b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java @@ -1,11 +1,64 @@ -public class AllFeaturesClassExample { - public void controlStructures(int a, boolean b) { +public class AllFeaturesClassExample { + int a; + boolean b; + char c; + + public void controlStructures(int adf, boolean bool) { + if (a > (10 + 8)) { + } else { + } + + + while (a > adf) { + a--; + } + + for (int i = 0; i < 5; i++) { + } + } - public AllFeaturesClassExample(boolean b){ - +// void logicalOperations() { +// // Logische UND-Operation +// if (b && a > 5) { +//// System.out.println("a ist größer als 5 und b ist wahr"); +// } +// +// // Logische ODER-Operation +// if (b || a < 5) { +//// System.out.println("b ist wahr oder a ist kleiner als 5"); +// } +// } + +// public static void main(String[] args) { +// AllFeaturesClassExample obj = new AllFeaturesClassExample(12, true, 'a'); +// obj.controlStructures(); +// } +} + +public class Test { + + public Car c; + + public int test(boolean b, int x) { + if (b == true) { + return c.getSpeed(); + } else { + return x; + } } } + +public class Car { + + private int speed; + + public int getSpeed() { + return speed; + } + +} + From 2537051668229b108fb02b8b490d8cd8f0cc86bb Mon Sep 17 00:00:00 2001 From: Bruder John Date: Tue, 2 Jul 2024 14:31:44 +0200 Subject: [PATCH 3/4] fix if field and parameter have same identifier --- src/main/java/semantic/SemanticAnalyzer.java | 6 +- .../java/semantic/context/FieldContext.java | 4 +- .../typedAstFeaturesTests/CorrectTest.java | 60 +------------------ 3 files changed, 11 insertions(+), 59 deletions(-) diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index 5906d16..c849067 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -535,6 +535,10 @@ public class SemanticAnalyzer implements SemanticVisitor { ITypeNode currentType = null; + if (memberAccessNode.thisExpr) { + currentType = new ReferenceType(currentClass.identifier); + } + for (String s : memberAccessNode.identifiers) { if (currentType == null) { if (currentScope.getLocalVar(s) != null) { @@ -552,7 +556,7 @@ public class SemanticAnalyzer implements SemanticVisitor { var currentTypeClass = context.getClass(reference.getIdentifier()); var currentField = currentTypeClass.getField(s); - if (currentField.getAccessModifier().accessType == EnumAccessModifierNode.PUBLIC) { + if (currentField.getAccessModifier().accessType == EnumAccessModifierNode.PUBLIC || memberAccessNode.thisExpr) { currentType = currentField.getType(); } else { errors.add(new NotVisibleException("This field is not visible")); diff --git a/src/main/java/semantic/context/FieldContext.java b/src/main/java/semantic/context/FieldContext.java index aba5ba0..3869bb1 100644 --- a/src/main/java/semantic/context/FieldContext.java +++ b/src/main/java/semantic/context/FieldContext.java @@ -4,13 +4,15 @@ import ast.members.FieldNode; import ast.type.*; import ast.type.type.*; +import java.util.Objects; + public class FieldContext { private AccessModifierNode accessModifier; private ITypeNode type; public FieldContext(FieldNode field) { - accessModifier = field.accessTypeNode; + accessModifier = Objects.requireNonNullElseGet(field.accessTypeNode, () -> new AccessModifierNode("private")); type = field.type; } diff --git a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java index 5c3a97b..c6d54fb 100644 --- a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java +++ b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java @@ -1,63 +1,9 @@ public class AllFeaturesClassExample { - int a; - boolean b; - char c; + int x; - public void controlStructures(int adf, boolean bool) { - if (a > (10 + 8)) { - } else { - } - - - while (a > adf) { - a--; - } - - for (int i = 0; i < 5; i++) { - } - - - } - -// void logicalOperations() { -// // Logische UND-Operation -// if (b && a > 5) { -//// System.out.println("a ist größer als 5 und b ist wahr"); -// } -// -// // Logische ODER-Operation -// if (b || a < 5) { -//// System.out.println("b ist wahr oder a ist kleiner als 5"); -// } -// } - -// public static void main(String[] args) { -// AllFeaturesClassExample obj = new AllFeaturesClassExample(12, true, 'a'); -// obj.controlStructures(); -// } -} - -public class Test { - - public Car c; - - public int test(boolean b, int x) { - if (b == true) { - return c.getSpeed(); - } else { - return x; - } - } - -} - -public class Car { - - private int speed; - - public int getSpeed() { - return speed; + public boolean test(boolean x){ + return x; } } From f7338a06b39782a46ae9c2280390a62b562a8c69 Mon Sep 17 00:00:00 2001 From: Bruder John Date: Tue, 2 Jul 2024 15:47:33 +0200 Subject: [PATCH 4/4] added MemberAccess to Assignable --- src/main/java/bytecode/MethodCodeGen.java | 2 +- src/main/java/semantic/SemanticAnalyzer.java | 3 +++ .../FieldOrParameterTypeMismatch.java | 10 ++++++++++ .../input/typedAstFeaturesTests/CorrectTest.java | 4 ++-- 4 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 src/test/resources/input/typedAstExceptionsTests/FieldOrParameterTypeMismatch.java diff --git a/src/main/java/bytecode/MethodCodeGen.java b/src/main/java/bytecode/MethodCodeGen.java index a1776c6..0999f48 100644 --- a/src/main/java/bytecode/MethodCodeGen.java +++ b/src/main/java/bytecode/MethodCodeGen.java @@ -50,7 +50,7 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor { @Override public void visit(ConstructorNode constructorNode) { methodVisitor = - classWriter.visitMethod(mapper.mapAccessTypeToOpcode(constructorNode.accessType), + classWriter.visitMethod(mapper.mapAccessTypeToOpcode(constructorNode.accesModifier), "", mapper.generateMethodDescriptor(new BaseType(TypeEnum.VOID), constructorNode.parameters), null, diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index c849067..110effd 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -246,6 +246,9 @@ public class SemanticAnalyzer implements SemanticVisitor { if (currentFields.get(toCheck.identifier) != null) { var type = currentFields.get(toCheck.identifier); toCheck.setTypeNode(type); + MemberAccessNode memberAccessNode = new MemberAccessNode(false); + memberAccessNode.identifiers.add(currentClass.identifier); + toCheck.memberAccess = memberAccessNode; return new TypeCheckResult(true, type); } else if (currentScope.getLocalVar(toCheck.identifier) != null) { var type = currentScope.getLocalVar(toCheck.identifier); diff --git a/src/test/resources/input/typedAstExceptionsTests/FieldOrParameterTypeMismatch.java b/src/test/resources/input/typedAstExceptionsTests/FieldOrParameterTypeMismatch.java new file mode 100644 index 0000000..0a9c17c --- /dev/null +++ b/src/test/resources/input/typedAstExceptionsTests/FieldOrParameterTypeMismatch.java @@ -0,0 +1,10 @@ +// @expected: TypeMismatchException +public class AllFeaturesClassExample { + int x; + + public boolean test(boolean x){ + return this.x; + } + +} + diff --git a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java index c6d54fb..4d27ecd 100644 --- a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java +++ b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java @@ -2,8 +2,8 @@ public class AllFeaturesClassExample { int x; - public boolean test(boolean x){ - return x; + public void test(){ + x = 1; } }