ContextAnalysis: Track local variables and function parameters separately.
This enables us to add all local variable Definitions to the DAST so that downstream visitors don't need to compute the local variables of a function again.
This commit is contained in:
@@ -8,10 +8,12 @@ import de.hsrm.compiler.Klang.nodes.loops.ForLoop;
|
|||||||
import de.hsrm.compiler.Klang.nodes.loops.WhileLoop;
|
import de.hsrm.compiler.Klang.nodes.loops.WhileLoop;
|
||||||
import de.hsrm.compiler.Klang.nodes.statements.*;
|
import de.hsrm.compiler.Klang.nodes.statements.*;
|
||||||
import de.hsrm.compiler.Klang.types.Type;
|
import de.hsrm.compiler.Klang.types.Type;
|
||||||
|
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
||||||
|
Map<String, VariableDeclaration> params = new HashMap<>();
|
||||||
Map<String, VariableDeclaration> vars = new HashMap<>();
|
Map<String, VariableDeclaration> vars = new HashMap<>();
|
||||||
Map<String, FunctionDefinition> functionDefs;
|
Map<String, FunctionDefinition> functionDefs;
|
||||||
Map<String, StructDefinition> structDefs;
|
Map<String, StructDefinition> structDefs;
|
||||||
@@ -199,8 +201,8 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vars.get(variableName) != null) {
|
if (vars.get(variableName) != null || params.get(variableName) != null) {
|
||||||
var error = "Redeclaration of variable with name \"" + variableName + "\".";
|
var error = "Redeclaration of variable or parameter with name \"" + variableName + "\".";
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,31 +238,27 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node visitVariable_assignment(KlangParser.Variable_assignmentContext ctx) {
|
public Node visitVariable_assignment(KlangParser.Variable_assignmentContext ctx) {
|
||||||
String name = ctx.IDENT().getText();
|
var name = ctx.IDENT().getText();
|
||||||
int line = ctx.start.getLine();
|
var line = ctx.start.getLine();
|
||||||
int col = ctx.start.getCharPositionInLine();
|
var col = ctx.start.getCharPositionInLine();
|
||||||
|
|
||||||
VariableDeclaration var = this.vars.get(name);
|
var variableOrParameter = getVariableOrParameter(name, line, col);
|
||||||
if (var == null) {
|
|
||||||
String error = "Variable with name \"" + name + "\" not defined.";
|
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate the expression
|
// Evaluate the expression
|
||||||
Expression expression = (Expression) this.visit(ctx.expression());
|
var expression = (Expression) visit(ctx.expression());
|
||||||
|
|
||||||
// Make sure expression can be assigned to the variable
|
// Make sure expression can be assigned to the variable
|
||||||
try {
|
try {
|
||||||
expression.type.combine(var.type);
|
expression.type.combine(variableOrParameter.type);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since we assigned a value to this variable, we can consider it initialized
|
// Since we assigned a value to this variable, we can consider it initialized
|
||||||
var.initialized = true;
|
variableOrParameter.initialized = true;
|
||||||
|
|
||||||
// Create a new node and add the type of the expression to it
|
// Create a new node and add the type of the expression to it
|
||||||
Node result = new VariableAssignment(name, expression);
|
var result = new VariableAssignment(name, expression);
|
||||||
result.line = line;
|
result.line = line;
|
||||||
result.col = col;
|
result.col = col;
|
||||||
return result;
|
return result;
|
||||||
@@ -272,8 +270,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
ReturnStatement result = new ReturnStatement(expression);
|
ReturnStatement result = new ReturnStatement(expression);
|
||||||
|
|
||||||
// Check if this expression is a tail recursion
|
// Check if this expression is a tail recursion
|
||||||
if (expression instanceof FunctionCall) {
|
if (expression instanceof FunctionCall funCall) {
|
||||||
var funCall = (FunctionCall) expression;
|
|
||||||
if (funCall.name.equals(this.currentFunctionDefinitionName)) {
|
if (funCall.name.equals(this.currentFunctionDefinitionName)) {
|
||||||
// Flag this function call
|
// Flag this function call
|
||||||
funCall.isTailRecursive = true;
|
funCall.isTailRecursive = true;
|
||||||
@@ -288,46 +285,24 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node visitField_assignment(KlangParser.Field_assignmentContext ctx) {
|
public Node visitField_assignment(KlangParser.Field_assignmentContext ctx) {
|
||||||
String varName = ctx.IDENT(0).getText();
|
var varName = ctx.IDENT(0).getText();
|
||||||
int line = ctx.start.getLine();
|
var line = ctx.start.getLine();
|
||||||
int col = ctx.start.getCharPositionInLine();
|
var col = ctx.start.getCharPositionInLine();
|
||||||
String[] path = new String[ctx.IDENT().size() - 1];
|
var path = createStructPath(ctx.IDENT());
|
||||||
|
|
||||||
for (int i = 1; i < ctx.IDENT().size(); i++) {
|
var variableOrParameter = getVariableOrParameter(varName, line, col);
|
||||||
path[i - 1] = ctx.IDENT(i).getText();
|
ensureReferencesStruct(variableOrParameter, line, col);
|
||||||
}
|
var fieldType = drillType(variableOrParameter, path, line, col);
|
||||||
|
|
||||||
// Get the referenced variable, make sure it is defined
|
// Visit the expression and make sure the type combines properly
|
||||||
var variableDef = this.vars.get(varName);
|
var expression = (Expression) visit(ctx.expression());
|
||||||
if (variableDef == null) {
|
|
||||||
String error = "Variable with name " + varName + " not defined.";
|
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure it references a struct
|
|
||||||
if (variableDef.type.isPrimitiveType()) {
|
|
||||||
String error = "Variable must reference a struct but references " + variableDef.type.getName() + ".";
|
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the type of the result of this expression
|
|
||||||
String structName = variableDef.type.getName();
|
|
||||||
Type fieldType;
|
|
||||||
try {
|
|
||||||
fieldType = Helper.drillType(this.structDefs, structName, path, 0);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the expression and make sure the type combines properly
|
|
||||||
Expression expression = (Expression) this.visit(ctx.expression());
|
|
||||||
try {
|
try {
|
||||||
fieldType.combine(expression.type);
|
fieldType.combine(expression.type);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
Node result = new FieldAssignment(varName, structName, path, expression);
|
var result = new FieldAssignment(varName, variableOrParameter.type.getName(), path, expression);
|
||||||
result.col = col;
|
result.col = col;
|
||||||
result.line = line;
|
result.line = line;
|
||||||
return result;
|
return result;
|
||||||
@@ -338,23 +313,17 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
var baseName = ctx.IDENT(0).getText();
|
var baseName = ctx.IDENT(0).getText();
|
||||||
var line = ctx.start.getLine();
|
var line = ctx.start.getLine();
|
||||||
var col = ctx.start.getCharPositionInLine();
|
var col = ctx.start.getCharPositionInLine();
|
||||||
|
var path = createStructPath(ctx.IDENT());
|
||||||
// Create a list of member names. This excludes
|
|
||||||
// the first entry as it is the base name.
|
|
||||||
var path = new ArrayList<String>();
|
|
||||||
for (int i = 1; i < ctx.IDENT().size(); i++) {
|
|
||||||
path.add(ctx.IDENT(i).getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if the base name points to an enum or a variable
|
// Determine if the base name points to an enum or a variable
|
||||||
var enumDef = enumDefs.get(baseName);
|
var enumDef = enumDefs.get(baseName);
|
||||||
if (enumDef != null) {
|
if (enumDef != null) {
|
||||||
if (path.size() != 1) {
|
if (path.length != 1) {
|
||||||
var error = "Illegal access to enum " + enumDef.name + ".";
|
var error = "Illegal access to enum " + enumDef.name + ".";
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
}
|
}
|
||||||
|
|
||||||
var enumValueName = path.get(0);
|
var enumValueName = path[0];
|
||||||
var enumValue = Arrays.stream(enumDef.enums)
|
var enumValue = Arrays.stream(enumDef.enums)
|
||||||
.filter(e -> e.value.equals(enumValueName))
|
.filter(e -> e.value.equals(enumValueName))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
@@ -371,29 +340,11 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
return enumAccessExpression;
|
return enumAccessExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the referenced variable, make sure it is defined
|
var variableOrParameter = getVariableOrParameter(baseName, line, col);
|
||||||
var variableDef = vars.get(baseName);
|
ensureReferencesStruct(variableOrParameter, line, col);
|
||||||
if (variableDef == null) {
|
var resultType = drillType(variableOrParameter, path, line, col);
|
||||||
var error = "Variable with name " + baseName + " not defined.";
|
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure it references a struct
|
var memberAccessExpression = new MemberAccessExpression(baseName, variableOrParameter.type.getName(), path);
|
||||||
if (variableDef.type.isPrimitiveType()) {
|
|
||||||
var error = "Variable must reference a struct but references " + variableDef.type.getName() + ".";
|
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the type of the result of this expression
|
|
||||||
var structName = variableDef.type.getName();
|
|
||||||
Type resultType;
|
|
||||||
try {
|
|
||||||
resultType = Helper.drillType(structDefs, structName, path.toArray(new String[0]), 0);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
var memberAccessExpression = new MemberAccessExpression(baseName, structName, path.toArray(new String[0]));
|
|
||||||
memberAccessExpression.type = resultType;
|
memberAccessExpression.type = resultType;
|
||||||
memberAccessExpression.line = line;
|
memberAccessExpression.line = line;
|
||||||
memberAccessExpression.col = col;
|
memberAccessExpression.col = col;
|
||||||
@@ -711,24 +662,20 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node visitVariable(KlangParser.VariableContext ctx) {
|
public Node visitVariable(KlangParser.VariableContext ctx) {
|
||||||
String name = ctx.IDENT().getText();
|
var variableName = ctx.IDENT().getText();
|
||||||
int line = ctx.start.getLine();
|
var line = ctx.start.getLine();
|
||||||
int col = ctx.start.getCharPositionInLine();
|
var col = ctx.start.getCharPositionInLine();
|
||||||
|
|
||||||
VariableDeclaration var = this.vars.get(name);
|
var variableOrParameter = getVariableOrParameter(variableName, line, col);
|
||||||
if (var == null) {
|
|
||||||
String error = "Variable with name \"" + name + "\" not defined.";
|
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the variable has been initialized before it can be used
|
// Make sure the variable has been initialized before it can be used
|
||||||
if (!var.initialized) {
|
if (!variableOrParameter.initialized) {
|
||||||
String error = "Variable with name \"" + name + "\" has not been initialized.";
|
var error = "Variable with name \"" + variableName + "\" has not been initialized.";
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable result = new Variable(ctx.IDENT().getText());
|
var result = new Variable(ctx.IDENT().getText());
|
||||||
result.type = var.type;
|
result.type = variableOrParameter.type;
|
||||||
result.line = line;
|
result.line = line;
|
||||||
result.col = col;
|
result.col = col;
|
||||||
return result;
|
return result;
|
||||||
@@ -839,23 +786,23 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new set for the variables of the current function
|
// Create a new set for the variables and parameters of the current function
|
||||||
// this will be filled in the variable declaration visitor as well
|
// this will be filled in the variable declaration visitor as well
|
||||||
vars = new HashMap<>();
|
vars = new HashMap<>();
|
||||||
|
params = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
// Process the parameter list by visiting every parameter in it
|
|
||||||
var paramCount = ctx.params.parameter().size();
|
var paramCount = ctx.params.parameter().size();
|
||||||
var params = new Parameter[paramCount];
|
var functionParameters = new Parameter[paramCount]; // the list of parameters that get passed to FunctionDefinition
|
||||||
for (int i = 0; i < paramCount; i++) {
|
for (int i = 0; i < paramCount; i++) {
|
||||||
// Add the parameter to the list of parameters
|
functionParameters[i] = (Parameter) visit(ctx.params.parameter(i));
|
||||||
var param = (Parameter) visit(ctx.params.parameter(i));
|
|
||||||
params[i] = param;
|
|
||||||
|
|
||||||
// add the param as a variable
|
// add the param as a variable to the global parameter map so that
|
||||||
var var = new VariableDeclaration(param.name);
|
// child nodes can access them.
|
||||||
var.initialized = true; // parameters can always be considered initialized
|
var param = new VariableDeclaration(functionParameters[i].name);
|
||||||
var.type = param.type;
|
param.initialized = true; // parameters can always be considered initialized
|
||||||
vars.put(param.name, var);
|
param.type = functionParameters[i].type;
|
||||||
|
params.put(param.name, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visit the block, make sure that a return value is guaranteed
|
// Visit the block, make sure that a return value is guaranteed
|
||||||
@@ -867,7 +814,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
}
|
}
|
||||||
|
|
||||||
var functionDef = new FunctionDefinition(name, params, (Block) block);
|
var functionDef = new FunctionDefinition(name, functionParameters, vars.values().toArray(new VariableDeclaration[0]), (Block) block);
|
||||||
functionDef.type = returnType;
|
functionDef.type = returnType;
|
||||||
functionDef.line = ctx.start.getLine();
|
functionDef.line = ctx.start.getLine();
|
||||||
functionDef.col = ctx.start.getCharPositionInLine();
|
functionDef.col = ctx.start.getCharPositionInLine();
|
||||||
@@ -988,19 +935,52 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node visitDestroy_statement(KlangParser.Destroy_statementContext ctx) {
|
public Node visitDestroy_statement(KlangParser.Destroy_statementContext ctx) {
|
||||||
String name = ctx.IDENT().getText();
|
var varName = ctx.IDENT().getText();
|
||||||
int line = ctx.start.getLine();
|
var line = ctx.start.getLine();
|
||||||
int col = ctx.start.getCharPositionInLine();
|
var col = ctx.start.getCharPositionInLine();
|
||||||
|
|
||||||
VariableDeclaration var = this.vars.get(name);
|
|
||||||
if (var == null) {
|
|
||||||
String error = "Variable with name \"" + name + "\" not defined.";
|
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
|
||||||
}
|
|
||||||
|
|
||||||
Node result = new DestructorCall(name);
|
var variableOrParameter = getVariableOrParameter(varName, line, col);
|
||||||
|
ensureReferencesStruct(variableOrParameter, line, col);
|
||||||
|
|
||||||
|
var result = new DestructorCall(varName);
|
||||||
result.line = line;
|
result.line = line;
|
||||||
result.col = col;
|
result.col = col;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private VariableDeclaration getVariableOrParameter(String name, int line, int col) {
|
||||||
|
var variable = vars.get(name);
|
||||||
|
var parameter = params.get(name);
|
||||||
|
if (variable == null && parameter == null) {
|
||||||
|
var error = "Variable or parameter with name \"" + name + "\" not defined.";
|
||||||
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return variable != null ? variable : parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureReferencesStruct(VariableDeclaration variableOrParameter, int line, int col) {
|
||||||
|
if (variableOrParameter.type.isPrimitiveType() || enumDefs.containsKey(variableOrParameter.type.getName())) {
|
||||||
|
var error = "Variable or parameter must reference a struct but references " + variableOrParameter.type.getName() + ".";
|
||||||
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Type drillType(VariableDeclaration variableOrParameter, String[] path, int line, int col) {
|
||||||
|
try {
|
||||||
|
var structName = variableOrParameter.type.getName();
|
||||||
|
return Helper.drillType(structDefs, structName, path, 0);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] createStructPath(List<TerminalNode> identifiers) {
|
||||||
|
// Create a list of member names. This excludes the first entry as it is the base name.
|
||||||
|
var path = new String[identifiers.size() - 1];
|
||||||
|
for (int i = 1; i < identifiers.size(); i++) {
|
||||||
|
path[i - 1] = identifiers.get(i).getText();
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -210,7 +210,7 @@ public class GetDefinitions extends KlangBaseVisitor<Node> {
|
|||||||
parameters.put(paramName, parameter);
|
parameters.put(paramName, parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
var functionDef = new FunctionDefinition(funcName, parameters.values().toArray(new Parameter[0]), null);
|
var functionDef = new FunctionDefinition(funcName, parameters.values().toArray(new Parameter[0]), null, null);
|
||||||
functionDef.type = Type.getByName(ctx.returnType.type().getText());
|
functionDef.type = Type.getByName(ctx.returnType.type().getText());
|
||||||
functionDef.line = line;
|
functionDef.line = line;
|
||||||
functionDef.col = col;
|
functionDef.col = col;
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
package de.hsrm.compiler.Klang.nodes;
|
package de.hsrm.compiler.Klang.nodes;
|
||||||
|
|
||||||
|
import de.hsrm.compiler.Klang.nodes.statements.VariableDeclaration;
|
||||||
import de.hsrm.compiler.Klang.visitors.Visitor;
|
import de.hsrm.compiler.Klang.visitors.Visitor;
|
||||||
|
|
||||||
public class FunctionDefinition extends Node {
|
public class FunctionDefinition extends Node {
|
||||||
|
|
||||||
public String name;
|
public String name;
|
||||||
public Parameter[] parameters;
|
public Parameter[] parameters;
|
||||||
|
public VariableDeclaration[] localVariables;
|
||||||
public Block block;
|
public Block block;
|
||||||
|
|
||||||
public FunctionDefinition(String name, Parameter[] parameters, Block block) {
|
public FunctionDefinition(String name, Parameter[] parameters, VariableDeclaration[] localVariables, Block block) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.parameters = parameters;
|
this.parameters = parameters;
|
||||||
this.block = block;
|
this.block = block;
|
||||||
|
this.localVariables = localVariables;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
package de.hsrm.compiler.Klang.types;
|
package de.hsrm.compiler.Klang.types;
|
||||||
|
|
||||||
import de.hsrm.compiler.Klang.Value;
|
import de.hsrm.compiler.Klang.Value;
|
||||||
import de.hsrm.compiler.Klang.nodes.EnumDefinition;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.FunctionDefinition;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.StructDefinition;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class NamedType extends Type {
|
public class NamedType extends Type {
|
||||||
public String name;
|
public String name;
|
||||||
@@ -49,8 +44,7 @@ public class NamedType extends Type {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (that instanceof NamedType) {
|
if (that instanceof NamedType thatType) {
|
||||||
var thatType = (NamedType) that;
|
|
||||||
return getName().equals(thatType.getName());
|
return getName().equals(thatType.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,6 @@ public class DestroyStatementTest {
|
|||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||||
|
|
||||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||||
assertEquals("Error in line 1:45 Variable with name \"x\" not defined.", e.getMessage());
|
assertEquals("Error in line 1:45 Variable or parameter with name \"x\" not defined.", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ public class FieldAssignmentTest {
|
|||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||||
|
|
||||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||||
assertEquals("Error in line 1:46 Variable with name str not defined.", e.getMessage());
|
assertEquals("Error in line 1:46 Variable or parameter with name \"str\" not defined.", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -29,6 +29,6 @@ public class FieldAssignmentTest {
|
|||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||||
|
|
||||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||||
assertEquals("Error in line 1:62 Variable must reference a struct but references int.", e.getMessage());
|
assertEquals("Error in line 1:62 Variable or parameter must reference a struct but references int.", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,4 +92,28 @@ public class FunctionDefinitionTest {
|
|||||||
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||||
assertEquals("Error in line 1:31 Parameter name Bar duplicates an enum of the same name.", e.getMessage());
|
assertEquals("Error in line 1:31 Parameter name Bar duplicates an enum of the same name.", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldResetVariablesAndParameterEnvironment() {
|
||||||
|
// given
|
||||||
|
var tree = Helper.prepareParser("""
|
||||||
|
function foo(x: int): int {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
function bar(): int {
|
||||||
|
let x: int = 0;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
bar();
|
||||||
|
""");
|
||||||
|
var ctxAnal = new ContextAnalysis(
|
||||||
|
Helper.getFuncs(tree),
|
||||||
|
Helper.getStructs(tree),
|
||||||
|
Helper.getEnums(tree)
|
||||||
|
);
|
||||||
|
|
||||||
|
// when / then
|
||||||
|
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@ public class StructFieldAccessTest {
|
|||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||||
|
|
||||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||||
assertEquals("Error in line 1:53 Variable with name str not defined.", e.getMessage());
|
assertEquals("Error in line 1:53 Variable or parameter with name \"str\" not defined.", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -28,6 +28,6 @@ public class StructFieldAccessTest {
|
|||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||||
|
|
||||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||||
assertEquals("Error in line 1:69 Variable must reference a struct but references int.", e.getMessage());
|
assertEquals("Error in line 1:69 Variable or parameter must reference a struct but references int.", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,6 +17,6 @@ public class VariableAssignmentTest {
|
|||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||||
|
|
||||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||||
assertEquals("Error in line 1:22 Variable with name \"x\" not defined.", e.getMessage());
|
assertEquals("Error in line 1:22 Variable or parameter with name \"x\" not defined.", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ public class VariableTest {
|
|||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||||
|
|
||||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||||
assertEquals("Error in line 1:29 Variable with name \"x\" not defined.", e.getMessage());
|
assertEquals("Error in line 1:29 Variable or parameter with name \"x\" not defined.", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user