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.
119 lines
4.0 KiB
Java
119 lines
4.0 KiB
Java
import de.hsrm.compiler.Klang.ContextAnalysis;
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
|
|
public class FunctionDefinitionTest {
|
|
|
|
@Test
|
|
void shouldNotThrowIfReturnTypeIsReferringToAnEnum() {
|
|
// given
|
|
var tree = Helper.prepareParser(" enum bar {A,B,C} function foo(a: int): bar { return bar.A; } foo(1);");
|
|
var ctxAnal = new ContextAnalysis(
|
|
Helper.getFuncs(tree),
|
|
Helper.getStructs(tree),
|
|
Helper.getEnums(tree)
|
|
);
|
|
|
|
// when / then
|
|
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
|
}
|
|
|
|
@Test
|
|
void shouldNotThrowIfParameterTypeIsReferringToAnEnum() {
|
|
// given
|
|
var tree = Helper.prepareParser(" enum bar {A,B,C} function foo(a: bar): int { return 1; } foo(bar.A);");
|
|
var ctxAnal = new ContextAnalysis(
|
|
Helper.getFuncs(tree),
|
|
Helper.getStructs(tree),
|
|
Helper.getEnums(tree)
|
|
);
|
|
|
|
// when / then
|
|
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
|
}
|
|
|
|
@Test
|
|
void shouldThrowExceptionIfParameterTypeIsNotDefined() {
|
|
// given
|
|
var tree = Helper.prepareParser("function foo(a: schwurbel): int { return 1; } foo();");
|
|
var ctxAnal = new ContextAnalysis(
|
|
Helper.getFuncs(tree),
|
|
Helper.getStructs(tree),
|
|
Helper.getEnums(tree)
|
|
);
|
|
|
|
// when / then
|
|
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
|
assertEquals("Error in line 1:14 Type schwurbel not defined.", e.getMessage());
|
|
}
|
|
|
|
@Test
|
|
void shouldThrowExceptionIfReturnTypeIsNotDefined() {
|
|
// given
|
|
var tree = Helper.prepareParser("function foo(): schwurbel { return 1; } foo();");
|
|
var ctxAnal = new ContextAnalysis(
|
|
Helper.getFuncs(tree),
|
|
Helper.getStructs(tree),
|
|
Helper.getEnums(tree)
|
|
);
|
|
|
|
// when / then
|
|
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
|
assertEquals("Error in line 1:14 Type schwurbel not defined.", e.getMessage());
|
|
}
|
|
|
|
@Test
|
|
void shouldThrowExceptionIfReturnStatementIsMissing() {
|
|
// given
|
|
var tree = Helper.prepareParser("function foo(): int { let x: int; x = 0; } foo();");
|
|
var ctxAnal = new ContextAnalysis(
|
|
Helper.getFuncs(tree),
|
|
Helper.getStructs(tree),
|
|
Helper.getEnums(tree)
|
|
);
|
|
|
|
// when / then
|
|
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
|
assertEquals("Error in line 1:20 Function foo has to return something of type int.", e.getMessage());
|
|
}
|
|
|
|
@Test
|
|
void shouldThrowExceptionIfParameterNameMatchesEnumName() {
|
|
// given
|
|
var tree = Helper.prepareParser("enum Bar { A, B } function foo(Bar: int): int { return 1; } foo(1);");
|
|
var ctxAnal = new ContextAnalysis(
|
|
Helper.getFuncs(tree),
|
|
Helper.getStructs(tree),
|
|
Helper.getEnums(tree)
|
|
);
|
|
|
|
// when / then
|
|
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());
|
|
}
|
|
|
|
@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));
|
|
}
|
|
} |