Improved checker code using declaration interfaces and overloaded error

reporting.
main
Deryck Brown 2 years ago
parent a6a078680c
commit 5cf07d1198
  1. 8
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstDeclaration.java
  2. 9
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstantDeclaration.java
  3. 12
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FuncDeclaration.java
  4. 12
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FunctionDeclaration.java
  5. 7
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcDeclaration.java
  6. 9
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcedureDeclaration.java
  7. 7
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VarDeclaration.java
  8. 9
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VariableDeclaration.java
  9. 11
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ConstFormalParameter.java
  10. 13
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FuncFormalParameter.java
  11. 8
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ProcFormalParameter.java
  12. 11
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/VarFormalParameter.java
  13. 394
      Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/Checker.java

@ -16,10 +16,11 @@ package triangle.abstractSyntaxTrees.declarations;
import triangle.abstractSyntaxTrees.expressions.Expression; import triangle.abstractSyntaxTrees.expressions.Expression;
import triangle.abstractSyntaxTrees.terminals.Identifier; import triangle.abstractSyntaxTrees.terminals.Identifier;
import triangle.abstractSyntaxTrees.types.TypeDenoter;
import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor;
import triangle.syntacticAnalyzer.SourcePosition; import triangle.syntacticAnalyzer.SourcePosition;
public class ConstDeclaration extends Declaration { public class ConstDeclaration extends Declaration implements ConstantDeclaration {
public ConstDeclaration(Identifier iAST, Expression eAST, SourcePosition position) { public ConstDeclaration(Identifier iAST, Expression eAST, SourcePosition position) {
super(position); super(position);
@ -27,6 +28,11 @@ public class ConstDeclaration extends Declaration {
E = eAST; E = eAST;
} }
@Override
public TypeDenoter getType() {
return E.type;
}
public <TArg, TResult> TResult visit(DeclarationVisitor<TArg, TResult> v, TArg arg) { public <TArg, TResult> TResult visit(DeclarationVisitor<TArg, TResult> v, TArg arg) {
return v.visitConstDeclaration(this, arg); return v.visitConstDeclaration(this, arg);
} }

@ -0,0 +1,9 @@
package triangle.abstractSyntaxTrees.declarations;
import triangle.abstractSyntaxTrees.types.TypeDenoter;
public interface ConstantDeclaration {
TypeDenoter getType();
}

@ -21,7 +21,7 @@ import triangle.abstractSyntaxTrees.types.TypeDenoter;
import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor;
import triangle.syntacticAnalyzer.SourcePosition; import triangle.syntacticAnalyzer.SourcePosition;
public class FuncDeclaration extends Declaration { public class FuncDeclaration extends Declaration implements FunctionDeclaration {
public FuncDeclaration(Identifier iAST, FormalParameterSequence fpsAST, TypeDenoter tAST, Expression eAST, public FuncDeclaration(Identifier iAST, FormalParameterSequence fpsAST, TypeDenoter tAST, Expression eAST,
SourcePosition position) { SourcePosition position) {
@ -36,6 +36,16 @@ public class FuncDeclaration extends Declaration {
return v.visitFuncDeclaration(this, arg); return v.visitFuncDeclaration(this, arg);
} }
@Override
public FormalParameterSequence getFormals() {
return FPS;
}
@Override
public TypeDenoter getType() {
return T;
}
public final Identifier I; public final Identifier I;
public final FormalParameterSequence FPS; public final FormalParameterSequence FPS;
public TypeDenoter T; public TypeDenoter T;

@ -0,0 +1,12 @@
package triangle.abstractSyntaxTrees.declarations;
import triangle.abstractSyntaxTrees.formals.FormalParameterSequence;
import triangle.abstractSyntaxTrees.types.TypeDenoter;
public interface FunctionDeclaration {
FormalParameterSequence getFormals();
TypeDenoter getType();
}

@ -20,7 +20,7 @@ import triangle.abstractSyntaxTrees.terminals.Identifier;
import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor;
import triangle.syntacticAnalyzer.SourcePosition; import triangle.syntacticAnalyzer.SourcePosition;
public class ProcDeclaration extends Declaration { public class ProcDeclaration extends Declaration implements ProcedureDeclaration {
public ProcDeclaration(Identifier iAST, FormalParameterSequence fpsAST, Command cAST, SourcePosition position) { public ProcDeclaration(Identifier iAST, FormalParameterSequence fpsAST, Command cAST, SourcePosition position) {
super(position); super(position);
@ -33,6 +33,11 @@ public class ProcDeclaration extends Declaration {
return v.visitProcDeclaration(this, arg); return v.visitProcDeclaration(this, arg);
} }
@Override
public FormalParameterSequence getFormals() {
return FPS;
}
public final Identifier I; public final Identifier I;
public final FormalParameterSequence FPS; public final FormalParameterSequence FPS;
public final Command C; public final Command C;

@ -0,0 +1,9 @@
package triangle.abstractSyntaxTrees.declarations;
import triangle.abstractSyntaxTrees.formals.FormalParameterSequence;
public interface ProcedureDeclaration {
FormalParameterSequence getFormals();
}

@ -19,7 +19,7 @@ import triangle.abstractSyntaxTrees.types.TypeDenoter;
import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor;
import triangle.syntacticAnalyzer.SourcePosition; import triangle.syntacticAnalyzer.SourcePosition;
public class VarDeclaration extends Declaration { public class VarDeclaration extends Declaration implements VariableDeclaration {
public VarDeclaration(Identifier iAST, TypeDenoter tAST, SourcePosition position) { public VarDeclaration(Identifier iAST, TypeDenoter tAST, SourcePosition position) {
super(position); super(position);
@ -27,6 +27,11 @@ public class VarDeclaration extends Declaration {
T = tAST; T = tAST;
} }
@Override
public TypeDenoter getType() {
return T;
}
public <TArg, TResult> TResult visit(DeclarationVisitor<TArg, TResult> v, TArg arg) { public <TArg, TResult> TResult visit(DeclarationVisitor<TArg, TResult> v, TArg arg) {
return v.visitVarDeclaration(this, arg); return v.visitVarDeclaration(this, arg);
} }

@ -0,0 +1,9 @@
package triangle.abstractSyntaxTrees.declarations;
import triangle.abstractSyntaxTrees.types.TypeDenoter;
public interface VariableDeclaration {
TypeDenoter getType();
}

@ -14,12 +14,13 @@
package triangle.abstractSyntaxTrees.formals; package triangle.abstractSyntaxTrees.formals;
import triangle.abstractSyntaxTrees.declarations.ConstantDeclaration;
import triangle.abstractSyntaxTrees.terminals.Identifier; import triangle.abstractSyntaxTrees.terminals.Identifier;
import triangle.abstractSyntaxTrees.types.TypeDenoter; import triangle.abstractSyntaxTrees.types.TypeDenoter;
import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor;
import triangle.syntacticAnalyzer.SourcePosition; import triangle.syntacticAnalyzer.SourcePosition;
public class ConstFormalParameter extends FormalParameter { public class ConstFormalParameter extends FormalParameter implements ConstantDeclaration {
public ConstFormalParameter(Identifier iAST, TypeDenoter tAST, SourcePosition position) { public ConstFormalParameter(Identifier iAST, TypeDenoter tAST, SourcePosition position) {
super(position); super(position);
@ -27,14 +28,18 @@ public class ConstFormalParameter extends FormalParameter {
T = tAST; T = tAST;
} }
@Override
public TypeDenoter getType() {
return T;
}
public <TArg, TResult> TResult visit(DeclarationVisitor<TArg, TResult> v, TArg arg) { public <TArg, TResult> TResult visit(DeclarationVisitor<TArg, TResult> v, TArg arg) {
return v.visitConstFormalParameter(this, arg); return v.visitConstFormalParameter(this, arg);
} }
@Override @Override
public boolean equals(Object fpAST) { public boolean equals(Object fpAST) {
if (fpAST instanceof ConstFormalParameter) { if (fpAST instanceof ConstFormalParameter cfpAST) {
var cfpAST = (ConstFormalParameter) fpAST;
return T.equals(cfpAST.T); return T.equals(cfpAST.T);
} else { } else {
return false; return false;

@ -14,12 +14,13 @@
package triangle.abstractSyntaxTrees.formals; package triangle.abstractSyntaxTrees.formals;
import triangle.abstractSyntaxTrees.declarations.FunctionDeclaration;
import triangle.abstractSyntaxTrees.terminals.Identifier; import triangle.abstractSyntaxTrees.terminals.Identifier;
import triangle.abstractSyntaxTrees.types.TypeDenoter; import triangle.abstractSyntaxTrees.types.TypeDenoter;
import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor;
import triangle.syntacticAnalyzer.SourcePosition; import triangle.syntacticAnalyzer.SourcePosition;
public class FuncFormalParameter extends FormalParameter { public class FuncFormalParameter extends FormalParameter implements FunctionDeclaration {
public FuncFormalParameter(Identifier iAST, FormalParameterSequence fpsAST, TypeDenoter tAST, public FuncFormalParameter(Identifier iAST, FormalParameterSequence fpsAST, TypeDenoter tAST,
SourcePosition position) { SourcePosition position) {
@ -33,6 +34,16 @@ public class FuncFormalParameter extends FormalParameter {
return v.visitFuncFormalParameter(this, arg); return v.visitFuncFormalParameter(this, arg);
} }
@Override
public FormalParameterSequence getFormals() {
return FPS;
}
@Override
public TypeDenoter getType() {
return T;
}
@Override @Override
public boolean equals(Object fpAST) { public boolean equals(Object fpAST) {
if (fpAST instanceof FuncFormalParameter) { if (fpAST instanceof FuncFormalParameter) {

@ -14,11 +14,12 @@
package triangle.abstractSyntaxTrees.formals; package triangle.abstractSyntaxTrees.formals;
import triangle.abstractSyntaxTrees.declarations.ProcedureDeclaration;
import triangle.abstractSyntaxTrees.terminals.Identifier; import triangle.abstractSyntaxTrees.terminals.Identifier;
import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor;
import triangle.syntacticAnalyzer.SourcePosition; import triangle.syntacticAnalyzer.SourcePosition;
public class ProcFormalParameter extends FormalParameter { public class ProcFormalParameter extends FormalParameter implements ProcedureDeclaration {
public ProcFormalParameter(Identifier iAST, FormalParameterSequence fpsAST, SourcePosition position) { public ProcFormalParameter(Identifier iAST, FormalParameterSequence fpsAST, SourcePosition position) {
super(position); super(position);
@ -30,6 +31,11 @@ public class ProcFormalParameter extends FormalParameter {
return v.visitProcFormalParameter(this, arg); return v.visitProcFormalParameter(this, arg);
} }
@Override
public FormalParameterSequence getFormals() {
return FPS;
}
@Override @Override
public boolean equals(Object fpAST) { public boolean equals(Object fpAST) {
if (fpAST instanceof ProcFormalParameter) { if (fpAST instanceof ProcFormalParameter) {

@ -14,12 +14,13 @@
package triangle.abstractSyntaxTrees.formals; package triangle.abstractSyntaxTrees.formals;
import triangle.abstractSyntaxTrees.declarations.VariableDeclaration;
import triangle.abstractSyntaxTrees.terminals.Identifier; import triangle.abstractSyntaxTrees.terminals.Identifier;
import triangle.abstractSyntaxTrees.types.TypeDenoter; import triangle.abstractSyntaxTrees.types.TypeDenoter;
import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor;
import triangle.syntacticAnalyzer.SourcePosition; import triangle.syntacticAnalyzer.SourcePosition;
public class VarFormalParameter extends FormalParameter { public class VarFormalParameter extends FormalParameter implements VariableDeclaration {
public VarFormalParameter(Identifier iAST, TypeDenoter tAST, SourcePosition position) { public VarFormalParameter(Identifier iAST, TypeDenoter tAST, SourcePosition position) {
super(position); super(position);
@ -27,14 +28,18 @@ public class VarFormalParameter extends FormalParameter {
T = tAST; T = tAST;
} }
@Override
public TypeDenoter getType() {
return T;
}
public <TArg, TResult> TResult visit(DeclarationVisitor<TArg, TResult> v, TArg arg) { public <TArg, TResult> TResult visit(DeclarationVisitor<TArg, TResult> v, TArg arg) {
return v.visitVarFormalParameter(this, arg); return v.visitVarFormalParameter(this, arg);
} }
@Override @Override
public boolean equals(Object fpAST) { public boolean equals(Object fpAST) {
if (fpAST instanceof VarFormalParameter) { if (fpAST instanceof VarFormalParameter vfpAST) {
VarFormalParameter vfpAST = (VarFormalParameter) fpAST;
return T.equals(vfpAST.T); return T.equals(vfpAST.T);
} else { } else {
return false; return false;

@ -16,6 +16,7 @@ package triangle.contextualAnalyzer;
import triangle.ErrorReporter; import triangle.ErrorReporter;
import triangle.StdEnvironment; import triangle.StdEnvironment;
import triangle.abstractSyntaxTrees.AbstractSyntaxTree;
import triangle.abstractSyntaxTrees.Program; import triangle.abstractSyntaxTrees.Program;
import triangle.abstractSyntaxTrees.actuals.ConstActualParameter; import triangle.abstractSyntaxTrees.actuals.ConstActualParameter;
import triangle.abstractSyntaxTrees.actuals.EmptyActualParameterSequence; import triangle.abstractSyntaxTrees.actuals.EmptyActualParameterSequence;
@ -37,12 +38,16 @@ import triangle.abstractSyntaxTrees.commands.SequentialCommand;
import triangle.abstractSyntaxTrees.commands.WhileCommand; import triangle.abstractSyntaxTrees.commands.WhileCommand;
import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration; import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration;
import triangle.abstractSyntaxTrees.declarations.ConstDeclaration; import triangle.abstractSyntaxTrees.declarations.ConstDeclaration;
import triangle.abstractSyntaxTrees.declarations.ConstantDeclaration;
import triangle.abstractSyntaxTrees.declarations.Declaration; import triangle.abstractSyntaxTrees.declarations.Declaration;
import triangle.abstractSyntaxTrees.declarations.FuncDeclaration; import triangle.abstractSyntaxTrees.declarations.FuncDeclaration;
import triangle.abstractSyntaxTrees.declarations.FunctionDeclaration;
import triangle.abstractSyntaxTrees.declarations.ProcDeclaration; import triangle.abstractSyntaxTrees.declarations.ProcDeclaration;
import triangle.abstractSyntaxTrees.declarations.ProcedureDeclaration;
import triangle.abstractSyntaxTrees.declarations.SequentialDeclaration; import triangle.abstractSyntaxTrees.declarations.SequentialDeclaration;
import triangle.abstractSyntaxTrees.declarations.UnaryOperatorDeclaration; import triangle.abstractSyntaxTrees.declarations.UnaryOperatorDeclaration;
import triangle.abstractSyntaxTrees.declarations.VarDeclaration; import triangle.abstractSyntaxTrees.declarations.VarDeclaration;
import triangle.abstractSyntaxTrees.declarations.VariableDeclaration;
import triangle.abstractSyntaxTrees.expressions.ArrayExpression; import triangle.abstractSyntaxTrees.expressions.ArrayExpression;
import triangle.abstractSyntaxTrees.expressions.BinaryExpression; import triangle.abstractSyntaxTrees.expressions.BinaryExpression;
import triangle.abstractSyntaxTrees.expressions.CallExpression; import triangle.abstractSyntaxTrees.expressions.CallExpression;
@ -117,29 +122,20 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
var vType = ast.V.visit(this); var vType = ast.V.visit(this);
var eType = ast.E.visit(this); var eType = ast.E.visit(this);
if (!ast.V.variable) { checkAndReportError(ast.V.variable, "LHS of assignment is not a variable", ast.V);
reporter.reportError("LHS of assignment is not a variable", "", ast.V.getPosition()); checkAndReportError(eType.equals(vType), "assignment incompatibilty", ast);
}
if (!eType.equals(vType)) {
reporter.reportError("assignment incompatibilty", "", ast.getPosition());
}
return null; return null;
} }
@Override @Override
public Void visitCallCommand(CallCommand ast, Void arg) { public Void visitCallCommand(CallCommand ast, Void arg) {
var binding = ast.I.visit(this); var binding = ast.I.visit(this);
if (binding == null) {
reportUndeclared(ast.I); if (binding instanceof ProcedureDeclaration procedure) {
} else if (binding instanceof ProcDeclaration) { ast.APS.visit(this, procedure.getFormals());
ast.APS.visit(this, ((ProcDeclaration) binding).FPS);
} else if (binding instanceof ProcFormalParameter) {
ast.APS.visit(this, ((ProcFormalParameter) binding).FPS);
} else { } else {
reporter.reportError("\"%\" is not a procedure identifier", ast.I.spelling, ast.I.getPosition()); reportUndeclaredOrError(binding, ast.I, "\"%\" is not a procedure identifier");
} }
return null; return null;
@ -153,9 +149,8 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public Void visitIfCommand(IfCommand ast, Void arg) { public Void visitIfCommand(IfCommand ast, Void arg) {
var eType = ast.E.visit(this); var eType = ast.E.visit(this);
if (!eType.equals(StdEnvironment.booleanType)) {
reporter.reportError("Boolean expression expected here", "", ast.E.getPosition()); checkAndReportError(eType.equals(StdEnvironment.booleanType), "Boolean expression expected here", ast.E);
}
ast.C1.visit(this); ast.C1.visit(this);
ast.C2.visit(this); ast.C2.visit(this);
@ -182,10 +177,10 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public Void visitWhileCommand(WhileCommand ast, Void arg) { public Void visitWhileCommand(WhileCommand ast, Void arg) {
var eType = ast.E.visit(this); var eType = ast.E.visit(this);
if (!eType.equals(StdEnvironment.booleanType)) {
reporter.reportError("Boolean expression expected here", "", ast.E.getPosition()); checkAndReportError(eType.equals(StdEnvironment.booleanType), "Boolean expression expected here", ast.E);
}
ast.C.visit(this); ast.C.visit(this);
return null; return null;
} }
@ -204,84 +199,62 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public TypeDenoter visitBinaryExpression(BinaryExpression ast, Void arg) { public TypeDenoter visitBinaryExpression(BinaryExpression ast, Void arg) {
var e1Type = ast.E1.visit(this); var e1Type = ast.E1.visit(this);
var e2Type = ast.E2.visit(this); var e2Type = ast.E2.visit(this);
var binding = ast.O.visit(this); var binding = ast.O.visit(this);
if (binding == null) { if (binding instanceof BinaryOperatorDeclaration bbinding) {
reportUndeclared(ast.O); if (bbinding.ARG1.equals(StdEnvironment.anyType)) {
} else {
if (!(binding instanceof BinaryOperatorDeclaration))
reporter.reportError("\"%\" is not a binary operator", ast.O.spelling, ast.O.getPosition());
var bbinding = (BinaryOperatorDeclaration) binding;
if (bbinding.ARG1 == StdEnvironment.anyType) {
// this operator must be "=" or "\=" // this operator must be "=" or "\="
if (!e1Type.equals(e2Type)) { checkAndReportError(e1Type.equals(e2Type), "incompatible argument types for \"%\"", ast.O, ast);
reporter.reportError("incompatible argument types for \"%\"", ast.O.spelling, ast.getPosition()); } else {
} checkAndReportError(e1Type.equals(bbinding.ARG1), "wrong argument type for \"%\"", ast.O, ast.E1);
} else if (!e1Type.equals(bbinding.ARG1)) { checkAndReportError(e2Type.equals(bbinding.ARG2), "wrong argument type for \"%\"", ast.O, ast.E2);
reporter.reportError("wrong argument type for \"%\"", ast.O.spelling, ast.E1.getPosition());
} else if (!e2Type.equals(bbinding.ARG2)) {
reporter.reportError("wrong argument type for \"%\"", ast.O.spelling, ast.E2.getPosition());
} }
return ast.type = bbinding.RES;
ast.type = bbinding.RES;
} }
return ast.type; reportUndeclaredOrError(binding, ast.O, "\"%\" is not a binary operator");
return ast.type = StdEnvironment.errorType;
} }
@Override @Override
public TypeDenoter visitCallExpression(CallExpression ast, Void arg) { public TypeDenoter visitCallExpression(CallExpression ast, Void arg) {
var binding = ast.I.visit(this); var binding = ast.I.visit(this);
if (binding == null) {
reportUndeclared(ast.I); if (binding instanceof FunctionDeclaration function) {
ast.type = StdEnvironment.errorType; ast.APS.visit(this, function.getFormals());
} else if (binding instanceof FuncDeclaration) { return ast.type = function.getType();
ast.APS.visit(this, ((FuncDeclaration) binding).FPS);
ast.type = ((FuncDeclaration) binding).T;
} else if (binding instanceof FuncFormalParameter) {
ast.APS.visit(this, ((FuncFormalParameter) binding).FPS);
ast.type = ((FuncFormalParameter) binding).T;
} else {
reporter.reportError("\"%\" is not a function identifier", ast.I.spelling, ast.I.getPosition());
} }
return ast.type; reportUndeclaredOrError(binding, ast.I, "\"%\" is not a function identifier");
return ast.type = StdEnvironment.errorType;
} }
@Override @Override
public TypeDenoter visitCharacterExpression(CharacterExpression ast, Void arg) { public TypeDenoter visitCharacterExpression(CharacterExpression ast, Void arg) {
ast.type = StdEnvironment.charType; return ast.type = StdEnvironment.charType;
return ast.type;
} }
@Override @Override
public TypeDenoter visitEmptyExpression(EmptyExpression ast, Void arg) { public TypeDenoter visitEmptyExpression(EmptyExpression ast, Void arg) {
ast.type = null; return ast.type = null;
return ast.type;
} }
@Override @Override
public TypeDenoter visitIfExpression(IfExpression ast, Void arg) { public TypeDenoter visitIfExpression(IfExpression ast, Void arg) {
var e1Type = ast.E1.visit(this); var e1Type = ast.E1.visit(this);
if (!e1Type.equals(StdEnvironment.booleanType)) { checkAndReportError(e1Type.equals(StdEnvironment.booleanType), "Boolean expression expected here", ast.E1);
reporter.reportError("Boolean expression expected here", "", ast.E1.getPosition());
}
var e2Type = ast.E2.visit(this); var e2Type = ast.E2.visit(this);
var e3Type = ast.E3.visit(this); var e3Type = ast.E3.visit(this);
if (!e2Type.equals(e3Type)) { checkAndReportError(e2Type.equals(e3Type), "incompatible limbs in if-expression", ast);
reporter.reportError("incompatible limbs in if-expression", "", ast.getPosition()); return ast.type = e2Type;
}
ast.type = e2Type;
return ast.type;
} }
@Override @Override
public TypeDenoter visitIntegerExpression(IntegerExpression ast, Void arg) { public TypeDenoter visitIntegerExpression(IntegerExpression ast, Void arg) {
ast.type = StdEnvironment.integerType; return ast.type = StdEnvironment.integerType;
return ast.type;
} }
@Override @Override
@ -296,34 +269,26 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public TypeDenoter visitRecordExpression(RecordExpression ast, Void arg) { public TypeDenoter visitRecordExpression(RecordExpression ast, Void arg) {
var rType = ast.RA.visit(this); var rType = ast.RA.visit(this);
ast.type = new RecordTypeDenoter(rType, ast.getPosition()); return ast.type = new RecordTypeDenoter(rType, ast.getPosition());
return ast.type;
} }
@Override @Override
public TypeDenoter visitUnaryExpression(UnaryExpression ast, Void arg) { public TypeDenoter visitUnaryExpression(UnaryExpression ast, Void arg) {
var eType = ast.E.visit(this); var eType = ast.E.visit(this);
var binding = ast.O.visit(this); var binding = ast.O.visit(this);
if (binding == null) {
reportUndeclared(ast.O); if (binding instanceof UnaryOperatorDeclaration ubinding) {
ast.type = StdEnvironment.errorType; checkAndReportError(eType.equals(ubinding.ARG), "wrong argument type for \"%\"", ast.O);
} else if (!(binding instanceof UnaryOperatorDeclaration)) { return ast.type = ubinding.RES;
reporter.reportError("\"%\" is not a unary operator", ast.O.spelling, ast.O.getPosition());
} else {
var ubinding = (UnaryOperatorDeclaration) binding;
if (!eType.equals(ubinding.ARG)) {
reporter.reportError("wrong argument type for \"%\"", ast.O.spelling, ast.O.getPosition());
}
ast.type = ubinding.RES;
} }
return ast.type;
reportUndeclaredOrError(binding, ast.O, "\"%\" is not a unary operator");
return ast.type = StdEnvironment.errorType;
} }
@Override @Override
public TypeDenoter visitVnameExpression(VnameExpression ast, Void arg) { public TypeDenoter visitVnameExpression(VnameExpression ast, Void arg) {
ast.type = ast.V.visit(this); return ast.type = ast.V.visit(this);
return ast.type;
} }
// Declarations // Declarations
@ -338,39 +303,37 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
public Void visitConstDeclaration(ConstDeclaration ast, Void arg) { public Void visitConstDeclaration(ConstDeclaration ast, Void arg) {
ast.E.visit(this); ast.E.visit(this);
idTable.enter(ast.I.spelling, ast); idTable.enter(ast.I.spelling, ast);
if (ast.duplicated) { checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast);
reporter.reportError("identifier \"%\" already declared", ast.I.spelling, ast.getPosition());
}
return null; return null;
} }
@Override @Override
public Void visitFuncDeclaration(FuncDeclaration ast, Void arg) { public Void visitFuncDeclaration(FuncDeclaration ast, Void arg) {
ast.T = ast.T.visit(this); ast.T = ast.T.visit(this);
idTable.enter(ast.I.spelling, ast); // permits recursion // permits recursion
if (ast.duplicated) { idTable.enter(ast.I.spelling, ast);
reporter.reportError("identifier \"%\" already declared", ast.I.spelling, ast.getPosition()); checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast);
}
idTable.openScope(); idTable.openScope();
ast.FPS.visit(this); ast.FPS.visit(this);
var eType = ast.E.visit(this); var eType = ast.E.visit(this);
idTable.closeScope(); idTable.closeScope();
if (!ast.T.equals(eType)) {
reporter.reportError("body of function \"%\" has wrong type", ast.I.spelling, ast.E.getPosition()); checkAndReportError(ast.T.equals(eType), "body of function \"%\" has wrong type", ast.I, ast.E);
}
return null; return null;
} }
@Override @Override
public Void visitProcDeclaration(ProcDeclaration ast, Void arg) { public Void visitProcDeclaration(ProcDeclaration ast, Void arg) {
idTable.enter(ast.I.spelling, ast); // permits recursion // permits recursion
if (ast.duplicated) { idTable.enter(ast.I.spelling, ast);
reporter.reportError("identifier \"%\" already declared", ast.I.spelling, ast.getPosition()); checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast);
}
idTable.openScope(); idTable.openScope();
ast.FPS.visit(this); ast.FPS.visit(this);
ast.C.visit(this); ast.C.visit(this);
idTable.closeScope(); idTable.closeScope();
return null; return null;
} }
@ -385,9 +348,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
public Void visitTypeDeclaration(TypeDeclaration ast, Void arg) { public Void visitTypeDeclaration(TypeDeclaration ast, Void arg) {
ast.T = ast.T.visit(this); ast.T = ast.T.visit(this);
idTable.enter(ast.I.spelling, ast); idTable.enter(ast.I.spelling, ast);
if (ast.duplicated) { checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast);
reporter.reportError("identifier \"%\" already declared", ast.I.spelling, ast.getPosition());
}
return null; return null;
} }
@ -400,10 +361,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
public Void visitVarDeclaration(VarDeclaration ast, Void arg) { public Void visitVarDeclaration(VarDeclaration ast, Void arg) {
ast.T = ast.T.visit(this); ast.T = ast.T.visit(this);
idTable.enter(ast.I.spelling, ast); idTable.enter(ast.I.spelling, ast);
if (ast.duplicated) { checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast);
reporter.reportError("identifier \"%\" already declared", ast.I.spelling, ast.getPosition());
}
return null; return null;
} }
@ -417,9 +375,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
var eType = ast.E.visit(this); var eType = ast.E.visit(this);
var elemType = ast.AA.visit(this); var elemType = ast.AA.visit(this);
ast.elemCount = ast.AA.elemCount + 1; ast.elemCount = ast.AA.elemCount + 1;
if (!eType.equals(elemType)) { checkAndReportError(eType.equals(elemType), "incompatible array-aggregate element", ast.E);
reporter.reportError("incompatible array-aggregate element", "", ast.E.getPosition());
}
return elemType; return elemType;
} }
@ -440,18 +396,14 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
var eType = ast.E.visit(this); var eType = ast.E.visit(this);
var rType = ast.RA.visit(this); var rType = ast.RA.visit(this);
var fType = checkFieldIdentifier(rType, ast.I); var fType = checkFieldIdentifier(rType, ast.I);
if (fType != StdEnvironment.errorType) { checkAndReportError(fType.equals(StdEnvironment.errorType), "duplicate field \"%\" in record", ast.I);
reporter.reportError("duplicate field \"%\" in record", ast.I.spelling, ast.I.getPosition()); return ast.type = new MultipleFieldTypeDenoter(ast.I, eType, rType, ast.getPosition());
}
ast.type = new MultipleFieldTypeDenoter(ast.I, eType, rType, ast.getPosition());
return ast.type;
} }
@Override @Override
public FieldTypeDenoter visitSingleRecordAggregate(SingleRecordAggregate ast, Void arg) { public FieldTypeDenoter visitSingleRecordAggregate(SingleRecordAggregate ast, Void arg) {
var eType = ast.E.visit(this); var eType = ast.E.visit(this);
ast.type = new SingleFieldTypeDenoter(ast.I, eType, ast.getPosition()); return ast.type = new SingleFieldTypeDenoter(ast.I, eType, ast.getPosition());
return ast.type;
} }
// Formal Parameters // Formal Parameters
@ -462,9 +414,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
public Void visitConstFormalParameter(ConstFormalParameter ast, Void arg) { public Void visitConstFormalParameter(ConstFormalParameter ast, Void arg) {
ast.T = ast.T.visit(this); ast.T = ast.T.visit(this);
idTable.enter(ast.I.spelling, ast); idTable.enter(ast.I.spelling, ast);
if (ast.duplicated) { checkAndReportError(!ast.duplicated, "duplicated formal parameter \"%\"", ast.I, ast);
reporter.reportError("duplicated formal parameter \"%\"", ast.I.spelling, ast.getPosition());
}
return null; return null;
} }
@ -475,9 +425,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
idTable.closeScope(); idTable.closeScope();
ast.T = ast.T.visit(this); ast.T = ast.T.visit(this);
idTable.enter(ast.I.spelling, ast); idTable.enter(ast.I.spelling, ast);
if (ast.duplicated) { checkAndReportError(!ast.duplicated, "duplicated formal parameter \"%\"", ast.I, ast);
reporter.reportError("duplicated formal parameter \"%\"", ast.I.spelling, ast.getPosition());
}
return null; return null;
} }
@ -487,9 +435,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
ast.FPS.visit(this); ast.FPS.visit(this);
idTable.closeScope(); idTable.closeScope();
idTable.enter(ast.I.spelling, ast); idTable.enter(ast.I.spelling, ast);
if (ast.duplicated) { checkAndReportError(!ast.duplicated, "duplicated formal parameter \"%\"", ast.I, ast);
reporter.reportError("duplicated formal parameter \"%\"", ast.I.spelling, ast.getPosition());
}
return null; return null;
} }
@ -497,9 +443,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
public Void visitVarFormalParameter(VarFormalParameter ast, Void arg) { public Void visitVarFormalParameter(VarFormalParameter ast, Void arg) {
ast.T = ast.T.visit(this); ast.T = ast.T.visit(this);
idTable.enter(ast.I.spelling, ast); idTable.enter(ast.I.spelling, ast);
if (ast.duplicated) { checkAndReportError(!ast.duplicated, "duplicated formal parameter \"%\"", ast.I, ast);
reporter.reportError("duplicated formal parameter \"%\"", ast.I.spelling, ast.getPosition());
}
return null; return null;
} }
@ -528,10 +472,10 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public Void visitConstActualParameter(ConstActualParameter ast, FormalParameter arg) { public Void visitConstActualParameter(ConstActualParameter ast, FormalParameter arg) {
var eType = ast.E.visit(this); var eType = ast.E.visit(this);
if (!(arg instanceof ConstFormalParameter)) { if (arg instanceof ConstFormalParameter param) {
reporter.reportError("const actual parameter not expected here", "", ast.getPosition()); checkAndReportError(eType.equals(param.T), "wrong type for const actual parameter", ast.E);
} else if (!eType.equals(((ConstFormalParameter) arg).T)) { } else {
reporter.reportError("wrong type for const actual parameter", "", ast.E.getPosition()); reportError("const actual parameter not expected here", ast);
} }
return null; return null;
} }
@ -539,27 +483,20 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public Void visitFuncActualParameter(FuncActualParameter ast, FormalParameter arg) { public Void visitFuncActualParameter(FuncActualParameter ast, FormalParameter arg) {
var binding = ast.I.visit(this); var binding = ast.I.visit(this);
if (binding == null) { if (binding instanceof FunctionDeclaration function) {
reportUndeclared(ast.I); var formals = function.getFormals();
} else if (!(binding instanceof FuncDeclaration || binding instanceof FuncFormalParameter)) { var functionType = function.getType();
reporter.reportError("\"%\" is not a function identifier", ast.I.spelling, ast.I.getPosition()); if (arg instanceof FuncFormalParameter param) {
} else if (!(arg instanceof FuncFormalParameter)) { if (!formals.equals(param.getFormals())) {
reporter.reportError("func actual parameter not expected here", "", ast.getPosition()); reportError("wrong signature for function \"%\"", ast.I);
} else { } else if (!functionType.equals(param.T)) {
FormalParameterSequence FPS = null; reportError("wrong type for function \"%\"", ast.I);
TypeDenoter T = null; }
if (binding instanceof FuncDeclaration) {
FPS = ((FuncDeclaration) binding).FPS;
T = ((FuncDeclaration) binding).T;
} else { } else {
FPS = ((FuncFormalParameter) binding).FPS; reportError("func actual parameter not expected here", ast);
T = ((FuncFormalParameter) binding).T;
}
if (!FPS.equals(((FuncFormalParameter) arg).FPS)) {
reporter.reportError("wrong signature for function \"%\"", ast.I.spelling, ast.I.getPosition());
} else if (!T.equals(((FuncFormalParameter) arg).T)) {
reporter.reportError("wrong type for function \"%\"", ast.I.spelling, ast.I.getPosition());
} }
} else {
reportUndeclaredOrError(binding, ast.I, "\"%\" is not a function identifier");
} }
return null; return null;
} }
@ -567,22 +504,15 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public Void visitProcActualParameter(ProcActualParameter ast, FormalParameter arg) { public Void visitProcActualParameter(ProcActualParameter ast, FormalParameter arg) {
var binding = ast.I.visit(this); var binding = ast.I.visit(this);
if (binding == null) { if (binding instanceof ProcedureDeclaration procedure) {
reportUndeclared(ast.I); var formals = procedure.getFormals();
} else if (!(binding instanceof ProcDeclaration || binding instanceof ProcFormalParameter)) { if (arg instanceof ProcFormalParameter param) {
reporter.reportError("\"%\" is not a procedure identifier", ast.I.spelling, ast.I.getPosition()); checkAndReportError(formals.equals(param.getFormals()), "wrong signature for procedure \"%\"", ast.I);
} else if (!(arg instanceof ProcFormalParameter)) {
reporter.reportError("proc actual parameter not expected here", "", ast.getPosition());
} else {
FormalParameterSequence FPS = null;
if (binding instanceof ProcDeclaration) {
FPS = ((ProcDeclaration) binding).FPS;
} else { } else {
FPS = ((ProcFormalParameter) binding).FPS; reportError("proc actual parameter not expected here", ast);
}
if (!FPS.equals(((ProcFormalParameter) arg).FPS)) {
reporter.reportError("wrong signature for procedure \"%\"", ast.I.spelling, ast.I.getPosition());
} }
} else {
reportUndeclaredOrError(binding, ast.I, "\"%\" is not a procedure identifier");
} }
return null; return null;
} }
@ -591,40 +521,38 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
public Void visitVarActualParameter(VarActualParameter ast, FormalParameter arg) { public Void visitVarActualParameter(VarActualParameter ast, FormalParameter arg) {
var vType = ast.V.visit(this); var vType = ast.V.visit(this);
if (!ast.V.variable) { if (!ast.V.variable) {
reporter.reportError("actual parameter is not a variable", "", ast.V.getPosition()); reportError("actual parameter is not a variable", ast.V);
} else if (!(arg instanceof VarFormalParameter)) { } else if (arg instanceof VarFormalParameter parameter) {
reporter.reportError("var actual parameter not expected here", "", ast.V.getPosition()); checkAndReportError(vType.equals(parameter.T), "wrong type for var actual parameter", ast.V);
} else if (!vType.equals(((VarFormalParameter) arg).T)) { } else {
reporter.reportError("wrong type for var actual parameter", "", ast.V.getPosition()); reportError("var actual parameter not expected here", ast.V);
} }
return null; return null;
} }
@Override @Override
public Void visitEmptyActualParameterSequence(EmptyActualParameterSequence ast, FormalParameterSequence arg) { public Void visitEmptyActualParameterSequence(EmptyActualParameterSequence ast, FormalParameterSequence arg) {
if (!(arg instanceof EmptyFormalParameterSequence)) { checkAndReportError(arg instanceof EmptyFormalParameterSequence, "too few actual parameters", ast);
reporter.reportError("too few actual parameters", "", ast.getPosition());
}
return null; return null;
} }
@Override @Override
public Void visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, FormalParameterSequence arg) { public Void visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, FormalParameterSequence arg) {
if (!(arg instanceof MultipleFormalParameterSequence)) { if (arg instanceof MultipleFormalParameterSequence formals) {
reporter.reportError("too many actual parameters", "", ast.getPosition()); ast.AP.visit(this, formals.FP);
ast.APS.visit(this, formals.FPS);
} else { } else {
ast.AP.visit(this, ((MultipleFormalParameterSequence) arg).FP); reportError("too many actual parameters", ast);
ast.APS.visit(this, ((MultipleFormalParameterSequence) arg).FPS);
} }
return null; return null;
} }
@Override @Override
public Void visitSingleActualParameterSequence(SingleActualParameterSequence ast, FormalParameterSequence arg) { public Void visitSingleActualParameterSequence(SingleActualParameterSequence ast, FormalParameterSequence arg) {
if (!(arg instanceof SingleFormalParameterSequence)) { if (arg instanceof SingleFormalParameterSequence formal) {
reporter.reportError("incorrect number of actual parameters", "", ast.getPosition()); ast.AP.visit(this, formal.FP);
} else { } else {
ast.AP.visit(this, ((SingleFormalParameterSequence) arg).FP); reportError("incorrect number of actual parameters", ast);
} }
return null; return null;
} }
@ -642,9 +570,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public TypeDenoter visitArrayTypeDenoter(ArrayTypeDenoter ast, Void arg) { public TypeDenoter visitArrayTypeDenoter(ArrayTypeDenoter ast, Void arg) {
ast.T = ast.T.visit(this); ast.T = ast.T.visit(this);
if ((Integer.valueOf(ast.IL.spelling)) == 0) { checkAndReportError(ast.IL.getValue() != 0, "arrays must not be empty", ast.IL);
reporter.reportError("arrays must not be empty", "", ast.IL.getPosition());
}
return ast; return ast;
} }
@ -666,14 +592,12 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public TypeDenoter visitSimpleTypeDenoter(SimpleTypeDenoter ast, Void arg) { public TypeDenoter visitSimpleTypeDenoter(SimpleTypeDenoter ast, Void arg) {
var binding = ast.I.visit(this); var binding = ast.I.visit(this);
if (binding == null) { if (binding instanceof TypeDeclaration decl) {
reportUndeclared(ast.I); return decl.T;
return StdEnvironment.errorType;
} else if (!(binding instanceof TypeDeclaration)) {
reporter.reportError("\"%\" is not a type identifier", ast.I.spelling, ast.I.getPosition());
return StdEnvironment.errorType;
} }
return ((TypeDeclaration) binding).T;
reportUndeclaredOrError(binding, ast.I, "\"%\" is not a type identifier");
return StdEnvironment.errorType;
} }
@Override @Override
@ -754,14 +678,12 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
public TypeDenoter visitDotVname(DotVname ast, Void arg) { public TypeDenoter visitDotVname(DotVname ast, Void arg) {
ast.type = null; ast.type = null;
var vType = ast.V.visit(this); var vType = ast.V.visit(this);
ast.variable = ast.V.variable; if (vType instanceof RecordTypeDenoter record) {
if (!(vType instanceof RecordTypeDenoter)) { ast.type = checkFieldIdentifier(record.FT, ast.I);
reporter.reportError("record expected here", "", ast.V.getPosition()); checkAndReportError(!ast.type.equals(StdEnvironment.errorType), "no field \"%\" in this record type",
ast.I);
} else { } else {
ast.type = checkFieldIdentifier(((RecordTypeDenoter) vType).FT, ast.I); reportError("record expected here", ast.V);
if (ast.type == StdEnvironment.errorType) {
reporter.reportError("no field \"%\" in this record type", ast.I.spelling, ast.I.getPosition());
}
} }
return ast.type; return ast.type;
} }
@ -770,42 +692,34 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
public TypeDenoter visitSimpleVname(SimpleVname ast, Void arg) { public TypeDenoter visitSimpleVname(SimpleVname ast, Void arg) {
ast.variable = false; ast.variable = false;
ast.type = StdEnvironment.errorType; ast.type = StdEnvironment.errorType;
var binding = ast.I.visit(this); var binding = ast.I.visit(this);
if (binding == null) { if (binding instanceof ConstantDeclaration constant) {
reportUndeclared(ast.I); return ast.type = constant.getType();
} else if (binding instanceof ConstDeclaration) { } else if (binding instanceof VariableDeclaration variable) {
ast.type = ((ConstDeclaration) binding).E.type; return ast.type = variable.getType();
ast.variable = false;
} else if (binding instanceof VarDeclaration) {
ast.type = ((VarDeclaration) binding).T;
ast.variable = true;
} else if (binding instanceof ConstFormalParameter) {
ast.type = ((ConstFormalParameter) binding).T;
ast.variable = false;
} else if (binding instanceof VarFormalParameter) {
ast.type = ((VarFormalParameter) binding).T;
ast.variable = true;
} else {
reporter.reportError("\"%\" is not a const or var identifier", ast.I.spelling, ast.I.getPosition());
} }
return ast.type;
reportUndeclaredOrError(binding, ast.I, "\"%\" is not a const or var identifier");
return ast.type = StdEnvironment.errorType;
} }
@Override @Override
public TypeDenoter visitSubscriptVname(SubscriptVname ast, Void arg) { public TypeDenoter visitSubscriptVname(SubscriptVname ast, Void arg) {
var vType = ast.V.visit(this); var vType = ast.V.visit(this);
ast.variable = ast.V.variable; ast.variable = ast.V.variable;
var eType = ast.E.visit(this); var eType = ast.E.visit(this);
if (vType != StdEnvironment.errorType) { if (vType != StdEnvironment.errorType) {
if (!(vType instanceof ArrayTypeDenoter)) { if (vType instanceof ArrayTypeDenoter arrayType) {
reporter.reportError("array expected here", "", ast.V.getPosition()); checkAndReportError(eType.equals(StdEnvironment.integerType), "Integer expression expected here",
ast.E);
ast.type = arrayType.T;
} else { } else {
if (!eType.equals(StdEnvironment.integerType)) { reportError("array expected here", ast.V);
reporter.reportError("Integer expression expected here", "", ast.E.getPosition());
}
ast.type = ((ArrayTypeDenoter) vType).T;
} }
} }
return ast.type; return ast.type;
} }
@ -842,24 +756,54 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
private static SourcePosition dummyPos = new SourcePosition(); private static SourcePosition dummyPos = new SourcePosition();
private ErrorReporter reporter; private ErrorReporter reporter;
// Reports that the identifier or operator used at a leaf of the AST private void reportUndeclaredOrError(Declaration binding, Terminal leaf, String message) {
// has not been declared. if (binding == null) {
reportError("\"%\" is not declared", leaf);
} else {
reportError(message, leaf);
}
}
private void reportError(String message, Terminal ast) {
reportError(message, ast, ast);
}
private void reportError(String message, Terminal spellingNode, AbstractSyntaxTree positionNode) {
reporter.reportError(message, spellingNode.spelling, positionNode.getPosition());
}
private void reportError(String message, AbstractSyntaxTree positionNode) {
reporter.reportError(message, "", positionNode.getPosition());
}
private void checkAndReportError(boolean condition, String message, String token, SourcePosition position) {
if (!condition) {
reporter.reportError(message, token, position);
}
}
private void checkAndReportError(boolean condition, String message, Terminal ast) {
checkAndReportError(condition, message, ast, ast);
}
private void checkAndReportError(boolean condition, String message, Terminal spellingNode,
AbstractSyntaxTree positionNode) {
checkAndReportError(condition, message, spellingNode.spelling, positionNode.getPosition());
}
private void reportUndeclared(Terminal leaf) { private void checkAndReportError(boolean condition, String message, AbstractSyntaxTree positionNode) {
reporter.reportError("\"%\" is not declared", leaf.spelling, leaf.getPosition()); checkAndReportError(condition, message, "", positionNode.getPosition());
} }
private static TypeDenoter checkFieldIdentifier(FieldTypeDenoter ast, Identifier I) { private static TypeDenoter checkFieldIdentifier(FieldTypeDenoter ast, Identifier I) {
if (ast instanceof MultipleFieldTypeDenoter) { if (ast instanceof MultipleFieldTypeDenoter ft) {
var ft = (MultipleFieldTypeDenoter) ast;
if (ft.I.spelling.compareTo(I.spelling) == 0) { if (ft.I.spelling.compareTo(I.spelling) == 0) {
I.decl = ast; I.decl = ast;
return ft.T; return ft.T;
} else { } else {
return checkFieldIdentifier(ft.FT, I); return checkFieldIdentifier(ft.FT, I);
} }
} else if (ast instanceof SingleFieldTypeDenoter) { } else if (ast instanceof SingleFieldTypeDenoter ft) {
var ft = (SingleFieldTypeDenoter) ast;
if (ft.I.spelling.compareTo(I.spelling) == 0) { if (ft.I.spelling.compareTo(I.spelling) == 0) {
I.decl = ast; I.decl = ast;
return ft.T; return ft.T;