Compare commits
28 Commits
af1021ed66
...
abgabe_com
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd173b1d45 | ||
| 221b928d0e | |||
|
|
8dd0b6cffa | ||
|
|
f288d5585f | ||
|
|
e05ca07d23 | ||
| fd17a25f29 | |||
|
|
500cfaffbe | ||
| 5a5191612e | |||
|
|
36a38ee7ab | ||
|
|
c38a330fda | ||
| ac870460e6 | |||
| da56e1c05e | |||
| ba17c7e2b6 | |||
| d6c0131d8f | |||
| d90581f0cd | |||
| 6714d2136d | |||
| fe9c9b79b8 | |||
| 89ec828499 | |||
| 9df0da89ff | |||
| 649e690ac4 | |||
| 6d60dcc4a3 | |||
| 35de3c7de4 | |||
| 5701d3e918 | |||
| 704e6441ca | |||
| cb5ceafbbc | |||
| d96b083c41 | |||
| acaa37b3b1 | |||
| d1cf626934 |
@@ -9,7 +9,18 @@ build:
|
||||
script:
|
||||
- mvn package
|
||||
|
||||
test:
|
||||
test_parsing:
|
||||
image: ubuntu:rolling
|
||||
stage: test
|
||||
tags:
|
||||
- docker
|
||||
before_script:
|
||||
- apt update
|
||||
- apt install -y build-essential openjdk-13-jre-headless maven
|
||||
script:
|
||||
- make testJava
|
||||
|
||||
test_compilation:
|
||||
image: ubuntu:rolling
|
||||
stage: test
|
||||
tags:
|
||||
|
||||
1
.mvn/jvm.config
Normal file
1
.mvn/jvm.config
Normal file
@@ -0,0 +1 @@
|
||||
--add-opens java.base/java.lang=ALL-UNNAMED
|
||||
@@ -1,4 +1,5 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//src/main/java=UTF-8
|
||||
encoding//src/test/java=UTF-8
|
||||
encoding//target/generated-sources/antlr4=UTF-8
|
||||
encoding/<project>=UTF-8
|
||||
|
||||
98
README.md
98
README.md
@@ -5,11 +5,10 @@ This is the project for Klang - the Kaiser language.
|
||||
This code was in equal parts developed by `Dennis Kaiser` and `Marvin Kaiser` at the RheinMain University of Applied Sciences for the Compilers course.
|
||||
|
||||
# Usage
|
||||
Pass source code via stdin
|
||||
|
||||
example call to print help `java -cp target/klang-1.0-jar-with-dependencies.jar de.hsrm.compiler.Klang.Klang -h`
|
||||
|
||||
example call: `java -cp <jar> <cp> -out <input> <output>`
|
||||
Arguments:
|
||||
- -out <file> File to write to
|
||||
- -h Print this help
|
||||
- --evaluate: Evaluates the given source code
|
||||
- --pretty: Pretty print the given source code
|
||||
@@ -23,8 +22,47 @@ The makefile can be used to perform various functions more easily:
|
||||
- `make pretty` prettifies code.k and writes to pretty.k
|
||||
- `make eval` evaluates code.k
|
||||
- `make test` runs tests from src/test/
|
||||
- `make testJava` runs JUnit tests
|
||||
- `make cleanTests` cleans files generated from tests
|
||||
|
||||
# Boilerplate Example
|
||||
A simple program in the KLang Language consits of some struct definitions and some function definition and a single expression that is used as the start for the compilation
|
||||
```
|
||||
struct node {
|
||||
value: int;
|
||||
tail: node;
|
||||
}
|
||||
|
||||
function makeList(anz: int): node {
|
||||
if (anz == 0) {
|
||||
return naught;
|
||||
}
|
||||
return create node(anz - 1, makeList(anz - 1));
|
||||
}
|
||||
|
||||
function get(ll: node, index: int): int {
|
||||
if (index == 0 || ll == naught) {
|
||||
return ll.value;
|
||||
} else {
|
||||
return get(ll.tail, index - 1);
|
||||
}
|
||||
}
|
||||
|
||||
function sum(list: node, length: int): int {
|
||||
if (length == 0) {
|
||||
return list.value;
|
||||
}
|
||||
return list.value + sum(list.tail, length -1);
|
||||
}
|
||||
|
||||
function init(pos: int): int {
|
||||
let n: node = makeList(5);
|
||||
return sum(n, pos);
|
||||
}
|
||||
|
||||
init(0);
|
||||
```
|
||||
|
||||
# Functionality
|
||||
The KLang compiler supports generation of AMD64 assembly code, as well as prettifying and evaluating the KLang code.
|
||||
|
||||
@@ -44,13 +82,13 @@ The following simple expressions are supported. Expressions need to be put in pa
|
||||
|
||||
### Examples:
|
||||
```
|
||||
(5 + 4)
|
||||
(8 % 2)
|
||||
(8 == 0)
|
||||
5 + 4
|
||||
8 % 2
|
||||
8 == 0
|
||||
```
|
||||
|
||||
## Functions
|
||||
Functions can be defined and called. A function call can be used like any other expression. Recursion is supported
|
||||
Functions can be defined and called. A function call can be used like any other expression. Recursion is supported aswell as linking agaings c object files since we are following the calling convention
|
||||
|
||||
### Examples
|
||||
```
|
||||
@@ -61,6 +99,46 @@ function fun(x: int, y: int, z: bool): int {
|
||||
fun(1, 2, 3);
|
||||
```
|
||||
|
||||
## Structs
|
||||
Structs can be defined, created and destroyed. Structs can reference other structs as well as themselves. You can reference structs that are defined later in the code. Our structs are compatible to c structs. When defining a struct, a constructor function is implicitly defined so that you can create instances of your struct. To denote a non existing reference to a struct, use the reserved word "naught";
|
||||
|
||||
### Examples
|
||||
```
|
||||
struct myStruct {
|
||||
a: int;
|
||||
b: bool;
|
||||
c: float;
|
||||
d: myStruct;
|
||||
}
|
||||
|
||||
function add(x: myStruct, y: myStruct): float {
|
||||
return x.c + y.c;
|
||||
}
|
||||
|
||||
function isOk(x: myStruct, y: myStruct): bool {
|
||||
return x.b && y.b;
|
||||
}
|
||||
|
||||
function getReferenced(x: myStruct): myStruct {
|
||||
return x.d;
|
||||
}
|
||||
|
||||
function start(): int {
|
||||
let x: myStruct = create myStruct(1, false, 42.0, naught);
|
||||
let y: myStruct = create myStruct(12, true, 13.37, x);
|
||||
let z: int = add(x, y);
|
||||
let a: bool = isOk(x, y);
|
||||
let y2: myStruct = getReferenced(x);
|
||||
let isSame: bool = y == y2;
|
||||
destroy y;
|
||||
destroy x;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
start();
|
||||
```
|
||||
|
||||
## Statements
|
||||
Several statements are supported:
|
||||
- if
|
||||
@@ -112,6 +190,9 @@ function forExample(end: int): int {
|
||||
|
||||
```
|
||||
|
||||
## Tail Call Optimized
|
||||
Recursive tail calls are optimized at compile time.
|
||||
|
||||
## Statically typed
|
||||
KLang statically verifies the integrity of your code. These checks include:
|
||||
- Type checking
|
||||
@@ -120,9 +201,10 @@ KLang statically verifies the integrity of your code. These checks include:
|
||||
- Ensuring that a function returns something
|
||||
- Ensuring that a function only returns data of the correct type
|
||||
|
||||
### Data Types
|
||||
### Primitive Data Types
|
||||
- Integer "int"
|
||||
- Boolean "bool"
|
||||
- Floats "float"
|
||||
|
||||
### Examples
|
||||
You can declare types for parameters, return values and variables
|
||||
|
||||
5
makefile
5
makefile
@@ -13,10 +13,13 @@ eval: code.k target/klang-1.0-jar-with-dependencies.jar
|
||||
build: clean target/klang-1.0-jar-with-dependencies.jar
|
||||
|
||||
target/klang-1.0-jar-with-dependencies.jar:
|
||||
mvn package
|
||||
mvn -Dmaven.test.skip=true package
|
||||
|
||||
test: ./src/test/test
|
||||
./src/test/test
|
||||
|
||||
testJava:
|
||||
mvn test
|
||||
|
||||
./src/test/test: ./src/test/test.s
|
||||
gcc -o ./src/test/test ./src/test/test.s ./src/test/**/*.c ./src/test/test.c
|
||||
|
||||
21
pom.xml
21
pom.xml
@@ -1,5 +1,4 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>de.hsrm.compiler</groupId>
|
||||
@@ -21,6 +20,16 @@
|
||||
<artifactId>antlr4-runtime</artifactId>
|
||||
<version>4.7.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.6.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.6.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@@ -74,6 +83,14 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -18,6 +18,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
||||
Map<String, FunctionInformation> funcs;
|
||||
Map<String, StructDefinition> structs;
|
||||
Type currentDeclaredReturnType;
|
||||
String currentFunctionDefinitionName;
|
||||
|
||||
private void checkNumeric(Node lhs, Node rhs, int line, int col) {
|
||||
if (!lhs.type.isNumericType() || !rhs.type.isNumericType()) {
|
||||
@@ -149,8 +150,8 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
||||
|
||||
@Override
|
||||
public Node visitDoWhileLoop(KlangParser.DoWhileLoopContext ctx) {
|
||||
Node condition = this.visit(ctx.cond);
|
||||
Node block = this.visit(ctx.braced_block());
|
||||
Node condition = this.visit(ctx.cond);
|
||||
Node result = new DoWhileLoop((Expression) condition, (Block) block);
|
||||
result.line = ctx.start.getLine();
|
||||
result.col = ctx.start.getCharPositionInLine();
|
||||
@@ -246,6 +247,16 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
||||
public Node visitReturn_statement(KlangParser.Return_statementContext ctx) {
|
||||
Expression expression = (Expression) this.visit(ctx.expression());
|
||||
ReturnStatement result = new ReturnStatement(expression);
|
||||
|
||||
// Check if this expression is a tail recursion
|
||||
if (expression instanceof FunctionCall) {
|
||||
var funCall = (FunctionCall) expression;
|
||||
if (funCall.name.equals(this.currentFunctionDefinitionName)) {
|
||||
// Flag this function call
|
||||
funCall.isTailRecursive = true;
|
||||
}
|
||||
}
|
||||
|
||||
result.type = expression.type;
|
||||
result.line = ctx.start.getLine();
|
||||
result.col = ctx.start.getCharPositionInLine();
|
||||
@@ -720,6 +731,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
||||
int col = ctx.start.getCharPositionInLine();
|
||||
Type returnType = Type.getByName(ctx.returnType.type().getText());
|
||||
this.currentDeclaredReturnType = returnType;
|
||||
this.currentFunctionDefinitionName = name;
|
||||
|
||||
if (!returnType.isPrimitiveType() && this.structs.get(returnType.getName()) == null) {
|
||||
String error = "Type " + returnType.getName() + " not defined.";
|
||||
|
||||
@@ -46,7 +46,7 @@ public class Klang {
|
||||
System.out.println("Last argument must be file");
|
||||
System.out.println("");
|
||||
System.out.println("Arguments:");
|
||||
System.out.println("--out <file>:\t File to write to");
|
||||
System.out.println("--o <file>:\t File to write to");
|
||||
System.out.println("--evaluate:\t Evaluates the given source code");
|
||||
System.out.println("--pretty:\t Pretty print the given source code");
|
||||
System.out
|
||||
@@ -115,7 +115,8 @@ public class Klang {
|
||||
PrettyPrintVisitor.ExWriter ex = new PrettyPrintVisitor.ExWriter(w);
|
||||
PrettyPrintVisitor printVisitor = new PrettyPrintVisitor(ex);
|
||||
root.welcome(printVisitor);
|
||||
System.out.println(w.toString());
|
||||
generateOutput(out, w.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (evaluate) {
|
||||
|
||||
@@ -6,6 +6,7 @@ public class FunctionCall extends Expression {
|
||||
|
||||
public String name;
|
||||
public Expression[] arguments;
|
||||
public boolean isTailRecursive = false;
|
||||
|
||||
public FunctionCall(String name, Expression[] arguments) {
|
||||
this.name = name;
|
||||
|
||||
@@ -113,6 +113,8 @@ public class GenASM implements Visitor<Void> {
|
||||
String[] registers = { "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9" };
|
||||
String[] floatRegisters = { "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
|
||||
private int lCount = 0; // Invariante: lCount ist benutzt
|
||||
private int currentFunctionStartLabel = 0;
|
||||
private Parameter[] currentFunctionParams;
|
||||
|
||||
private void intToFloat(String src, String dst) {
|
||||
this.ex.write(" cvtsi2sd " + src + ", " + dst + "\n");
|
||||
@@ -566,6 +568,11 @@ public class GenASM implements Visitor<Void> {
|
||||
if (e.expression != null) {
|
||||
e.expression.welcome(this);
|
||||
int offset = this.env.get(e.name);
|
||||
|
||||
if (e.expression.type.equals(Type.getFloatType())) {
|
||||
this.ex.write(" movq %xmm0, %rax\n");
|
||||
}
|
||||
|
||||
this.ex.write(" movq %rax, " + offset + "(%rbp)\n");
|
||||
}
|
||||
return null;
|
||||
@@ -606,11 +613,15 @@ public class GenASM implements Visitor<Void> {
|
||||
|
||||
@Override
|
||||
public Void visit(FunctionDefinition e) {
|
||||
int lblStart = ++lCount;
|
||||
this.currentFunctionStartLabel = lblStart;
|
||||
this.currentFunctionParams = e.parameters;
|
||||
this.ex.write(".globl " + e.name + "\n");
|
||||
this.ex.write(".type " + e.name + ", @function\n");
|
||||
this.ex.write(e.name + ":\n");
|
||||
this.ex.write(" pushq %rbp\n");
|
||||
this.ex.write(" movq %rsp, %rbp\n");
|
||||
this.ex.write(".L" + lblStart + ":\n");
|
||||
|
||||
// hole die anzahl der lokalen variablen
|
||||
this.vars = new TreeSet<String>();
|
||||
@@ -682,6 +693,29 @@ public class GenASM implements Visitor<Void> {
|
||||
|
||||
@Override
|
||||
public Void visit(FunctionCall e) {
|
||||
if (e.isTailRecursive) {
|
||||
|
||||
// Visit the arguments and move them into the stack
|
||||
for(int i = 0; i < e.arguments.length; i++) {
|
||||
e.arguments[i].welcome(this);
|
||||
|
||||
if (e.arguments[i].type.equals(Type.getFloatType())) {
|
||||
this.ex.write(" movq %xmm0, %rax\n");
|
||||
}
|
||||
|
||||
this.ex.write(" pushq %rax\n");
|
||||
}
|
||||
|
||||
// push args into local var locations, last arg is ontop of the stack
|
||||
for (int i = e.arguments.length - 1; i >= 0; i--) {
|
||||
this.ex.write(" popq " + this.env.get(this.currentFunctionParams[i].name) + "(%rbp)\n");
|
||||
}
|
||||
|
||||
this.ex.write(" jmp .L" + this.currentFunctionStartLabel + "\n");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if (e.arguments.length > 0) {
|
||||
// Mapping arguments index -> xmm registers index
|
||||
int[] xmmIdxs = new int[this.floatRegisters.length];
|
||||
|
||||
@@ -92,4 +92,28 @@ int runFunctionCallTests () {
|
||||
argumentTest("fgetMix8(...args)", 8, fgetMix8());
|
||||
argumentTest_f("fgetMix9(...args)", 9.0, fgetMix9());
|
||||
argumentTest("fgetMix10(...args)", 10, fgetMix10());
|
||||
|
||||
printf("\nTail Call Tests \n");
|
||||
// Checks that tails calls are properly invoked
|
||||
argumentTest("arg1Tail(...args)", 1, arg1Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10));
|
||||
argumentTest("arg2Tail(...args)", 2, arg2Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10));
|
||||
argumentTest("arg3Tail(...args)", 3, arg3Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10));
|
||||
argumentTest("arg4Tail(...args)", 4, arg4Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10));
|
||||
argumentTest("arg5Tail(...args)", 5, arg5Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10));
|
||||
argumentTest("arg6Tail(...args)", 6, arg6Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10));
|
||||
argumentTest("arg7Tail(...args)", 7, arg7Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10));
|
||||
argumentTest("arg8Tail(...args)", 8, arg8Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10));
|
||||
argumentTest("arg9Tail(...args)", 9, arg9Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10));
|
||||
argumentTest("arg10Tail(...args)", 10, arg10Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10));
|
||||
// Checks that parameters are correctly passed from klang to functions
|
||||
argumentTest("get1Tail(...args)", 1, get1Tail(10));
|
||||
argumentTest("get2Tail(...args)", 2, get2Tail(10));
|
||||
argumentTest("get3Tail(...args)", 3, get3Tail(10));
|
||||
argumentTest("get4Tail(...args)", 4, get4Tail(10));
|
||||
argumentTest("get5Tail(...args)", 5, get5Tail(10));
|
||||
argumentTest("get6Tail(...args)", 6, get6Tail(10));
|
||||
argumentTest("get7Tail(...args)", 7, get7Tail(10));
|
||||
argumentTest("get8Tail(...args)", 8, get8Tail(10));
|
||||
argumentTest("get9Tail(...args)", 9, get9Tail(10));
|
||||
argumentTest("get10Tail(...args)", 10, get10Tail(10));
|
||||
}
|
||||
@@ -20,6 +20,28 @@ long get8();
|
||||
long get9();
|
||||
long get10();
|
||||
|
||||
long arg1Tail(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j, long count);
|
||||
long arg2Tail(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j, long count);
|
||||
long arg3Tail(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j, long count);
|
||||
long arg4Tail(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j, long count);
|
||||
long arg5Tail(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j, long count);
|
||||
long arg6Tail(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j, long count);
|
||||
long arg7Tail(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j, long count);
|
||||
long arg8Tail(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j, long count);
|
||||
long arg9Tail(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j, long count);
|
||||
long arg10Tail(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j, long count);
|
||||
|
||||
long get1Tail(long count);
|
||||
long get2Tail(long count);
|
||||
long get3Tail(long count);
|
||||
long get4Tail(long count);
|
||||
long get5Tail(long count);
|
||||
long get6Tail(long count);
|
||||
long get7Tail(long count);
|
||||
long get8Tail(long count);
|
||||
long get9Tail(long count);
|
||||
long get10Tail(long count);
|
||||
|
||||
double farg1(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j);
|
||||
double farg2(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j);
|
||||
double farg3(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j);
|
||||
|
||||
20
src/test/java/AndTest.java
Normal file
20
src/test/java/AndTest.java
Normal file
@@ -0,0 +1,20 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
|
||||
public class AndTest {
|
||||
@Test
|
||||
void onlyForBool() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): bool { return 1 && 2; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:30 && is only defined for bool.", e.getMessage());
|
||||
}
|
||||
}
|
||||
43
src/test/java/ConstructorCallTest.java
Normal file
43
src/test/java/ConstructorCallTest.java
Normal file
@@ -0,0 +1,43 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
|
||||
public class ConstructorCallTest {
|
||||
|
||||
@Test
|
||||
void structNotDefined() {
|
||||
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): bar { return create schwurbel(1); } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:52 Struct with name \"schwurbel\" not defined.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void numConstructorParameterMissmatch() {
|
||||
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): bar { return create bar(1, false); } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructorParameterTypeMismatch() {
|
||||
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): bar { return create bar(false); } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
21
src/test/java/DestroyStatementTest.java
Normal file
21
src/test/java/DestroyStatementTest.java
Normal file
@@ -0,0 +1,21 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
|
||||
|
||||
public class DestroyStatementTest {
|
||||
@Test
|
||||
void variableNotDefined() {
|
||||
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): int { destroy x; return 1; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:45 Variable with name \"x\" not defined.", e.getMessage());
|
||||
}
|
||||
}
|
||||
32
src/test/java/FieldAssignmentTest.java
Normal file
32
src/test/java/FieldAssignmentTest.java
Normal file
@@ -0,0 +1,32 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
|
||||
public class FieldAssignmentTest {
|
||||
|
||||
@Test
|
||||
void variableNotDefined() {
|
||||
ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { str.a = 1; return 1; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:46 Variable with name str not defined.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void fieldAssignmentOnNonStruct() {
|
||||
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 structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:62 Variable must reference a struct but references int.", e.getMessage());
|
||||
}
|
||||
}
|
||||
43
src/test/java/FunctionCallTest.java
Normal file
43
src/test/java/FunctionCallTest.java
Normal file
@@ -0,0 +1,43 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
|
||||
public class FunctionCallTest {
|
||||
|
||||
@Test
|
||||
void funcNotDefined() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): int { return 1; } bar();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:34 Function with name \"bar\" not defined.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void numParameterMismatch() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): int { return 1; } foo(5);");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:34 Function \"foo\" expects 0 parameters, but got 1.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void parameterTypeMissmatch() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(x: int): int { return x; } foo(false);");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:40 argument 0 Expected int but got: bool", e.getMessage());
|
||||
}
|
||||
}
|
||||
32
src/test/java/FunctionDefinitionTest.java
Normal file
32
src/test/java/FunctionDefinitionTest.java
Normal file
@@ -0,0 +1,32 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
|
||||
public class FunctionDefinitionTest {
|
||||
|
||||
@Test
|
||||
void typeNotDefined() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): schwurbel { return 1; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:0 Type schwurbel not defined.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void noReturnExpression() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): int { let x: int; x = 0; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
36
src/test/java/Helper.java
Normal file
36
src/test/java/Helper.java
Normal file
@@ -0,0 +1,36 @@
|
||||
import java.util.*;
|
||||
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.tree.*;
|
||||
|
||||
import de.hsrm.compiler.Klang.*;
|
||||
import de.hsrm.compiler.Klang.helper.*;
|
||||
import de.hsrm.compiler.Klang.nodes.*;
|
||||
|
||||
public class Helper {
|
||||
public static ParseTree prepareParser(String input) {
|
||||
CharStream inStream = CharStreams.fromString(input);
|
||||
KlangLexer lexer = new KlangLexer(inStream);
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
KlangParser parser = new KlangParser(tokens);
|
||||
return parser.parse();
|
||||
}
|
||||
|
||||
public static Map<String, FunctionInformation> getFuncs(ParseTree tree) {
|
||||
var functionDefinitions = new HashMap<String, FunctionInformation>();
|
||||
new GetFunctions(functionDefinitions).visit(tree);
|
||||
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) {
|
||||
var structs = new HashMap<String, StructDefinition>();
|
||||
new GetStructs(getStructNames(tree), structs).visit(tree);
|
||||
return structs;
|
||||
}
|
||||
}
|
||||
20
src/test/java/ModuloTest.java
Normal file
20
src/test/java/ModuloTest.java
Normal file
@@ -0,0 +1,20 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
|
||||
public class ModuloTest {
|
||||
@Test
|
||||
void onlyForInt() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): float { return 1.0 % 2.3; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:31 Only integers are allowed for modulo.", e.getMessage());
|
||||
}
|
||||
}
|
||||
21
src/test/java/OrTest.java
Normal file
21
src/test/java/OrTest.java
Normal file
@@ -0,0 +1,21 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
|
||||
public class OrTest {
|
||||
|
||||
@Test
|
||||
void onlyForBool() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): bool { return 1 || 2; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:30 || is only defined for bool.", e.getMessage());
|
||||
}
|
||||
}
|
||||
14
src/test/java/ParameterTest.java
Normal file
14
src/test/java/ParameterTest.java
Normal file
@@ -0,0 +1,14 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ParameterTest {
|
||||
@Test
|
||||
void typeNotDefined() {
|
||||
ParseTree tree = Helper.prepareParser("struct test { a: schwurbel; } function foo(): int { return 1; } foo();");
|
||||
Exception e = assertThrows(RuntimeException.class, () -> Helper.getStructs(tree));
|
||||
assertEquals("Error in line 1:14 Type schwurbel not defined.", e.getMessage());
|
||||
}
|
||||
}
|
||||
31
src/test/java/StructFieldAccessTest.java
Normal file
31
src/test/java/StructFieldAccessTest.java
Normal file
@@ -0,0 +1,31 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
|
||||
public class StructFieldAccessTest {
|
||||
@Test
|
||||
void variableNotDefined() {
|
||||
ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { return str.a; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:53 Variable with name str not defined.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void fieldAssignmentOnNonStruct() {
|
||||
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 structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:69 Variable must reference a struct but references int.", e.getMessage());
|
||||
}
|
||||
}
|
||||
21
src/test/java/VariableAssignmentTest.java
Normal file
21
src/test/java/VariableAssignmentTest.java
Normal file
@@ -0,0 +1,21 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
|
||||
public class VariableAssignmentTest {
|
||||
|
||||
@Test
|
||||
void variableNotDefined() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): int { x = 1; return 1; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:22 Variable with name \"x\" not defined.", e.getMessage());
|
||||
}
|
||||
}
|
||||
32
src/test/java/VariableDeclarationTest.java
Normal file
32
src/test/java/VariableDeclarationTest.java
Normal file
@@ -0,0 +1,32 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
|
||||
public class VariableDeclarationTest {
|
||||
@Test
|
||||
void typeNotDefined() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): int { let X: unk; return 1; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:22 Type unk not defined.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void variableRedeclaration()
|
||||
{
|
||||
ParseTree tree = Helper.prepareParser("function foo(): int { let x: int; let x: bool; return 1; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:34 Redeclaration of variable with name \"x\".", e.getMessage());
|
||||
}
|
||||
}
|
||||
32
src/test/java/VariableTest.java
Normal file
32
src/test/java/VariableTest.java
Normal file
@@ -0,0 +1,32 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
|
||||
public class VariableTest {
|
||||
|
||||
@Test
|
||||
void variableNotDefined() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): int { return x; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:29 Variable with name \"x\" not defined.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void variableNotInitialized() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): int { let x: int; return x; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:41 Variable with name \"x\" has not been initialized.", e.getMessage());
|
||||
}
|
||||
}
|
||||
121
src/test/test.k
121
src/test/test.k
@@ -106,6 +106,127 @@ function get10(): int {
|
||||
return arg10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||
}
|
||||
|
||||
// TAIL CALL
|
||||
function arg1Tail(a: int, b: int, c: int,d: int,e: int,f: int,g: int, h: int,i: int,j: int, count: int): int {
|
||||
if (count <= 0) {
|
||||
return a;
|
||||
}
|
||||
|
||||
return arg1Tail(a, b, c, d, e, f, g, h, i, j, count - 1);
|
||||
}
|
||||
|
||||
function get1Tail(count: int): int {
|
||||
return arg1Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10);
|
||||
}
|
||||
|
||||
function arg2Tail(a: int, b: int, c: int,d: int,e: int,f: int,g: int, h: int,i: int,j: int, count: int): int {
|
||||
if (count <= 0) {
|
||||
return b;
|
||||
}
|
||||
|
||||
return arg2Tail(a, b, c, d, e, f, g, h, i, j, count - 1);
|
||||
}
|
||||
|
||||
function get2Tail(count: int): int {
|
||||
return arg2Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10);
|
||||
}
|
||||
|
||||
function arg3Tail(a: int, b: int, c: int,d: int,e: int,f: int,g: int, h: int,i: int,j: int, count: int): int {
|
||||
if (count <= 0) {
|
||||
return c;
|
||||
}
|
||||
|
||||
return arg3Tail(a, b, c, d, e, f, g, h, i, j, count - 1);
|
||||
}
|
||||
|
||||
function get3Tail(count: int): int {
|
||||
return arg3Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10);
|
||||
}
|
||||
|
||||
function arg4Tail(a: int, b: int, c: int,d: int,e: int,f: int,g: int, h: int,i: int,j: int, count: int): int {
|
||||
if (count <= 0) {
|
||||
return d;
|
||||
}
|
||||
|
||||
return arg4Tail(a, b, c, d, e, f, g, h, i, j, count - 1);
|
||||
}
|
||||
|
||||
function get4Tail(count: int): int {
|
||||
return arg4Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10);
|
||||
}
|
||||
|
||||
function arg5Tail(a: int, b: int, c: int,d: int,e: int,f: int,g: int, h: int,i: int,j: int, count: int): int {
|
||||
if (count <= 0) {
|
||||
return e;
|
||||
}
|
||||
|
||||
return arg5Tail(a, b, c, d, e, f, g, h, i, j, count - 1);
|
||||
}
|
||||
|
||||
function get5Tail(count: int): int {
|
||||
return arg5Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10);
|
||||
}
|
||||
|
||||
function arg6Tail(a: int, b: int, c: int,d: int,e: int,f: int,g: int, h: int,i: int,j: int, count: int): int {
|
||||
if (count <= 0) {
|
||||
return f;
|
||||
}
|
||||
|
||||
return arg6Tail(a, b, c, d, e, f, g, h, i, j, count - 1);
|
||||
}
|
||||
|
||||
function get6Tail(count: int): int {
|
||||
return arg6Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10);
|
||||
}
|
||||
|
||||
function arg7Tail(a: int, b: int, c: int,d: int,e: int,f: int,g: int, h: int,i: int,j: int, count: int): int {
|
||||
if (count <= 0) {
|
||||
return g;
|
||||
}
|
||||
|
||||
return arg7Tail(a, b, c, d, e, f, g, h, i, j, count - 1);
|
||||
}
|
||||
|
||||
function get7Tail(count: int): int {
|
||||
return arg7Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10);
|
||||
}
|
||||
|
||||
function arg8Tail(a: int, b: int, c: int,d: int,e: int,f: int,g: int, h: int,i: int,j: int, count: int): int {
|
||||
if (count <= 0) {
|
||||
return h;
|
||||
}
|
||||
|
||||
return arg8Tail(a, b, c, d, e, f, g, h, i, j, count - 1);
|
||||
}
|
||||
|
||||
function get8Tail(count: int): int {
|
||||
return arg8Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10);
|
||||
}
|
||||
|
||||
function arg9Tail(a: int, b: int, c: int,d: int,e: int,f: int,g: int, h: int,i: int,j: int, count: int): int {
|
||||
if (count <= 0) {
|
||||
return i;
|
||||
}
|
||||
|
||||
return arg9Tail(a, b, c, d, e, f, g, h, i, j, count - 1);
|
||||
}
|
||||
|
||||
function get9Tail(count: int): int {
|
||||
return arg9Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10);
|
||||
}
|
||||
|
||||
function arg10Tail(a: int, b: int, c: int, d: int, e: int, f: int, g: int, h: int, i: int, j: int, count: int): int {
|
||||
if (count <= 0) {
|
||||
return j;
|
||||
}
|
||||
|
||||
return arg10Tail(a, b, c, d, e, f, g, h, i, j, count - 1);
|
||||
}
|
||||
|
||||
function get10Tail(count: int): int {
|
||||
return arg10Tail(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10);
|
||||
}
|
||||
|
||||
// FLOATS
|
||||
|
||||
function farg1(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float {
|
||||
|
||||
Reference in New Issue
Block a user