WIP: Add enum support
This commit is contained in:
@@ -5,7 +5,11 @@ parse
|
|||||||
;
|
;
|
||||||
|
|
||||||
program
|
program
|
||||||
: (functionDef | structDef)* expression SCOL
|
: (functionDef | structDef | enumDef)* expression SCOL
|
||||||
|
;
|
||||||
|
|
||||||
|
enumDef
|
||||||
|
: ENUM enumName=IDENT OBRK (IDENT (COMMA IDENT)*)+ CBRK
|
||||||
;
|
;
|
||||||
|
|
||||||
structDef
|
structDef
|
||||||
@@ -143,6 +147,7 @@ forLoop
|
|||||||
IF: 'if';
|
IF: 'if';
|
||||||
ELSE: 'else';
|
ELSE: 'else';
|
||||||
FUNC: 'function';
|
FUNC: 'function';
|
||||||
|
ENUM: 'enum';
|
||||||
STRUCT: 'struct';
|
STRUCT: 'struct';
|
||||||
RETURN: 'return';
|
RETURN: 'return';
|
||||||
LET: 'let';
|
LET: 'let';
|
||||||
|
|||||||
@@ -15,8 +15,9 @@ import de.hsrm.compiler.Klang.types.Type;
|
|||||||
|
|
||||||
public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
||||||
Map<String, VariableDeclaration> vars = new HashMap<>();
|
Map<String, VariableDeclaration> vars = new HashMap<>();
|
||||||
Map<String, FunctionInformation> funcs;
|
Map<String, FunctionInformation> functionDefs;
|
||||||
Map<String, StructDefinition> structs;
|
Map<String, StructDefinition> structDefs;
|
||||||
|
Map<String, EnumDefinition> enumDefs;
|
||||||
Type currentDeclaredReturnType;
|
Type currentDeclaredReturnType;
|
||||||
String currentFunctionDefinitionName;
|
String currentFunctionDefinitionName;
|
||||||
|
|
||||||
@@ -27,9 +28,14 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContextAnalysis(Map<String, FunctionInformation> funcs, Map<String, StructDefinition> structs) {
|
public ContextAnalysis(
|
||||||
this.funcs = funcs;
|
Map<String, FunctionInformation> functionDefs,
|
||||||
this.structs = structs;
|
Map<String, StructDefinition> structDefs,
|
||||||
|
Map<String, EnumDefinition> enumDefs
|
||||||
|
) {
|
||||||
|
this.functionDefs = functionDefs;
|
||||||
|
this.structDefs = structDefs;
|
||||||
|
this.enumDefs = enumDefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -41,7 +47,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Expression expression = (Expression) this.visit(ctx.expression());
|
Expression expression = (Expression) this.visit(ctx.expression());
|
||||||
Program result = new Program(funcs, this.structs, expression);
|
Program result = new Program(funcs, structDefs, enumDefs, expression);
|
||||||
result.type = expression.type;
|
result.type = expression.type;
|
||||||
result.line = ctx.start.getLine();
|
result.line = ctx.start.getLine();
|
||||||
result.col = ctx.start.getCharPositionInLine();
|
result.col = ctx.start.getCharPositionInLine();
|
||||||
@@ -67,7 +73,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
statements[i] = (Statement) currentStatement;
|
statements[i] = (Statement) currentStatement;
|
||||||
actualStatementCount += 1;
|
actualStatementCount += 1;
|
||||||
|
|
||||||
// We use the existance of a type to indicate that this statement returns
|
// We use the existence of a type to indicate that this statement returns
|
||||||
// something for which the VariableDeclaration is an exception
|
// something for which the VariableDeclaration is an exception
|
||||||
if (currentStatement.type != null && !(currentStatement instanceof VariableDeclaration)) {
|
if (currentStatement.type != null && !(currentStatement instanceof VariableDeclaration)) {
|
||||||
// check whether the type matches
|
// check whether the type matches
|
||||||
@@ -89,9 +95,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
// create a shorter statements array and copy the statements to there
|
// create a shorter statements array and copy the statements to there
|
||||||
if (actualStatementCount < declaredStatementCount) {
|
if (actualStatementCount < declaredStatementCount) {
|
||||||
Statement[] newStatements = new Statement[actualStatementCount];
|
Statement[] newStatements = new Statement[actualStatementCount];
|
||||||
for (int i = 0; i < actualStatementCount; i++) {
|
System.arraycopy(statements, 0, newStatements, 0, actualStatementCount);
|
||||||
newStatements[i] = statements[i];
|
|
||||||
}
|
|
||||||
statements = newStatements;
|
statements = newStatements;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +181,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
int col = ctx.start.getCharPositionInLine();
|
int col = ctx.start.getCharPositionInLine();
|
||||||
Type declaredType = Type.getByName(ctx.type_annotation().type().getText());
|
Type declaredType = Type.getByName(ctx.type_annotation().type().getText());
|
||||||
|
|
||||||
if (!declaredType.isPrimitiveType() && this.structs.get(declaredType.getName()) == null) {
|
if (!declaredType.isPrimitiveType() && this.structDefs.get(declaredType.getName()) == null) {
|
||||||
String error = "Type " + declaredType.getName() + " not defined.";
|
String error = "Type " + declaredType.getName() + " not defined.";
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
}
|
}
|
||||||
@@ -291,7 +295,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
String structName = variableDef.type.getName();
|
String structName = variableDef.type.getName();
|
||||||
Type fieldType;
|
Type fieldType;
|
||||||
try {
|
try {
|
||||||
fieldType = Helper.drillType(this.structs, structName, path, 0);
|
fieldType = Helper.drillType(this.structDefs, structName, path, 0);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -338,7 +342,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
String structName = variableDef.type.getName();
|
String structName = variableDef.type.getName();
|
||||||
Type resultType;
|
Type resultType;
|
||||||
try {
|
try {
|
||||||
resultType = Helper.drillType(this.structs, structName, path, 0);
|
resultType = Helper.drillType(this.structDefs, structName, path, 0);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -708,7 +712,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node visitBoolAtom(KlangParser.BoolAtomContext ctx) {
|
public Node visitBoolAtom(KlangParser.BoolAtomContext ctx) {
|
||||||
Node n = new BooleanExpression(ctx.getText().equals("true") ? true : false);
|
Node n = new BooleanExpression(ctx.getText().equals("true"));
|
||||||
n.type = Type.getBooleanType();
|
n.type = Type.getBooleanType();
|
||||||
n.line = ctx.start.getLine();
|
n.line = ctx.start.getLine();
|
||||||
n.col = ctx.start.getCharPositionInLine();
|
n.col = ctx.start.getCharPositionInLine();
|
||||||
@@ -733,7 +737,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
this.currentDeclaredReturnType = returnType;
|
this.currentDeclaredReturnType = returnType;
|
||||||
this.currentFunctionDefinitionName = name;
|
this.currentFunctionDefinitionName = name;
|
||||||
|
|
||||||
if (!returnType.isPrimitiveType() && this.structs.get(returnType.getName()) == null) {
|
if (!returnType.isPrimitiveType() && this.structDefs.get(returnType.getName()) == null) {
|
||||||
String error = "Type " + returnType.getName() + " not defined.";
|
String error = "Type " + returnType.getName() + " not defined.";
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
}
|
}
|
||||||
@@ -779,7 +783,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
int col = ctx.start.getCharPositionInLine();
|
int col = ctx.start.getCharPositionInLine();
|
||||||
Type type = Type.getByName(ctx.type_annotation().type().getText());
|
Type type = Type.getByName(ctx.type_annotation().type().getText());
|
||||||
|
|
||||||
if (!type.isPrimitiveType() && this.structs.get(type.getName()) == null) {
|
if (!type.isPrimitiveType() && this.structDefs.get(type.getName()) == null) {
|
||||||
String error = "Type " + type.getName() + " not defined.";
|
String error = "Type " + type.getName() + " not defined.";
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
}
|
}
|
||||||
@@ -797,7 +801,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
int line = ctx.start.getLine();
|
int line = ctx.start.getLine();
|
||||||
int col = ctx.start.getCharPositionInLine();
|
int col = ctx.start.getCharPositionInLine();
|
||||||
|
|
||||||
FunctionInformation func = this.funcs.get(name);
|
FunctionInformation func = this.functionDefs.get(name);
|
||||||
if (func == null) {
|
if (func == null) {
|
||||||
String error = "Function with name \"" + name + "\" not defined.";
|
String error = "Function with name \"" + name + "\" not defined.";
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
@@ -835,7 +839,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
int col = ctx.start.getCharPositionInLine();
|
int col = ctx.start.getCharPositionInLine();
|
||||||
|
|
||||||
// Get the corresponding struct definition
|
// Get the corresponding struct definition
|
||||||
var struct = this.structs.get(name);
|
var struct = this.structDefs.get(name);
|
||||||
if (struct == null) {
|
if (struct == null) {
|
||||||
String error = "Struct with name \"" + name + "\" not defined.";
|
String error = "Struct with name \"" + name + "\" not defined.";
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
|
|||||||
218
src/main/java/de/hsrm/compiler/Klang/GetDefinitions.java
Normal file
218
src/main/java/de/hsrm/compiler/Klang/GetDefinitions.java
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
package de.hsrm.compiler.Klang;
|
||||||
|
|
||||||
|
import de.hsrm.compiler.Klang.helper.FunctionInformation;
|
||||||
|
import de.hsrm.compiler.Klang.helper.Helper;
|
||||||
|
import de.hsrm.compiler.Klang.nodes.*;
|
||||||
|
import de.hsrm.compiler.Klang.types.EnumType;
|
||||||
|
import de.hsrm.compiler.Klang.types.StructType;
|
||||||
|
import de.hsrm.compiler.Klang.types.Type;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
public class GetDefinitions extends KlangBaseVisitor<Node> {
|
||||||
|
private final Map<String, FunctionInformation> functionDefs;
|
||||||
|
private final Map<String, StructDefinition> structDefs;
|
||||||
|
private final Map<String, EnumDefinition> enumDefs;
|
||||||
|
|
||||||
|
private Set<String> functionNames;
|
||||||
|
private Set<String> structNames;
|
||||||
|
private Set<String> enumNames;
|
||||||
|
|
||||||
|
public GetDefinitions(
|
||||||
|
Map<String, FunctionInformation> functionDefs,
|
||||||
|
Map<String, StructDefinition> structDefs,
|
||||||
|
Map<String, EnumDefinition> enumDefs
|
||||||
|
) {
|
||||||
|
this.functionDefs = functionDefs;
|
||||||
|
this.structDefs = structDefs;
|
||||||
|
this.enumDefs = enumDefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> collectFunctionNames(KlangParser.ProgramContext ctx) {
|
||||||
|
var result = new HashSet<String>();
|
||||||
|
for (int i = 0; i < ctx.functionDef().size(); i++) {
|
||||||
|
var currentFunctionDef = ctx.functionDef(i);
|
||||||
|
var funcName = currentFunctionDef.funcName.getText();
|
||||||
|
if (result.contains(funcName)) {
|
||||||
|
var line = currentFunctionDef.funcName.getLine();
|
||||||
|
var col = currentFunctionDef.funcName.getCharPositionInLine();
|
||||||
|
var error = "Function " + funcName + " defined multiple times.";
|
||||||
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
|
}
|
||||||
|
result.add(funcName);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> collectStructNames(KlangParser.ProgramContext ctx) {
|
||||||
|
var result = new HashSet<String>();
|
||||||
|
for (int i = 0; i < ctx.structDef().size(); i++) {
|
||||||
|
var currentStructDef = ctx.structDef(i);
|
||||||
|
var structName = currentStructDef.structName.getText();
|
||||||
|
if (result.contains(structName)) {
|
||||||
|
var line = currentStructDef.structName.getLine();
|
||||||
|
var col = currentStructDef.structName.getCharPositionInLine();
|
||||||
|
var error = "Struct " + structName + " defined multiple times.";
|
||||||
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
|
}
|
||||||
|
result.add(structName);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> collectEnumNames(KlangParser.ProgramContext ctx) {
|
||||||
|
var result = new HashSet<String>();
|
||||||
|
for (int i = 0; i < ctx.enumDef().size(); i++) {
|
||||||
|
var currentEnumDef = ctx.enumDef(i);
|
||||||
|
var enumName = currentEnumDef.enumName.getText();
|
||||||
|
if (result.contains(enumName)) {
|
||||||
|
var line = currentEnumDef.enumName.getLine();
|
||||||
|
var col = currentEnumDef.enumName.getCharPositionInLine();
|
||||||
|
var error = "Enum " + enumName + " defined multiple times.";
|
||||||
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
|
}
|
||||||
|
result.add(enumName);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node visitProgram(KlangParser.ProgramContext ctx) {
|
||||||
|
functionNames = collectFunctionNames(ctx);
|
||||||
|
structNames = collectStructNames(ctx);
|
||||||
|
enumNames = collectEnumNames(ctx);
|
||||||
|
|
||||||
|
for (int i = 0; i < ctx.functionDef().size(); i++) {
|
||||||
|
visit(ctx.functionDef(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < ctx.structDef().size(); i++) {
|
||||||
|
visit(ctx.structDef(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < ctx.enumDef().size(); i++) {
|
||||||
|
visit(ctx.enumDef(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node visitEnumDef(KlangParser.EnumDefContext ctx) {
|
||||||
|
// Check that there isn't a function or struct with the same name
|
||||||
|
var enumName = ctx.enumName.getText();
|
||||||
|
if (functionNames.contains(enumName) || structNames.contains(enumName)) {
|
||||||
|
var line = ctx.start.getLine();
|
||||||
|
var col = ctx.start.getCharPositionInLine();
|
||||||
|
var error = "Duplicate use of name " + enumName + ".";
|
||||||
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDENT() includes the enumName as the first entry, which we skip
|
||||||
|
var enumFields = new HashSet<String>();
|
||||||
|
for (int i = 1; i < ctx.IDENT().size(); i++) {
|
||||||
|
var currentEnumField = ctx.IDENT(i);
|
||||||
|
var currentEnumFieldName = currentEnumField.getText();
|
||||||
|
if (enumFields.contains(currentEnumFieldName)) {
|
||||||
|
var line = currentEnumField.getSymbol().getLine();
|
||||||
|
var col = currentEnumField.getSymbol().getCharPositionInLine();
|
||||||
|
var error = " Duplicate enum value " + currentEnumFieldName + " in enum " + enumName + ".";
|
||||||
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
|
}
|
||||||
|
enumFields.add(currentEnumFieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
var enumDef = new EnumDefinition(enumName, enumFields.toArray(new String[0]));
|
||||||
|
enumDef.line = ctx.start.getLine();
|
||||||
|
enumDef.col = ctx.start.getCharPositionInLine();
|
||||||
|
enumDef.type = new EnumType(enumName);
|
||||||
|
enumDefs.put(enumName, enumDef);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node visitStructDef(KlangParser.StructDefContext ctx) {
|
||||||
|
var structName = ctx.structName.getText();
|
||||||
|
var structFieldCount = ctx.structField().size();
|
||||||
|
var structFields = new StructField[structFieldCount];
|
||||||
|
var structFieldNames = new HashSet<String>();
|
||||||
|
var line = ctx.start.getLine();
|
||||||
|
var col = ctx.start.getCharPositionInLine();
|
||||||
|
|
||||||
|
// Check that there isn't a function or enum with the same name
|
||||||
|
if (functionNames.contains(structName) || enumNames.contains(structName)) {
|
||||||
|
var error = "Duplicate use of name " + structName + ".";
|
||||||
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < structFieldCount; i++) {
|
||||||
|
var currentStructField = ctx.structField(i);
|
||||||
|
var structFieldName = currentStructField.IDENT().getText();
|
||||||
|
var structFieldTypeName = currentStructField.type_annotation().type().getText();
|
||||||
|
var structFieldLine = currentStructField.start.getLine();
|
||||||
|
var structFieldCol = currentStructField.start.getCharPositionInLine();
|
||||||
|
|
||||||
|
if (structFieldNames.contains(structFieldName)) {
|
||||||
|
var error = "Duplicate struct field " + structFieldName + " in struct " + structName + ".";
|
||||||
|
throw new RuntimeException(Helper.getErrorPrefix(structFieldLine, structFieldCol) + error);
|
||||||
|
}
|
||||||
|
|
||||||
|
var structField = new StructField(structFieldName);
|
||||||
|
structField.type = Type.getByName(structFieldTypeName);
|
||||||
|
structField.line = structFieldLine;
|
||||||
|
structField.col = structFieldCol;
|
||||||
|
|
||||||
|
structFieldNames.add(structFieldName);
|
||||||
|
structFields[i] = structField;
|
||||||
|
}
|
||||||
|
|
||||||
|
var structDef = new StructDefinition(structName, structFields);
|
||||||
|
structDef.line = line;
|
||||||
|
structDef.col = col;
|
||||||
|
structDef.type = new StructType(structName);
|
||||||
|
structDefs.put(structName, structDef);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node visitFunctionDef(KlangParser.FunctionDefContext ctx) {
|
||||||
|
var funcName = ctx.funcName.getText();
|
||||||
|
var returnType = Type.getByName(ctx.returnType.getText());
|
||||||
|
var parameters = new TreeMap<String, Type>();
|
||||||
|
var paramCount = ctx.params.parameter().size();
|
||||||
|
var signature = new Type[paramCount];
|
||||||
|
|
||||||
|
// Check that there isn't a struct or enum with the same name
|
||||||
|
if (structNames.contains(funcName) || enumNames.contains(funcName)) {
|
||||||
|
var line = ctx.start.getLine();
|
||||||
|
var col = ctx.start.getCharPositionInLine();
|
||||||
|
var error = "Duplicate use of name " + funcName + ".";
|
||||||
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < paramCount; i++) {
|
||||||
|
var currentParam = ctx.params.parameter(i);
|
||||||
|
var paramType = Type.getByName(currentParam.type_annotation().type().getText());
|
||||||
|
var paramName = currentParam.IDENT().getText();
|
||||||
|
|
||||||
|
if (parameters.containsKey(paramName)) {
|
||||||
|
var paramLine = currentParam.start.getLine();
|
||||||
|
var paramCol = currentParam.start.getCharPositionInLine();
|
||||||
|
var error = "Duplicate parameter name " + paramName + " in function " + funcName + ".";
|
||||||
|
throw new RuntimeException(Helper.getErrorPrefix(paramLine, paramCol) + error);
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters.put(paramName, paramType);
|
||||||
|
signature[i] = paramType;
|
||||||
|
}
|
||||||
|
|
||||||
|
var information = new FunctionInformation(funcName, returnType, parameters, signature);
|
||||||
|
functionDefs.put(funcName, information);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
package de.hsrm.compiler.Klang;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
import de.hsrm.compiler.Klang.types.*;
|
|
||||||
import de.hsrm.compiler.Klang.helper.*;
|
|
||||||
|
|
||||||
public class GetFunctions extends KlangBaseVisitor<Void> {
|
|
||||||
|
|
||||||
private Map<String, FunctionInformation> funcs;
|
|
||||||
|
|
||||||
public GetFunctions(Map<String, FunctionInformation> funcs) {
|
|
||||||
this.funcs = funcs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitProgram(KlangParser.ProgramContext ctx) {
|
|
||||||
for (int i = 0; i < ctx.functionDef().size(); i++) {
|
|
||||||
this.visit(ctx.functionDef(i));
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitFunctionDef(KlangParser.FunctionDefContext ctx) {
|
|
||||||
String name = ctx.funcName.getText();
|
|
||||||
int line = ctx.start.getLine();
|
|
||||||
int col = ctx.start.getCharPositionInLine();
|
|
||||||
|
|
||||||
if (this.funcs.containsKey(name)) {
|
|
||||||
String error = "Function " + name + " defined multiple times.";
|
|
||||||
throw new Error(Helper.getErrorPrefix(line, col) + error);
|
|
||||||
}
|
|
||||||
|
|
||||||
Type returnType = Type.getByName(ctx.returnType.type().getText());
|
|
||||||
|
|
||||||
TreeMap<String, Type> parameters = new TreeMap<String, Type>();
|
|
||||||
|
|
||||||
// Process the paremter list by visiting every paremter in it
|
|
||||||
int paramCount = ctx.params.parameter().size();
|
|
||||||
Type[] signature = new Type[paramCount];
|
|
||||||
for (int i = 0; i < paramCount; i++) {
|
|
||||||
Type paramType = Type.getByName(ctx.params.parameter(i).type_annotation().type().getText());
|
|
||||||
String paramName = ctx.params.parameter(i).IDENT().getText();
|
|
||||||
parameters.put(paramName, paramType);
|
|
||||||
signature[i] = paramType;
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionInformation information = new FunctionInformation(name, returnType, parameters, signature);
|
|
||||||
this.funcs.put(name, information);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package de.hsrm.compiler.Klang;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import de.hsrm.compiler.Klang.helper.Helper;
|
|
||||||
|
|
||||||
public class GetStructNames extends KlangBaseVisitor<Void> {
|
|
||||||
private Set<String> structNames;
|
|
||||||
|
|
||||||
public GetStructNames(Set<String> structNames) {
|
|
||||||
this.structNames = structNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitProgram(KlangParser.ProgramContext ctx) {
|
|
||||||
for (int i = 0; i < ctx.structDef().size(); i++) {
|
|
||||||
this.visit(ctx.structDef(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitStructDef(KlangParser.StructDefContext ctx) {
|
|
||||||
String name = ctx.structName.getText();
|
|
||||||
int line = ctx.start.getLine();
|
|
||||||
int col = ctx.start.getCharPositionInLine();
|
|
||||||
|
|
||||||
if (this.structNames.contains(name)) {
|
|
||||||
String error = "Struct " + name + " defined multiple times.";
|
|
||||||
throw new Error(Helper.getErrorPrefix(line, col) + error);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.structNames.add(name);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
package de.hsrm.compiler.Klang;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import de.hsrm.compiler.Klang.helper.Helper;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.Node;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.StructDefinition;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.StructField;
|
|
||||||
import de.hsrm.compiler.Klang.types.StructType;
|
|
||||||
import de.hsrm.compiler.Klang.types.Type;
|
|
||||||
|
|
||||||
public class GetStructs extends KlangBaseVisitor<Node> {
|
|
||||||
|
|
||||||
private Set<String> structNames;
|
|
||||||
private Map<String, StructDefinition> structs;
|
|
||||||
|
|
||||||
public GetStructs(Set<String> structNames, Map<String, StructDefinition> structs) {
|
|
||||||
this.structs = structs;
|
|
||||||
this.structNames = structNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Node visitProgram(KlangParser.ProgramContext ctx) {
|
|
||||||
for (int i = 0; i < ctx.structDef().size(); i++) {
|
|
||||||
this.visit(ctx.structDef(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Node visitStructDef(KlangParser.StructDefContext ctx) {
|
|
||||||
String name = ctx.structName.getText();
|
|
||||||
int line = ctx.start.getLine();
|
|
||||||
int col = ctx.start.getCharPositionInLine();
|
|
||||||
StructField[] fields = new StructField[ctx.structField().size()];
|
|
||||||
|
|
||||||
for (int i = 0; i < ctx.structField().size(); i++) {
|
|
||||||
StructField field = (StructField) this.visit(ctx.structField(i));
|
|
||||||
fields[i] = field;
|
|
||||||
}
|
|
||||||
|
|
||||||
StructDefinition result = new StructDefinition(name, fields);
|
|
||||||
result.line = line;
|
|
||||||
result.col = col;
|
|
||||||
result.type = new StructType(name);
|
|
||||||
this.structs.put(name, result);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Node visitStructField(KlangParser.StructFieldContext ctx) {
|
|
||||||
String name = ctx.IDENT().getText();
|
|
||||||
int line = ctx.start.getLine();
|
|
||||||
int col = ctx.start.getCharPositionInLine();
|
|
||||||
Type type = Type.getByName(ctx.type_annotation().type().getText());
|
|
||||||
|
|
||||||
if (!type.isPrimitiveType() && !this.structNames.contains(type.getName())) {
|
|
||||||
String error = "Type " + type.getName() + " not defined.";
|
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
|
||||||
}
|
|
||||||
|
|
||||||
Node result = new StructField(name);
|
|
||||||
result.type = type;
|
|
||||||
result.line = line;
|
|
||||||
result.col = col;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +1,22 @@
|
|||||||
package de.hsrm.compiler.Klang;
|
package de.hsrm.compiler.Klang;
|
||||||
|
|
||||||
// import ANTLR's runtime libraries
|
import de.hsrm.compiler.Klang.helper.FunctionInformation;
|
||||||
import org.antlr.v4.runtime.*;
|
import de.hsrm.compiler.Klang.nodes.EnumDefinition;
|
||||||
import org.antlr.v4.runtime.tree.*;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
import de.hsrm.compiler.Klang.nodes.Node;
|
import de.hsrm.compiler.Klang.nodes.Node;
|
||||||
import de.hsrm.compiler.Klang.nodes.StructDefinition;
|
import de.hsrm.compiler.Klang.nodes.StructDefinition;
|
||||||
import de.hsrm.compiler.Klang.visitors.*;
|
import de.hsrm.compiler.Klang.visitors.EvalVisitor;
|
||||||
import de.hsrm.compiler.Klang.helper.*;
|
import de.hsrm.compiler.Klang.visitors.GenASM;
|
||||||
|
import de.hsrm.compiler.Klang.visitors.PrettyPrintVisitor;
|
||||||
|
import org.antlr.v4.runtime.CharStream;
|
||||||
|
import org.antlr.v4.runtime.CharStreams;
|
||||||
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class Klang {
|
public class Klang {
|
||||||
|
|
||||||
@@ -87,22 +90,15 @@ public class Klang {
|
|||||||
|
|
||||||
// Context Analysis and DAST generation
|
// Context Analysis and DAST generation
|
||||||
Node root;
|
Node root;
|
||||||
HashMap<String, StructDefinition> structs;
|
var functionDefs = new HashMap<String, FunctionInformation>();
|
||||||
|
var structDefs = new HashMap<String, StructDefinition>();
|
||||||
|
var enumDefs = new HashMap<String, EnumDefinition>();
|
||||||
try {
|
try {
|
||||||
// Extract information about all functions
|
// Extract information about all definitions
|
||||||
var functionDefinitions = new HashMap<String, FunctionInformation>();
|
new GetDefinitions(functionDefs, structDefs, enumDefs).visit(tree);
|
||||||
new GetFunctions(functionDefinitions).visit(tree);
|
|
||||||
|
|
||||||
// Extract names of all structs
|
|
||||||
var structNames = new HashSet<String>();
|
|
||||||
new GetStructNames(structNames).visit(tree);
|
|
||||||
|
|
||||||
// Extract information about all structs
|
|
||||||
structs = new HashMap<String, StructDefinition>();
|
|
||||||
new GetStructs(structNames, structs).visit(tree);
|
|
||||||
|
|
||||||
// Create the DAST
|
// Create the DAST
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(functionDefinitions, structs);
|
ContextAnalysis ctxAnal = new ContextAnalysis(functionDefs, structDefs, enumDefs);
|
||||||
root = ctxAnal.visit(tree);
|
root = ctxAnal.visit(tree);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println(e.getMessage());
|
System.err.println(e.getMessage());
|
||||||
@@ -122,14 +118,14 @@ public class Klang {
|
|||||||
if (evaluate) {
|
if (evaluate) {
|
||||||
// Evaluate the sourcecode and print the result
|
// Evaluate the sourcecode and print the result
|
||||||
System.out.println("\nEvaluating the source code:");
|
System.out.println("\nEvaluating the source code:");
|
||||||
EvalVisitor evalVisitor = new EvalVisitor(structs);
|
EvalVisitor evalVisitor = new EvalVisitor(structDefs);
|
||||||
Value result = root.welcome(evalVisitor);
|
Value result = root.welcome(evalVisitor);
|
||||||
generateOutput(out, "Result was: " + result.asObject().toString());
|
generateOutput(out, "Result was: " + result.asObject().toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate assembler code
|
// Generate assembler code
|
||||||
GenASM genasm = new GenASM(mainName, structs);
|
GenASM genasm = new GenASM(mainName, structDefs);
|
||||||
root.welcome(genasm);
|
root.welcome(genasm);
|
||||||
generateOutput(out, genasm.toAsm());
|
generateOutput(out, genasm.toAsm());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package de.hsrm.compiler.Klang.nodes;
|
||||||
|
|
||||||
|
import de.hsrm.compiler.Klang.visitors.Visitor;
|
||||||
|
|
||||||
|
public class EnumDefinition extends Node {
|
||||||
|
|
||||||
|
public String name;
|
||||||
|
public String[] enums;
|
||||||
|
|
||||||
|
public EnumDefinition(String name, String[] enums) {
|
||||||
|
this.name = name;
|
||||||
|
this.enums = enums;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <R> R welcome(Visitor<R> v) {
|
||||||
|
return v.visit(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,11 +9,18 @@ public class Program extends Node {
|
|||||||
|
|
||||||
public FunctionDefinition[] funcs;
|
public FunctionDefinition[] funcs;
|
||||||
public Map<String, StructDefinition> structs;
|
public Map<String, StructDefinition> structs;
|
||||||
|
public Map<String, EnumDefinition> enums;
|
||||||
public Expression expression;
|
public Expression expression;
|
||||||
|
|
||||||
public Program(FunctionDefinition[] funcs, Map<String, StructDefinition> structs, Expression expression) {
|
public Program(
|
||||||
|
FunctionDefinition[] funcs,
|
||||||
|
Map<String, StructDefinition> structs,
|
||||||
|
Map<String, EnumDefinition> enums,
|
||||||
|
Expression expression
|
||||||
|
) {
|
||||||
this.funcs = funcs;
|
this.funcs = funcs;
|
||||||
this.structs = structs;
|
this.structs = structs;
|
||||||
|
this.enums = enums;
|
||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
48
src/main/java/de/hsrm/compiler/Klang/types/EnumType.java
Normal file
48
src/main/java/de/hsrm/compiler/Klang/types/EnumType.java
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package de.hsrm.compiler.Klang.types;
|
||||||
|
|
||||||
|
public class EnumType extends Type {
|
||||||
|
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
public EnumType(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type combine(Type that) {
|
||||||
|
if(this.equals(that)) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeException("Type mismatch: cannot combine enum " + getName() + " and " + that.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPrimitiveType() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNumericType() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object that) {
|
||||||
|
if (this == that) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (that instanceof EnumType) {
|
||||||
|
var thatType = (EnumType) that;
|
||||||
|
return getName().equals(thatType.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,12 +4,7 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import de.hsrm.compiler.Klang.Value;
|
import de.hsrm.compiler.Klang.Value;
|
||||||
import de.hsrm.compiler.Klang.nodes.Block;
|
import de.hsrm.compiler.Klang.nodes.*;
|
||||||
import de.hsrm.compiler.Klang.nodes.FunctionDefinition;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.Parameter;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.Program;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.StructDefinition;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.StructField;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.expressions.*;
|
import de.hsrm.compiler.Klang.nodes.expressions.*;
|
||||||
import de.hsrm.compiler.Klang.nodes.loops.DoWhileLoop;
|
import de.hsrm.compiler.Klang.nodes.loops.DoWhileLoop;
|
||||||
import de.hsrm.compiler.Klang.nodes.loops.ForLoop;
|
import de.hsrm.compiler.Klang.nodes.loops.ForLoop;
|
||||||
@@ -471,6 +466,11 @@ public class EvalVisitor implements Visitor<Value> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value visit(EnumDefinition e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Value visit(StructDefinition e) {
|
public Value visit(StructDefinition e) {
|
||||||
// We get these from a previous visitor
|
// We get these from a previous visitor
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
package de.hsrm.compiler.Klang.visitors;
|
package de.hsrm.compiler.Klang.visitors;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
|
|
||||||
import de.hsrm.compiler.Klang.asm.ASM;
|
import de.hsrm.compiler.Klang.asm.ASM;
|
||||||
import de.hsrm.compiler.Klang.helper.Helper;
|
import de.hsrm.compiler.Klang.helper.Helper;
|
||||||
import de.hsrm.compiler.Klang.nodes.*;
|
import de.hsrm.compiler.Klang.nodes.*;
|
||||||
@@ -16,6 +10,8 @@ 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 java.util.*;
|
||||||
|
|
||||||
public class GenASM implements Visitor<Void> {
|
public class GenASM implements Visitor<Void> {
|
||||||
private class FloatWriter {
|
private class FloatWriter {
|
||||||
private StringBuilder sb = new StringBuilder();
|
private StringBuilder sb = new StringBuilder();
|
||||||
@@ -778,6 +774,11 @@ public class GenASM implements Visitor<Void> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visit(EnumDefinition e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visit(StructDefinition e) {
|
public Void visit(StructDefinition e) {
|
||||||
// We get these from a previous visitor
|
// We get these from a previous visitor
|
||||||
|
|||||||
@@ -234,6 +234,11 @@ class GetVars implements Visitor<Void> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visit(EnumDefinition e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visit(StructDefinition e) {
|
public Void visit(StructDefinition e) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -68,6 +68,12 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
|||||||
ex.nl();
|
ex.nl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (var enumDef: e.enums.values()) {
|
||||||
|
enumDef.welcome(this);
|
||||||
|
ex.nl();
|
||||||
|
ex.nl();
|
||||||
|
}
|
||||||
|
|
||||||
e.expression.welcome(this);
|
e.expression.welcome(this);
|
||||||
ex.write(";");
|
ex.write(";");
|
||||||
return null;
|
return null;
|
||||||
@@ -377,6 +383,22 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visit(EnumDefinition e) {
|
||||||
|
ex.write("enum " + e.name + " { ");
|
||||||
|
var first = true;
|
||||||
|
for(var enumName: e.enums) {
|
||||||
|
if (!first) {
|
||||||
|
ex.write(", ");
|
||||||
|
} else {
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
ex.write(enumName);
|
||||||
|
}
|
||||||
|
ex.write(" }");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visit(StructDefinition e) {
|
public Void visit(StructDefinition e) {
|
||||||
ex.write("struct " + e.name + " {");
|
ex.write("struct " + e.name + " {");
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
package de.hsrm.compiler.Klang.visitors;
|
package de.hsrm.compiler.Klang.visitors;
|
||||||
|
|
||||||
import de.hsrm.compiler.Klang.nodes.Block;
|
import de.hsrm.compiler.Klang.nodes.*;
|
||||||
import de.hsrm.compiler.Klang.nodes.FunctionDefinition;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.Parameter;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.Program;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.StructDefinition;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.StructField;
|
|
||||||
import de.hsrm.compiler.Klang.nodes.expressions.*;
|
import de.hsrm.compiler.Klang.nodes.expressions.*;
|
||||||
import de.hsrm.compiler.Klang.nodes.loops.*;
|
import de.hsrm.compiler.Klang.nodes.loops.*;
|
||||||
import de.hsrm.compiler.Klang.nodes.statements.*;
|
import de.hsrm.compiler.Klang.nodes.statements.*;
|
||||||
@@ -42,6 +37,7 @@ public interface Visitor<R> {
|
|||||||
R visit(FunctionCall e);
|
R visit(FunctionCall e);
|
||||||
R visit(Program e);
|
R visit(Program e);
|
||||||
R visit(Parameter e);
|
R visit(Parameter e);
|
||||||
|
R visit(EnumDefinition e);
|
||||||
R visit(StructDefinition e);
|
R visit(StructDefinition e);
|
||||||
R visit(StructField e);
|
R visit(StructField e);
|
||||||
R visit(StructFieldAccessExpression e);
|
R visit(StructFieldAccessExpression e);
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ public class AndTest {
|
|||||||
ParseTree tree = Helper.prepareParser("function foo(): bool { return 1 && 2; } foo();");
|
ParseTree tree = Helper.prepareParser("function foo(): bool { return 1 && 2; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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:30 && is only defined for bool.", e.getMessage());
|
assertEquals("Error in line 1:30 && is only defined for bool.", e.getMessage());
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ public class ConstructorCallTest {
|
|||||||
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): bar { return create schwurbel(1); } foo();");
|
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): bar { return create schwurbel(1); } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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:52 Struct with name \"schwurbel\" not defined.", e.getMessage());
|
assertEquals("Error in line 1:52 Struct with name \"schwurbel\" not defined.", e.getMessage());
|
||||||
@@ -24,7 +25,8 @@ public class ConstructorCallTest {
|
|||||||
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): bar { return create bar(1, false); } foo();");
|
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): bar { return create bar(1, false); } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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:52 Struct \"bar\" defined 1 fields, but got 2 constructor parameters.", e.getMessage());
|
assertEquals("Error in line 1:52 Struct \"bar\" defined 1 fields, but got 2 constructor parameters.", e.getMessage());
|
||||||
@@ -35,7 +37,8 @@ public class ConstructorCallTest {
|
|||||||
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): bar { return create bar(false); } foo();");
|
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): bar { return create bar(false); } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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:63 argument 0 Type missmatch: cannot combine bool and int", e.getMessage());
|
assertEquals("Error in line 1:63 argument 0 Type missmatch: cannot combine bool and int", e.getMessage());
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ public class DestroyStatementTest {
|
|||||||
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): int { destroy x; return 1; } foo();");
|
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): int { destroy x; return 1; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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 with name \"x\" not defined.", e.getMessage());
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ public class FieldAssignmentTest {
|
|||||||
ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { str.a = 1; return 1; } foo();");
|
ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { str.a = 1; return 1; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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 with name str not defined.", e.getMessage());
|
||||||
@@ -24,7 +25,8 @@ public class FieldAssignmentTest {
|
|||||||
ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { let x: int = 0; x.a = 0; return 1; } foo();");
|
ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { let x: int = 0; x.a = 0; return 1; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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 must reference a struct but references int.", e.getMessage());
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ public class FunctionCallTest {
|
|||||||
ParseTree tree = Helper.prepareParser("function foo(): int { return 1; } bar();");
|
ParseTree tree = Helper.prepareParser("function foo(): int { return 1; } bar();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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:34 Function with name \"bar\" not defined.", e.getMessage());
|
assertEquals("Error in line 1:34 Function with name \"bar\" not defined.", e.getMessage());
|
||||||
@@ -24,7 +25,8 @@ public class FunctionCallTest {
|
|||||||
ParseTree tree = Helper.prepareParser("function foo(): int { return 1; } foo(5);");
|
ParseTree tree = Helper.prepareParser("function foo(): int { return 1; } foo(5);");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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:34 Function \"foo\" expects 0 parameters, but got 1.", e.getMessage());
|
assertEquals("Error in line 1:34 Function \"foo\" expects 0 parameters, but got 1.", e.getMessage());
|
||||||
@@ -35,7 +37,8 @@ public class FunctionCallTest {
|
|||||||
ParseTree tree = Helper.prepareParser("function foo(x: int): int { return x; } foo(false);");
|
ParseTree tree = Helper.prepareParser("function foo(x: int): int { return x; } foo(false);");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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:40 argument 0 Expected int but got: bool", e.getMessage());
|
assertEquals("Error in line 1:40 argument 0 Expected int but got: bool", e.getMessage());
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ public class FunctionDefinitionTest {
|
|||||||
ParseTree tree = Helper.prepareParser("function foo(): schwurbel { return 1; } foo();");
|
ParseTree tree = Helper.prepareParser("function foo(): schwurbel { return 1; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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:0 Type schwurbel not defined.", e.getMessage());
|
assertEquals("Error in line 1:0 Type schwurbel not defined.", e.getMessage());
|
||||||
@@ -24,7 +25,8 @@ public class FunctionDefinitionTest {
|
|||||||
ParseTree tree = Helper.prepareParser("function foo(): int { let x: int; x = 0; } foo();");
|
ParseTree tree = Helper.prepareParser("function foo(): int { let x: int; x = 0; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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:0 Function foo has to return something of type int.", e.getMessage());
|
assertEquals("Error in line 1:0 Function foo has to return something of type int.", e.getMessage());
|
||||||
|
|||||||
@@ -18,19 +18,19 @@ public class Helper {
|
|||||||
|
|
||||||
public static Map<String, FunctionInformation> getFuncs(ParseTree tree) {
|
public static Map<String, FunctionInformation> getFuncs(ParseTree tree) {
|
||||||
var functionDefinitions = new HashMap<String, FunctionInformation>();
|
var functionDefinitions = new HashMap<String, FunctionInformation>();
|
||||||
new GetFunctions(functionDefinitions).visit(tree);
|
new GetDefinitions(functionDefinitions, new HashMap<>(), new HashMap<>()).visit(tree);
|
||||||
return functionDefinitions;
|
return functionDefinitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<String> getStructNames(ParseTree tree) {
|
|
||||||
var structNames = new HashSet<String>();
|
|
||||||
new GetStructNames(structNames).visit(tree);
|
|
||||||
return structNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<String, StructDefinition> getStructs(ParseTree tree) {
|
public static Map<String, StructDefinition> getStructs(ParseTree tree) {
|
||||||
var structs = new HashMap<String, StructDefinition>();
|
var structs = new HashMap<String, StructDefinition>();
|
||||||
new GetStructs(getStructNames(tree), structs).visit(tree);
|
new GetDefinitions(new HashMap<>(), structs, new HashMap<>()).visit(tree);
|
||||||
return structs;
|
return structs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Map<String, EnumDefinition> getEnums(ParseTree tree) {
|
||||||
|
var enums = new HashMap<String, EnumDefinition>();
|
||||||
|
new GetDefinitions(new HashMap<>(), new HashMap<>(), enums).visit(tree);
|
||||||
|
return enums;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,8 @@ public class ModuloTest {
|
|||||||
ParseTree tree = Helper.prepareParser("function foo(): float { return 1.0 % 2.3; } foo();");
|
ParseTree tree = Helper.prepareParser("function foo(): float { return 1.0 % 2.3; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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:31 Only integers are allowed for modulo.", e.getMessage());
|
assertEquals("Error in line 1:31 Only integers are allowed for modulo.", e.getMessage());
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ public class OrTest {
|
|||||||
ParseTree tree = Helper.prepareParser("function foo(): bool { return 1 || 2; } foo();");
|
ParseTree tree = Helper.prepareParser("function foo(): bool { return 1 || 2; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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:30 || is only defined for bool.", e.getMessage());
|
assertEquals("Error in line 1:30 || is only defined for bool.", e.getMessage());
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ public class StructFieldAccessTest {
|
|||||||
ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { return str.a; } foo();");
|
ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { return str.a; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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 with name str not defined.", e.getMessage());
|
||||||
@@ -23,7 +24,8 @@ public class StructFieldAccessTest {
|
|||||||
ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { let x: int = 0; return x.a; } foo();");
|
ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { let x: int = 0; return x.a; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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 must reference a struct but references int.", e.getMessage());
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ public class VariableAssignmentTest {
|
|||||||
ParseTree tree = Helper.prepareParser("function foo(): int { x = 1; return 1; } foo();");
|
ParseTree tree = Helper.prepareParser("function foo(): int { x = 1; return 1; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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 with name \"x\" not defined.", e.getMessage());
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ public class VariableDeclarationTest {
|
|||||||
ParseTree tree = Helper.prepareParser("function foo(): int { let X: unk; return 1; } foo();");
|
ParseTree tree = Helper.prepareParser("function foo(): int { let X: unk; return 1; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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 Type unk not defined.", e.getMessage());
|
assertEquals("Error in line 1:22 Type unk not defined.", e.getMessage());
|
||||||
@@ -24,7 +25,8 @@ public class VariableDeclarationTest {
|
|||||||
ParseTree tree = Helper.prepareParser("function foo(): int { let x: int; let x: bool; return 1; } foo();");
|
ParseTree tree = Helper.prepareParser("function foo(): int { let x: int; let x: bool; return 1; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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:34 Redeclaration of variable with name \"x\".", e.getMessage());
|
assertEquals("Error in line 1:34 Redeclaration of variable with name \"x\".", e.getMessage());
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ public class VariableTest {
|
|||||||
ParseTree tree = Helper.prepareParser("function foo(): int { return x; } foo();");
|
ParseTree tree = Helper.prepareParser("function foo(): int { return x; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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 with name \"x\" not defined.", e.getMessage());
|
||||||
@@ -24,7 +25,8 @@ public class VariableTest {
|
|||||||
ParseTree tree = Helper.prepareParser("function foo(): int { let x: int; return x; } foo();");
|
ParseTree tree = Helper.prepareParser("function foo(): int { let x: int; return x; } foo();");
|
||||||
var funcs = Helper.getFuncs(tree);
|
var funcs = Helper.getFuncs(tree);
|
||||||
var structs = Helper.getStructs(tree);
|
var structs = Helper.getStructs(tree);
|
||||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
var enums = Helper.getEnums(tree);
|
||||||
|
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:41 Variable with name \"x\" has not been initialized.", e.getMessage());
|
assertEquals("Error in line 1:41 Variable with name \"x\" has not been initialized.", e.getMessage());
|
||||||
|
|||||||
Reference in New Issue
Block a user