Compare commits
70 Commits
af1021ed66
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| bcc9f29ff5 | |||
| 259ac49981 | |||
| 2aff9b3d0d | |||
| a7e93f4f01 | |||
| 5f0e84198a | |||
| aef2c84fdc | |||
| 4219f93021 | |||
| 7965c89a60 | |||
| 26eff47057 | |||
|
|
53976615e1 | ||
| c124587983 | |||
| 07e5a338a4 | |||
| 76419d86bb | |||
| f55f2661de | |||
| 06609ae899 | |||
| c5c01041e4 | |||
| 9751a1da2f | |||
| 534b507f7a | |||
| cce58b6e38 | |||
| 8b17ced533 | |||
| bacc40d844 | |||
| f38bd3d69e | |||
| 441d0122f8 | |||
| e835bd0f06 | |||
| ea1c04ae0a | |||
| 198bd74a47 | |||
| 0594542167 | |||
| 77fe360ffa | |||
| 55a5b8f54a | |||
| 2768b4429c | |||
| 30dfbbbbba | |||
| f77d6a002d | |||
| 22634c9652 | |||
| 6fd3f5a2e6 | |||
| 3b928d621b | |||
| 9a58afb550 | |||
| 6e4431652c | |||
| 7af815042b | |||
| 7c40a50196 | |||
|
|
8529e24a37 | ||
|
|
49b024b95f | ||
|
|
982fc6417d | ||
|
|
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 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -16,4 +16,5 @@ src/main/antlr4/de/hsrm/compiler/Klang/.antlr
|
||||
|
||||
# build output
|
||||
out
|
||||
src/test/test
|
||||
src/test/test
|
||||
/.idea/uiDesigner.xml
|
||||
|
||||
@@ -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:
|
||||
|
||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
16
.idea/compiler.xml
generated
Normal file
16
.idea/compiler.xml
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile name="Maven default annotation processors profile" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<module name="klang" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
<bytecodeTargetLevel>
|
||||
<module name="klang" target="17" />
|
||||
</bytecodeTargetLevel>
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/encodings.xml
generated
Normal file
8
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/target/generated-sources/antlr4" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
20
.idea/jarRepositories.xml
generated
Normal file
20
.idea/jarRepositories.xml
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
13
.idea/libraries/Maven__org_antlr_antlr4_runtime_4_7_2.xml
generated
Normal file
13
.idea/libraries/Maven__org_antlr_antlr4_runtime_4_7_2.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.antlr:antlr4-runtime:4.7.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr4-runtime/4.7.2/antlr4-runtime-4.7.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr4-runtime/4.7.2/antlr4-runtime-4.7.2-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr4-runtime/4.7.2/antlr4-runtime-4.7.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
13
.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_0.xml
generated
Normal file
13
.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_0.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.apiguardian:apiguardian-api:1.1.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
13
.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_6_0.xml
generated
Normal file
13
.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_6_0.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.junit.jupiter:junit-jupiter-api:5.6.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/5.6.0/junit-jupiter-api-5.6.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/5.6.0/junit-jupiter-api-5.6.0-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/5.6.0/junit-jupiter-api-5.6.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
13
.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_6_0.xml
generated
Normal file
13
.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_6_0.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.junit.jupiter:junit-jupiter-engine:5.6.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-engine/5.6.0/junit-jupiter-engine-5.6.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-engine/5.6.0/junit-jupiter-engine-5.6.0-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-engine/5.6.0/junit-jupiter-engine-5.6.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
13
.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_6_0.xml
generated
Normal file
13
.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_6_0.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.junit.platform:junit-platform-commons:1.6.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-commons/1.6.0/junit-platform-commons-1.6.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-commons/1.6.0/junit-platform-commons-1.6.0-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-commons/1.6.0/junit-platform-commons-1.6.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
13
.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_6_0.xml
generated
Normal file
13
.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_6_0.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.junit.platform:junit-platform-engine:1.6.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-engine/1.6.0/junit-platform-engine-1.6.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-engine/1.6.0/junit-platform-engine-1.6.0-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-engine/1.6.0/junit-platform-engine-1.6.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
13
.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml
generated
Normal file
13
.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.opentest4j:opentest4j:1.2.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
28
.idea/misc.xml
generated
Normal file
28
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ANTLRGenerationPreferences">
|
||||
<option name="perGrammarGenerationSettings">
|
||||
<list>
|
||||
<PerGrammarGenerationSettings>
|
||||
<option name="fileName" value="$PROJECT_DIR$/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4" />
|
||||
<option name="outputDir" value="" />
|
||||
<option name="libDir" value="" />
|
||||
<option name="encoding" value="" />
|
||||
<option name="pkg" value="" />
|
||||
<option name="language" value="" />
|
||||
<option name="generateVisitor" value="true" />
|
||||
</PerGrammarGenerationSettings>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="corretto-17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/classes" />
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/klang.iml" filepath="$PROJECT_DIR$/klang.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
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
|
||||
|
||||
22
klang.iml
Normal file
22
klang.iml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_17">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/generated-sources/antlr4" isTestSource="false" generated="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Maven: org.antlr:antlr4-runtime:4.7.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.junit.jupiter:junit-jupiter-api:5.6.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apiguardian:apiguardian-api:1.1.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.opentest4j:opentest4j:1.2.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.junit.platform:junit-platform-commons:1.6.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.junit.jupiter:junit-jupiter-engine:5.6.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.junit.platform:junit-platform-engine:1.6.0" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
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
|
||||
|
||||
28
pom.xml
28
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>
|
||||
@@ -31,7 +40,7 @@
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<configuration>
|
||||
<release>11</release>
|
||||
<release>17</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- Plugin to compile the g4 files ahead of the java files
|
||||
@@ -63,6 +72,11 @@
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>de.hsrm.compiler.Klang.Klang</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
@@ -74,6 +88,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>
|
||||
@@ -5,7 +5,11 @@ parse
|
||||
;
|
||||
|
||||
program
|
||||
: (functionDef | structDef)* expression SCOL
|
||||
: (functionDef | structDef | enumDef)* expression SCOL
|
||||
;
|
||||
|
||||
enumDef
|
||||
: ENUM enumName=IDENT OBRK (IDENT (COMMA IDENT)*)+ CBRK
|
||||
;
|
||||
|
||||
structDef
|
||||
@@ -29,7 +33,7 @@ parameter
|
||||
;
|
||||
|
||||
braced_block
|
||||
: OBRK statement+ CBRK
|
||||
: OBRK (statement | functionCall SCOL)+ CBRK
|
||||
;
|
||||
|
||||
|
||||
@@ -69,7 +73,7 @@ field_assignment
|
||||
;
|
||||
|
||||
return_statement
|
||||
: RETURN expression SCOL
|
||||
: RETURN expression? SCOL
|
||||
;
|
||||
|
||||
destroy_statement
|
||||
@@ -78,7 +82,7 @@ destroy_statement
|
||||
|
||||
expression
|
||||
: atom #atomExpression
|
||||
| IDENT (PERIOD IDENT)+ #structFieldAccessExpression
|
||||
| IDENT (PERIOD IDENT)+ #memberAccessExpression
|
||||
| OPAR expression CPAR #parenthesisExpression
|
||||
| lhs=expression MUL rhs=expression #multiplicationExpression
|
||||
| lhs=expression DIV rhs=expression #divisionExpression
|
||||
@@ -103,6 +107,7 @@ atom
|
||||
: INTEGER_LITERAL #intAtom
|
||||
| BOOLEAN_LITERAL #boolAtom
|
||||
| FLOAT_LITERAL #floatAtom
|
||||
| CHAR_LITERAL #charAtom
|
||||
| NULL # nullAtom
|
||||
| IDENT #variable
|
||||
;
|
||||
@@ -115,7 +120,9 @@ type
|
||||
: INTEGER
|
||||
| BOOLEAN
|
||||
| FLOAT
|
||||
| CHAR
|
||||
| IDENT
|
||||
| VOID
|
||||
;
|
||||
|
||||
functionCall
|
||||
@@ -143,6 +150,7 @@ forLoop
|
||||
IF: 'if';
|
||||
ELSE: 'else';
|
||||
FUNC: 'function';
|
||||
ENUM: 'enum';
|
||||
STRUCT: 'struct';
|
||||
RETURN: 'return';
|
||||
LET: 'let';
|
||||
@@ -178,9 +186,13 @@ SUB: '-';
|
||||
MOD: '%';
|
||||
DIV: '/';
|
||||
|
||||
SQUOT: '\'';
|
||||
|
||||
BOOLEAN: 'bool';
|
||||
INTEGER: 'int';
|
||||
FLOAT: 'float';
|
||||
CHAR: 'char';
|
||||
VOID: 'void';
|
||||
|
||||
INTEGER_LITERAL
|
||||
: [0-9]+
|
||||
@@ -195,6 +207,10 @@ BOOLEAN_LITERAL
|
||||
| 'false'
|
||||
;
|
||||
|
||||
CHAR_LITERAL
|
||||
: SQUOT [ -~] SQUOT
|
||||
;
|
||||
|
||||
IDENT
|
||||
: [a-zA-Z][a-zA-Z0-9]*
|
||||
;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
220
src/main/java/de/hsrm/compiler/Klang/GetDefinitions.java
Normal file
220
src/main/java/de/hsrm/compiler/Klang/GetDefinitions.java
Normal file
@@ -0,0 +1,220 @@
|
||||
package de.hsrm.compiler.Klang;
|
||||
|
||||
import de.hsrm.compiler.Klang.helper.Helper;
|
||||
import de.hsrm.compiler.Klang.nodes.*;
|
||||
import de.hsrm.compiler.Klang.types.NamedType;
|
||||
import de.hsrm.compiler.Klang.types.Type;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class GetDefinitions extends KlangBaseVisitor<Node> {
|
||||
private final Map<String, FunctionDefinition> 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, FunctionDefinition> 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 enumValues = new LinkedHashMap<String, EnumValue>();
|
||||
for (int i = 1; i < ctx.IDENT().size(); i++) {
|
||||
var currentEnumField = ctx.IDENT(i);
|
||||
var currentEnumFieldName = currentEnumField.getText();
|
||||
var line = currentEnumField.getSymbol().getLine();
|
||||
var col = currentEnumField.getSymbol().getCharPositionInLine();
|
||||
|
||||
if (enumValues.containsKey(currentEnumFieldName)) {
|
||||
var error = " Duplicate enum value " + currentEnumFieldName + " in enum " + enumName + ".";
|
||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||
}
|
||||
|
||||
var enumValue = new EnumValue(currentEnumFieldName, i - 1);
|
||||
enumValue.line = line;
|
||||
enumValue.col = col;
|
||||
|
||||
enumValues.put(currentEnumFieldName, enumValue);
|
||||
}
|
||||
|
||||
var enumDef = new EnumDefinition(enumName, enumValues.values().toArray(new EnumValue[0]));
|
||||
enumDef.line = ctx.start.getLine();
|
||||
enumDef.col = ctx.start.getCharPositionInLine();
|
||||
enumDef.type = new NamedType(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 LinkedHashMap<String, StructField>();
|
||||
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 structFieldLine = currentStructField.start.getLine();
|
||||
var structFieldCol = currentStructField.start.getCharPositionInLine();
|
||||
|
||||
if (structFields.containsKey(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(currentStructField.type_annotation().type().getText());
|
||||
structField.line = structFieldLine;
|
||||
structField.col = structFieldCol;
|
||||
|
||||
structFields.put(structFieldName, structField);
|
||||
}
|
||||
|
||||
var structDef = new StructDefinition(structName, structFields.values().toArray(new StructField[0]));
|
||||
structDef.line = line;
|
||||
structDef.col = col;
|
||||
structDef.type = new NamedType(structName);
|
||||
structDefs.put(structName, structDef);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visitFunctionDef(KlangParser.FunctionDefContext ctx) {
|
||||
var funcName = ctx.funcName.getText();
|
||||
var paramCount = ctx.params.parameter().size();
|
||||
var parameters = new LinkedHashMap<String, Parameter>();
|
||||
var line = ctx.start.getLine();
|
||||
var col = ctx.start.getCharPositionInLine();
|
||||
|
||||
// Check that there isn't a struct or enum with the same name
|
||||
if (structNames.contains(funcName) || enumNames.contains(funcName)) {
|
||||
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 paramName = currentParam.IDENT().getText();
|
||||
var paramLine = currentParam.start.getLine();
|
||||
var paramCol = currentParam.start.getCharPositionInLine();
|
||||
|
||||
if (parameters.containsKey(paramName)) {
|
||||
var error = "Duplicate parameter name " + paramName + " in function " + funcName + ".";
|
||||
throw new RuntimeException(Helper.getErrorPrefix(paramLine, paramCol) + error);
|
||||
}
|
||||
|
||||
var parameter = new Parameter(paramName);
|
||||
parameter.type = Type.getByName(currentParam.type_annotation().type().getText());
|
||||
parameter.line = paramLine;
|
||||
parameter.col = paramCol;
|
||||
|
||||
parameters.put(paramName, parameter);
|
||||
}
|
||||
|
||||
var functionDef = new FunctionDefinition(funcName, parameters.values().toArray(new Parameter[0]), null, null);
|
||||
functionDef.type = Type.getByName(ctx.returnType.type().getText());
|
||||
functionDef.line = line;
|
||||
functionDef.col = col;
|
||||
functionDefs.put(funcName, functionDef);
|
||||
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,24 @@
|
||||
package de.hsrm.compiler.Klang;
|
||||
|
||||
// import ANTLR's runtime libraries
|
||||
import org.antlr.v4.runtime.*;
|
||||
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.helper.*;
|
||||
import de.hsrm.compiler.Klang.nodes.EnumDefinition;
|
||||
import de.hsrm.compiler.Klang.nodes.FunctionDefinition;
|
||||
import de.hsrm.compiler.Klang.nodes.Node;
|
||||
import de.hsrm.compiler.Klang.nodes.StructDefinition;
|
||||
import de.hsrm.compiler.Klang.visitors.*;
|
||||
import de.hsrm.compiler.Klang.helper.*;
|
||||
import de.hsrm.compiler.Klang.types.Type;
|
||||
import de.hsrm.compiler.Klang.visitors.EvalVisitor;
|
||||
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 {
|
||||
|
||||
@@ -46,7 +51,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
|
||||
@@ -87,22 +92,15 @@ public class Klang {
|
||||
|
||||
// Context Analysis and DAST generation
|
||||
Node root;
|
||||
HashMap<String, StructDefinition> structs;
|
||||
var functionDefs = new HashMap<String, FunctionDefinition>();
|
||||
var structDefs = new HashMap<String, StructDefinition>();
|
||||
var enumDefs = new HashMap<String, EnumDefinition>();
|
||||
try {
|
||||
// Extract information about all functions
|
||||
var functionDefinitions = new HashMap<String, FunctionInformation>();
|
||||
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);
|
||||
// Extract information about all definitions
|
||||
new GetDefinitions(functionDefs, structDefs, enumDefs).visit(tree);
|
||||
|
||||
// Create the DAST
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(functionDefinitions, structs);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(functionDefs, structDefs, enumDefs);
|
||||
root = ctxAnal.visit(tree);
|
||||
} catch (Exception e) {
|
||||
System.err.println(e.getMessage());
|
||||
@@ -115,24 +113,26 @@ 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) {
|
||||
// Evaluate the sourcecode and print the result
|
||||
System.out.println("\nEvaluating the source code:");
|
||||
EvalVisitor evalVisitor = new EvalVisitor(structs);
|
||||
EvalVisitor evalVisitor = new EvalVisitor(structDefs);
|
||||
Value result = root.welcome(evalVisitor);
|
||||
generateOutput(out, "Result was: " + result.asObject().toString());
|
||||
if (result.type.equals(Type.getVoidType())) {
|
||||
generateOutput(out, "Result was void");
|
||||
} else {
|
||||
generateOutput(out, "Result was: " + result.asObject().toString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate assembler code
|
||||
// System.out.println("\nPrinting the assembler code");
|
||||
StringWriter wAsm = new StringWriter();
|
||||
GenASM.ExWriter exAsm = new GenASM.ExWriter(wAsm);
|
||||
GenASM genasm = new GenASM(exAsm, mainName, structs);
|
||||
GenASM genasm = new GenASM(mainName, structDefs);
|
||||
root.welcome(genasm);
|
||||
generateOutput(out, wAsm.toString());
|
||||
generateOutput(out, genasm.toAsm());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ import de.hsrm.compiler.Klang.types.Type;
|
||||
import java.util.Map;
|
||||
|
||||
public class Value {
|
||||
private final Object value;
|
||||
public Type type;
|
||||
private Object value;
|
||||
|
||||
public Value(Object value) {
|
||||
this.value = value;
|
||||
@@ -17,19 +17,23 @@ public class Value {
|
||||
}
|
||||
|
||||
public Object asObject() {
|
||||
return this.value;
|
||||
return value;
|
||||
}
|
||||
|
||||
public int asInteger() {
|
||||
return (int) this.value;
|
||||
return (int) value;
|
||||
}
|
||||
|
||||
public double asFloat() {
|
||||
return (double) this.value;
|
||||
return (double) value;
|
||||
}
|
||||
|
||||
public boolean asBoolean() {
|
||||
return (boolean) this.value;
|
||||
return (boolean) value;
|
||||
}
|
||||
|
||||
public char asChar() {
|
||||
return (char) value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
222
src/main/java/de/hsrm/compiler/Klang/asm/ASM.java
Normal file
222
src/main/java/de/hsrm/compiler/Klang/asm/ASM.java
Normal file
@@ -0,0 +1,222 @@
|
||||
package de.hsrm.compiler.Klang.asm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.hsrm.compiler.Klang.asm.mnemonics.*;
|
||||
|
||||
public class ASM {
|
||||
private List<Mnemonic> mnemonics;
|
||||
|
||||
public ASM() {
|
||||
this.mnemonics = new ArrayList<Mnemonic>();
|
||||
}
|
||||
|
||||
public void push(String dataType, int immediate) {
|
||||
mnemonics.add(new Push(dataType, immediate));
|
||||
}
|
||||
|
||||
public void push(String dataType, String operand) {
|
||||
mnemonics.add(new Push(dataType, operand));
|
||||
}
|
||||
|
||||
public void pop(String dataType, String operand) {
|
||||
mnemonics.add(new Pop(dataType, operand));
|
||||
}
|
||||
|
||||
public void mov(String dataType, String src, String dst) {
|
||||
mnemonics.add(new Mov(dataType, src, dst));
|
||||
}
|
||||
|
||||
public void mov(String dataType, String label, String src, String dst) {
|
||||
mnemonics.add(new Mov(dataType, label, src, dst));
|
||||
}
|
||||
|
||||
public void mov(String dataType, int offset, String src, String dst) {
|
||||
mnemonics.add(new Mov(dataType, offset, src, dst));
|
||||
}
|
||||
|
||||
public void mov(String dataType, String src, int offset, String dst) {
|
||||
mnemonics.add(new Mov(dataType, src, offset, dst));
|
||||
}
|
||||
|
||||
public void mov(String dataType, int immediate, String dst) {
|
||||
mnemonics.add(new Mov(dataType, immediate, dst));
|
||||
}
|
||||
|
||||
public void ucomi(String dataType, String src, String dst) {
|
||||
mnemonics.add(new Ucomi(dataType, src, dst));
|
||||
}
|
||||
|
||||
public void cmp(String dataType, String src, String dst) {
|
||||
mnemonics.add(new Cmp(dataType, src, dst));
|
||||
}
|
||||
|
||||
public void cmp(String dataType, int immediate, String dst) {
|
||||
mnemonics.add(new Cmp(dataType, immediate, dst));
|
||||
}
|
||||
|
||||
public void je(int label) {
|
||||
mnemonics.add(new Je(label));
|
||||
}
|
||||
|
||||
public void je(String labelPrefix, int label) {
|
||||
mnemonics.add(new Je(labelPrefix, label));
|
||||
}
|
||||
|
||||
public void jmp(int label) {
|
||||
mnemonics.add(new Jmp(label));
|
||||
}
|
||||
|
||||
public void jmp(String labelPrefix, int label) {
|
||||
mnemonics.add(new Jmp(labelPrefix, label));
|
||||
}
|
||||
|
||||
public void jne(int label) {
|
||||
mnemonics.add(new Jne(label));
|
||||
}
|
||||
|
||||
public void jne(String labelPrefix, int label) {
|
||||
mnemonics.add(new Jne(labelPrefix, label));
|
||||
}
|
||||
|
||||
public void jg(int label) {
|
||||
mnemonics.add(new Jg(label));
|
||||
}
|
||||
|
||||
public void jg(String labelPrefix, int label) {
|
||||
mnemonics.add(new Jg(labelPrefix, label));
|
||||
}
|
||||
|
||||
public void jge(int label) {
|
||||
mnemonics.add(new Jge(label));
|
||||
}
|
||||
|
||||
public void jge(String labelPrefix, int label) {
|
||||
mnemonics.add(new Jge(labelPrefix, label));
|
||||
}
|
||||
|
||||
public void jl(int label) {
|
||||
mnemonics.add(new Jl(label));
|
||||
}
|
||||
|
||||
public void jl(String labelPrefix, int label) {
|
||||
mnemonics.add(new Jl(labelPrefix, label));
|
||||
}
|
||||
|
||||
public void jle(int label) {
|
||||
mnemonics.add(new Jle(label));
|
||||
}
|
||||
|
||||
public void jle(String labelPrefix, int label) {
|
||||
mnemonics.add(new Jle(labelPrefix, label));
|
||||
}
|
||||
|
||||
public void jz(int label) {
|
||||
mnemonics.add(new Jz(label));
|
||||
}
|
||||
|
||||
public void jz(String labelPrefix, int label) {
|
||||
mnemonics.add(new Jz(labelPrefix, label));
|
||||
}
|
||||
|
||||
public void jnz(int label) {
|
||||
mnemonics.add(new Jnz(label));
|
||||
}
|
||||
|
||||
public void jnz(String labelPrefix, int label) {
|
||||
mnemonics.add(new Jnz(labelPrefix, label));
|
||||
}
|
||||
|
||||
public void label(int label) {
|
||||
mnemonics.add(new Label(label));
|
||||
}
|
||||
|
||||
public void label(String labelPrefix, int label) {
|
||||
mnemonics.add(new Label(labelPrefix, label));
|
||||
}
|
||||
|
||||
public void add(String dataType, String src, String dst) {
|
||||
mnemonics.add(new Add(dataType, src, dst));
|
||||
}
|
||||
|
||||
public void add(String dataType, String src, int dstOffset, String dst) {
|
||||
mnemonics.add(new Add(dataType, src, dstOffset, dst));
|
||||
}
|
||||
|
||||
public void add(String dataType, int immediate, String dst) {
|
||||
mnemonics.add(new Add(dataType, immediate, dst));
|
||||
}
|
||||
|
||||
public void sub(String dataType, String src, String dst) {
|
||||
mnemonics.add(new Sub(dataType, src, dst));
|
||||
}
|
||||
|
||||
public void mul(String dataType, String src, String dst) {
|
||||
mnemonics.add(new Mul(dataType, src, dst));
|
||||
}
|
||||
|
||||
public void div(String dataType, String src, String dst) {
|
||||
mnemonics.add(new Div(dataType, src, dst));
|
||||
}
|
||||
|
||||
public void idiv(String dataType, String operand) {
|
||||
mnemonics.add(new Idiv(dataType, operand));
|
||||
}
|
||||
|
||||
public void imul(String dataType, String src, String dst) {
|
||||
mnemonics.add(new Imul(dataType, src, dst));
|
||||
}
|
||||
|
||||
public void cqto() {
|
||||
mnemonics.add(new Cqto());
|
||||
}
|
||||
|
||||
public void leave() {
|
||||
mnemonics.add(new Leave());
|
||||
}
|
||||
|
||||
public void ret() {
|
||||
mnemonics.add(new Ret());
|
||||
}
|
||||
|
||||
public void xor(String dataType, String src, String dst) {
|
||||
mnemonics.add(new Xor(dataType, src, dst));
|
||||
}
|
||||
|
||||
public void neg(String operand) {
|
||||
mnemonics.add(new Neg(operand));
|
||||
}
|
||||
|
||||
public void functionHead(String functionName) {
|
||||
mnemonics.add(new FunctionHead(functionName));
|
||||
}
|
||||
|
||||
public void call(String operand) {
|
||||
mnemonics.add(new Call(operand));
|
||||
}
|
||||
|
||||
public void text(String text) {
|
||||
mnemonics.add(new Text(text));
|
||||
}
|
||||
|
||||
public void newline() {
|
||||
mnemonics.add(new Newline());
|
||||
}
|
||||
|
||||
public void cvtsi2sd(String src, String dst) {
|
||||
mnemonics.add(new Cvtsi2sd(src, dst));
|
||||
}
|
||||
|
||||
public String toAsm() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
mnemonics.stream().forEach(x -> {
|
||||
for (int i = 0; i < x.indentation; i++) {
|
||||
sb.append("\t");
|
||||
}
|
||||
sb.append(x.toAsm());
|
||||
sb.append("\n");
|
||||
});
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
29
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Add.java
Normal file
29
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Add.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Add extends TwoOperandMnemonic {
|
||||
public String dataType;
|
||||
|
||||
public Add(String dataType, String src, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = src;
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
public Add(String dataType, String src, int dstOffset, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = src;
|
||||
this.dst = dstOffset + "(" + dst + ")";
|
||||
}
|
||||
|
||||
public Add(String dataType, int immediate, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = "$" + immediate;
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "add" + this.dataType + " " + this.src + ", " + this.dst;
|
||||
}
|
||||
|
||||
}
|
||||
14
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Call.java
Normal file
14
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Call.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Call extends OneOperandMnemonic {
|
||||
|
||||
public Call(String operand) {
|
||||
this.operand = operand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "call " + this.operand;
|
||||
}
|
||||
|
||||
}
|
||||
22
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Cmp.java
Normal file
22
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Cmp.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Cmp extends TwoOperandMnemonic {
|
||||
public String dataType;
|
||||
|
||||
public Cmp(String dataType, String src, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = src;
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
public Cmp(String dataType, int immediate, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = "$" + immediate;
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "cmp" + this.dataType + " " + this.src + ", " + this.dst;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Cqto extends NoOperandMnemonic {
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "cqto";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Cvtsi2sd extends TwoOperandMnemonic {
|
||||
|
||||
public Cvtsi2sd(String src, String dst) {
|
||||
this.src = src;
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "cvtsi2sd " + this.src + ", " + this.dst;
|
||||
}
|
||||
|
||||
}
|
||||
17
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Div.java
Normal file
17
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Div.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Div extends TwoOperandMnemonic {
|
||||
public String dataType;
|
||||
|
||||
public Div(String dataType, String src, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = src;
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "div" + this.dataType + " " + this.src + ", " + this.dst;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class FunctionHead extends NoOperandMnemonic {
|
||||
|
||||
public String functionName;
|
||||
|
||||
public FunctionHead(String functionName) {
|
||||
this.functionName = functionName;
|
||||
this.indentation = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(".globl ");
|
||||
sb.append(this.functionName);
|
||||
sb.append("\n");
|
||||
sb.append(".type ");
|
||||
sb.append(this.functionName);
|
||||
sb.append(", @function\n");
|
||||
sb.append(this.functionName);
|
||||
sb.append(":");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
16
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Idiv.java
Normal file
16
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Idiv.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Idiv extends OneOperandMnemonic{
|
||||
public String dataType;
|
||||
|
||||
public Idiv(String dataType, String operand) {
|
||||
this.dataType = dataType;
|
||||
this.operand = operand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "idiv" + this.dataType + " " + this.operand;
|
||||
}
|
||||
|
||||
}
|
||||
17
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Imul.java
Normal file
17
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Imul.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Imul extends TwoOperandMnemonic {
|
||||
public String dataType;
|
||||
|
||||
public Imul(String dataType, String src, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = src;
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "imul" + this.dataType + " " + this.src + ", " + this.dst;
|
||||
}
|
||||
|
||||
}
|
||||
12
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Je.java
Normal file
12
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Je.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Je extends Jump {
|
||||
|
||||
public Je(int label) {
|
||||
super("je", label);
|
||||
}
|
||||
|
||||
public Je(String labelPrefix, int label) {
|
||||
super("je", labelPrefix, label);
|
||||
}
|
||||
}
|
||||
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jg.java
Normal file
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jg.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Jg extends Jump {
|
||||
public Jg(int label) {
|
||||
super("jg", label);
|
||||
}
|
||||
|
||||
public Jg(String labelPrefix, int label) {
|
||||
super("jg", labelPrefix, label);
|
||||
}
|
||||
}
|
||||
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jge.java
Normal file
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jge.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Jge extends Jump {
|
||||
public Jge(int label) {
|
||||
super("jge", label);
|
||||
}
|
||||
|
||||
public Jge(String labelPrefix, int label) {
|
||||
super("jge", labelPrefix, label);
|
||||
}
|
||||
}
|
||||
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jl.java
Normal file
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jl.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Jl extends Jump {
|
||||
public Jl(int label) {
|
||||
super("jl", label);
|
||||
}
|
||||
|
||||
public Jl(String labelPrefix, int label) {
|
||||
super("jl", labelPrefix, label);
|
||||
}
|
||||
}
|
||||
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jle.java
Normal file
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jle.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Jle extends Jump {
|
||||
public Jle(int label) {
|
||||
super("jle", label);
|
||||
}
|
||||
|
||||
public Jle(String labelPrefix, int label) {
|
||||
super("jle", labelPrefix, label);
|
||||
}
|
||||
}
|
||||
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jmp.java
Normal file
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jmp.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Jmp extends Jump {
|
||||
public Jmp(String labelPrefix, int label) {
|
||||
super("jmp", labelPrefix, label);
|
||||
}
|
||||
|
||||
public Jmp(int label) {
|
||||
super("jmp", label);
|
||||
}
|
||||
}
|
||||
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jne.java
Normal file
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jne.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Jne extends Jump {
|
||||
public Jne(int label) {
|
||||
super("jne", label);
|
||||
}
|
||||
|
||||
public Jne(String labelPrefix, int label) {
|
||||
super("jne", labelPrefix, label);
|
||||
}
|
||||
}
|
||||
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jnz.java
Normal file
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jnz.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Jnz extends Jump {
|
||||
public Jnz(int label) {
|
||||
super("jnz", label);
|
||||
}
|
||||
|
||||
public Jnz(String labelPrefix, int label) {
|
||||
super("jnz", labelPrefix, label);
|
||||
}
|
||||
}
|
||||
21
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jump.java
Normal file
21
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jump.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public abstract class Jump extends Mnemonic {
|
||||
protected String opcode;
|
||||
public String labelPrefix = "L";
|
||||
public int label;
|
||||
public Jump(String opcode, String labelPrefix, int label) {
|
||||
this.opcode = opcode;
|
||||
this.labelPrefix = labelPrefix;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public Jump(String opcode, int label) {
|
||||
this.opcode = opcode;
|
||||
this.label = label;
|
||||
}
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return this.opcode + " ." + this.labelPrefix + this.label;
|
||||
}
|
||||
}
|
||||
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jz.java
Normal file
11
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Jz.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Jz extends Jump {
|
||||
public Jz(int label) {
|
||||
super("jz", label);
|
||||
}
|
||||
|
||||
public Jz(String labelPrefix, int label) {
|
||||
super("jz", labelPrefix, label);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Label extends Mnemonic {
|
||||
public String labelPrefix = "L";
|
||||
public int label;
|
||||
|
||||
public Label(int label) {
|
||||
this.label = label;
|
||||
this.indentation = 0;
|
||||
}
|
||||
|
||||
public Label(String labelPrefix, int label) {
|
||||
this.labelPrefix = labelPrefix;
|
||||
this.label = label;
|
||||
this.indentation = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "." + this.labelPrefix + this.label + ":";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Leave extends NoOperandMnemonic {
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "leave";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public abstract class Mnemonic {
|
||||
public abstract String toAsm();
|
||||
public int indentation = 2;
|
||||
}
|
||||
40
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Mov.java
Normal file
40
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Mov.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Mov extends TwoOperandMnemonic{
|
||||
public String dataType = "q";
|
||||
|
||||
public Mov(String dataType, String src, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = src;
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
public Mov(String dataType, String label, String src, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = label + "(" + src + ")";
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
public Mov(String dataType, int offset, String src, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = offset + "(" + src + ")";
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
public Mov(String dataType, int immediate, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = "$" + immediate;
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
public Mov(String dataType, String src, int offset, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = src;
|
||||
this.dst = offset + "(" + dst + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "mov" + this.dataType + " " + this.src + ", " + this.dst;
|
||||
}
|
||||
}
|
||||
17
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Mul.java
Normal file
17
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Mul.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Mul extends TwoOperandMnemonic {
|
||||
public String dataType;
|
||||
|
||||
public Mul(String dataType, String src, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = src;
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "mul" + this.dataType + " " + this.src + ", " + this.dst;
|
||||
}
|
||||
|
||||
}
|
||||
14
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Neg.java
Normal file
14
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Neg.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Neg extends OneOperandMnemonic {
|
||||
|
||||
public Neg(String operand) {
|
||||
this.operand = operand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "neg " + this.operand;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Newline extends NoOperandMnemonic {
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public abstract class NoOperandMnemonic extends Mnemonic {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public abstract class OneOperandMnemonic extends Mnemonic {
|
||||
public String operand;
|
||||
}
|
||||
16
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Pop.java
Normal file
16
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Pop.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Pop extends OneOperandMnemonic {
|
||||
public String dataType;
|
||||
|
||||
public Pop(String dataType, String operand) {
|
||||
this.dataType = dataType;
|
||||
this.operand = operand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "pop" + this.dataType + " " + this.operand;
|
||||
}
|
||||
|
||||
}
|
||||
21
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Push.java
Normal file
21
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Push.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Push extends OneOperandMnemonic {
|
||||
public String dataType;
|
||||
|
||||
public Push(String dataType, int immediate){
|
||||
this.dataType = dataType;
|
||||
this.operand = "$" + immediate;
|
||||
}
|
||||
|
||||
public Push(String dataType, String operand) {
|
||||
this.dataType = dataType;
|
||||
this.operand = operand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "push" + this.dataType + " " + this.operand;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Ret extends NoOperandMnemonic {
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "ret";
|
||||
}
|
||||
}
|
||||
17
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Sub.java
Normal file
17
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Sub.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Sub extends TwoOperandMnemonic {
|
||||
public String dataType;
|
||||
|
||||
public Sub(String dataType, String src, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = src;
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "sub" + this.dataType + " " + this.src + ", " + this.dst;
|
||||
}
|
||||
|
||||
}
|
||||
15
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Text.java
Normal file
15
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Text.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Text extends NoOperandMnemonic {
|
||||
public String text;
|
||||
|
||||
public Text(String text) {
|
||||
this.text = text;
|
||||
this.indentation = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return this.text;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public abstract class TwoOperandMnemonic extends Mnemonic {
|
||||
public String src;
|
||||
public String dst;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Ucomi extends TwoOperandMnemonic {
|
||||
public String dataType;
|
||||
|
||||
public Ucomi(String dataType, String src, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = src;
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "ucomi" + this.dataType + " " + this.src + ", " + this.dst;
|
||||
}
|
||||
|
||||
}
|
||||
17
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Xor.java
Normal file
17
src/main/java/de/hsrm/compiler/Klang/asm/mnemonics/Xor.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package de.hsrm.compiler.Klang.asm.mnemonics;
|
||||
|
||||
public class Xor extends TwoOperandMnemonic {
|
||||
public String dataType;
|
||||
|
||||
public Xor(String dataType, String src, String dst) {
|
||||
this.dataType = dataType;
|
||||
this.src = src;
|
||||
this.dst = dst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAsm() {
|
||||
return "xor" + this.dataType + " " + this.src + ", " + this.dst;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package de.hsrm.compiler.Klang.helper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import de.hsrm.compiler.Klang.types.Type;
|
||||
|
||||
public class FunctionInformation {
|
||||
public String name;
|
||||
public Type returnType;
|
||||
public Map<String, Type> parameters;
|
||||
public Type[] signature;
|
||||
|
||||
public FunctionInformation(String name, Type returnType, Map<String,Type> parameters, Type[] signature) {
|
||||
this.name = name;
|
||||
this.returnType = returnType;
|
||||
this.parameters = parameters;
|
||||
this.signature = signature;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
package de.hsrm.compiler.Klang.nodes;
|
||||
|
||||
import de.hsrm.compiler.Klang.nodes.statements.Statement;
|
||||
import de.hsrm.compiler.Klang.visitors.Visitor;
|
||||
|
||||
public class Block extends Node {
|
||||
|
||||
public Statement[] statements;
|
||||
public Node[] statementsOrFunctionCalls;
|
||||
|
||||
public Block(Statement[] statements) {
|
||||
this.statements = statements;
|
||||
public Block(Node[] statements) {
|
||||
this.statementsOrFunctionCalls = statements;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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 EnumValue[] enums;
|
||||
|
||||
public EnumDefinition(String name, EnumValue[] enums) {
|
||||
this.name = name;
|
||||
this.enums = enums;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R welcome(Visitor<R> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
}
|
||||
18
src/main/java/de/hsrm/compiler/Klang/nodes/EnumValue.java
Normal file
18
src/main/java/de/hsrm/compiler/Klang/nodes/EnumValue.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package de.hsrm.compiler.Klang.nodes;
|
||||
|
||||
import de.hsrm.compiler.Klang.visitors.Visitor;
|
||||
|
||||
public class EnumValue extends Node {
|
||||
public String value;
|
||||
public int index;
|
||||
|
||||
public EnumValue(String value, int index) {
|
||||
this.value = value;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R welcome(Visitor<R> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,20 @@
|
||||
package de.hsrm.compiler.Klang.nodes;
|
||||
|
||||
import de.hsrm.compiler.Klang.nodes.statements.VariableDeclaration;
|
||||
import de.hsrm.compiler.Klang.visitors.Visitor;
|
||||
|
||||
public class FunctionDefinition extends Node {
|
||||
|
||||
public String name;
|
||||
public Parameter[] parameters;
|
||||
public VariableDeclaration[] localVariables;
|
||||
public Block block;
|
||||
|
||||
public FunctionDefinition(String name, Parameter[] parameters, Block block) {
|
||||
public FunctionDefinition(String name, Parameter[] parameters, VariableDeclaration[] localVariables, Block block) {
|
||||
this.name = name;
|
||||
this.parameters = parameters;
|
||||
this.block = block;
|
||||
this.localVariables = localVariables;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,11 +9,18 @@ public class Program extends Node {
|
||||
|
||||
public FunctionDefinition[] funcs;
|
||||
public Map<String, StructDefinition> structs;
|
||||
public Map<String, EnumDefinition> enums;
|
||||
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.structs = structs;
|
||||
this.enums = enums;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.hsrm.compiler.Klang.nodes.expressions;
|
||||
|
||||
import de.hsrm.compiler.Klang.visitors.Visitor;
|
||||
|
||||
public class CharExpression extends Expression {
|
||||
public char c;
|
||||
|
||||
public CharExpression(char c) {
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R welcome(Visitor<R> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package de.hsrm.compiler.Klang.nodes.expressions;
|
||||
|
||||
import de.hsrm.compiler.Klang.nodes.EnumDefinition;
|
||||
import de.hsrm.compiler.Klang.nodes.EnumValue;
|
||||
import de.hsrm.compiler.Klang.visitors.Visitor;
|
||||
|
||||
public class EnumAccessExpression extends Expression {
|
||||
public String enumName;
|
||||
public String enumValueName;
|
||||
public EnumValue enumValue;
|
||||
|
||||
public EnumAccessExpression(
|
||||
String enumName,
|
||||
String enumValueName,
|
||||
EnumValue enumValue
|
||||
) {
|
||||
this.enumName = enumName;
|
||||
this.enumValueName = enumValueName;
|
||||
this.enumValue = enumValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R welcome(Visitor<R> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -2,12 +2,12 @@ package de.hsrm.compiler.Klang.nodes.expressions;
|
||||
|
||||
import de.hsrm.compiler.Klang.visitors.Visitor;
|
||||
|
||||
public class StructFieldAccessExpression extends Expression {
|
||||
public class MemberAccessExpression extends Expression {
|
||||
public String varName;
|
||||
public String structName;
|
||||
public String[] path;
|
||||
|
||||
public StructFieldAccessExpression(String varName, String structName, String[] path) {
|
||||
public MemberAccessExpression(String varName, String structName, String[] path) {
|
||||
this.varName = varName;
|
||||
this.structName = structName;
|
||||
this.path = path;
|
||||
@@ -11,6 +11,10 @@ public class ReturnStatement extends Statement {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public ReturnStatement() {
|
||||
this.expression = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R welcome(Visitor<R> v) {
|
||||
return v.visit(this);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package de.hsrm.compiler.Klang.types;
|
||||
|
||||
import de.hsrm.compiler.Klang.Value;
|
||||
|
||||
public class BooleanType extends PrimitiveType {
|
||||
|
||||
private static BooleanType instance = null;
|
||||
@@ -30,7 +32,11 @@ public class BooleanType extends PrimitiveType {
|
||||
}
|
||||
|
||||
// Every remaining type will throw a RuntimeException
|
||||
throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName());
|
||||
throw new RuntimeException("Type mismatch: cannot combine " + this.getName() + " and " + that.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean valuesEqual(Value a, Value b) {
|
||||
return a.asBoolean() == b.asBoolean();
|
||||
}
|
||||
}
|
||||
47
src/main/java/de/hsrm/compiler/Klang/types/CharType.java
Normal file
47
src/main/java/de/hsrm/compiler/Klang/types/CharType.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package de.hsrm.compiler.Klang.types;
|
||||
|
||||
import de.hsrm.compiler.Klang.Value;
|
||||
|
||||
public class CharType extends PrimitiveType {
|
||||
private static CharType instance = null;
|
||||
|
||||
public static CharType getType() {
|
||||
if (instance != null) {
|
||||
return instance;
|
||||
}
|
||||
instance = new CharType();
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "char";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type combine(Type that) {
|
||||
if (this.equals(that)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (that.equals(Type.getIntegerType())) {
|
||||
return this;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Type mismatch: cannot combine " + getName() + " and " + that.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean valuesEqual(Value a, Value b) {
|
||||
return ((int) a.asChar()) == ((int) b.asChar());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (this == that) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return that instanceof CharType;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package de.hsrm.compiler.Klang.types;
|
||||
|
||||
import de.hsrm.compiler.Klang.Value;
|
||||
|
||||
public class FloatType extends NumericType {
|
||||
|
||||
private static FloatType instance = null;
|
||||
@@ -34,7 +36,11 @@ public class FloatType extends NumericType {
|
||||
}
|
||||
|
||||
// Every remaining type will throw a RuntimeException
|
||||
throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName());
|
||||
throw new RuntimeException("Type mismatch: cannot combine " + this.getName() + " and " + that.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean valuesEqual(Value a, Value b) {
|
||||
return a.asFloat() == b.asFloat();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package de.hsrm.compiler.Klang.types;
|
||||
|
||||
import de.hsrm.compiler.Klang.Value;
|
||||
|
||||
public class IntegerType extends NumericType {
|
||||
|
||||
private static IntegerType instance = null;
|
||||
@@ -33,8 +35,17 @@ public class IntegerType extends NumericType {
|
||||
return Type.getFloatType();
|
||||
}
|
||||
|
||||
if (that.equals(Type.getCharType())) {
|
||||
return Type.getCharType();
|
||||
}
|
||||
|
||||
// Every remaining type will throw a RuntimeException
|
||||
throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName());
|
||||
throw new RuntimeException("Type mismatch: cannot combine " + this.getName() + " and " + that.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean valuesEqual(Value a, Value b) {
|
||||
return a.asInteger() == b.asInteger();
|
||||
}
|
||||
|
||||
}
|
||||
53
src/main/java/de/hsrm/compiler/Klang/types/NamedType.java
Normal file
53
src/main/java/de/hsrm/compiler/Klang/types/NamedType.java
Normal file
@@ -0,0 +1,53 @@
|
||||
package de.hsrm.compiler.Klang.types;
|
||||
|
||||
import de.hsrm.compiler.Klang.Value;
|
||||
|
||||
public class NamedType extends Type {
|
||||
public String name;
|
||||
|
||||
public NamedType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type combine(Type that) {
|
||||
if(this.equals(that) || (that instanceof NullType)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Type mismatch: cannot combine " + getName() + " and " + that.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean valuesEqual(Value a, Value b) {
|
||||
return a.asObject().equals(b.asObject());
|
||||
}
|
||||
|
||||
@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 NamedType thatType) {
|
||||
return getName().equals(thatType.getName());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package de.hsrm.compiler.Klang.types;
|
||||
|
||||
import de.hsrm.compiler.Klang.Value;
|
||||
|
||||
public class NullType extends Type {
|
||||
|
||||
private static NullType instance = null;
|
||||
@@ -21,13 +23,18 @@ public class NullType extends Type {
|
||||
public Type combine(Type that) {
|
||||
// You can not combine null with a primitive type
|
||||
if (that.isPrimitiveType()) {
|
||||
throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName());
|
||||
throw new RuntimeException("Type mismatch: cannot combine " + this.getName() + " and " + that.getName());
|
||||
}
|
||||
|
||||
// Everything else combines with null to the type it was before
|
||||
return that;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean valuesEqual(Value a, Value b) {
|
||||
return a.asObject() == b.asObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrimitiveType() {
|
||||
return false;
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
package de.hsrm.compiler.Klang.types;
|
||||
|
||||
public class StructType extends Type {
|
||||
|
||||
public String name;
|
||||
|
||||
public StructType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type combine(Type that) {
|
||||
if (that.equals(this)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// If you combine a null type with a struct type, you
|
||||
// always get the struct type back.
|
||||
if (that == NullType.getType()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrimitiveType() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (this == that) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (that instanceof StructType) {
|
||||
StructType thatType = (StructType) that;
|
||||
return this.getName().equals(thatType.getName());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNumericType() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,12 @@
|
||||
package de.hsrm.compiler.Klang.types;
|
||||
|
||||
import de.hsrm.compiler.Klang.Value;
|
||||
import de.hsrm.compiler.Klang.nodes.EnumDefinition;
|
||||
import de.hsrm.compiler.Klang.nodes.FunctionDefinition;
|
||||
import de.hsrm.compiler.Klang.nodes.StructDefinition;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class Type {
|
||||
|
||||
// Returns an instance of IntegerType
|
||||
@@ -16,22 +23,33 @@ public abstract class Type {
|
||||
return FloatType.getType();
|
||||
}
|
||||
|
||||
public static CharType getCharType() {
|
||||
return CharType.getType();
|
||||
}
|
||||
|
||||
public static NullType getNullType() {
|
||||
return NullType.getType();
|
||||
}
|
||||
|
||||
public static VoidType getVoidType() {
|
||||
return VoidType.getType();
|
||||
}
|
||||
|
||||
public static Type getByName(String name) {
|
||||
switch (name) {
|
||||
case "bool": return getBooleanType();
|
||||
case "int": return getIntegerType();
|
||||
case "float": return getFloatType();
|
||||
case "char": return getCharType();
|
||||
case "null": return getNullType();
|
||||
default: return new StructType(name);
|
||||
case "void": return getVoidType();
|
||||
default: return new NamedType(name);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract String getName();
|
||||
public abstract Type combine(Type that);
|
||||
public abstract boolean valuesEqual(Value a, Value b);
|
||||
public abstract boolean isPrimitiveType();
|
||||
public abstract boolean isNumericType();
|
||||
}
|
||||
}
|
||||
|
||||
45
src/main/java/de/hsrm/compiler/Klang/types/VoidType.java
Normal file
45
src/main/java/de/hsrm/compiler/Klang/types/VoidType.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package de.hsrm.compiler.Klang.types;
|
||||
|
||||
import de.hsrm.compiler.Klang.Value;
|
||||
|
||||
public class VoidType extends Type {
|
||||
|
||||
private static VoidType instance;
|
||||
|
||||
public static VoidType getType() {
|
||||
if (instance != null) {
|
||||
return instance;
|
||||
}
|
||||
instance = new VoidType();
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "void";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type combine(Type that) {
|
||||
if (that.equals(this)) {
|
||||
return this;
|
||||
}
|
||||
throw new RuntimeException("Type mismatch: cannot combine " + this.getName() + " and " + that.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean valuesEqual(Value a, Value b) {
|
||||
throw new RuntimeException("Can not compare void types.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrimitiveType() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNumericType() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,17 +4,13 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import de.hsrm.compiler.Klang.Value;
|
||||
import de.hsrm.compiler.Klang.nodes.Block;
|
||||
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.*;
|
||||
import de.hsrm.compiler.Klang.nodes.expressions.*;
|
||||
import de.hsrm.compiler.Klang.nodes.loops.DoWhileLoop;
|
||||
import de.hsrm.compiler.Klang.nodes.loops.ForLoop;
|
||||
import de.hsrm.compiler.Klang.nodes.loops.WhileLoop;
|
||||
import de.hsrm.compiler.Klang.nodes.statements.*;
|
||||
import de.hsrm.compiler.Klang.types.NullType;
|
||||
import de.hsrm.compiler.Klang.types.Type;
|
||||
|
||||
public class EvalVisitor implements Visitor<Value> {
|
||||
@@ -50,26 +46,17 @@ public class EvalVisitor implements Visitor<Value> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(EqualityExpression e) {
|
||||
Value lhs = e.lhs.welcome(this);
|
||||
Value rhs = e.rhs.welcome(this);
|
||||
Type resultType = Type.getBooleanType();
|
||||
Type combineType = lhs.type.combine(rhs.type);
|
||||
public Value visit(CharExpression e) {
|
||||
return new Value(e.c, Type.getCharType());
|
||||
}
|
||||
|
||||
switch(combineType.getName()) {
|
||||
case "bool": {
|
||||
return new Value(lhs.asBoolean() == rhs.asBoolean(), resultType);
|
||||
}
|
||||
case "int": {
|
||||
return new Value(lhs.asInteger() == rhs.asInteger(), resultType);
|
||||
}
|
||||
case "float": {
|
||||
return new Value(lhs.asFloat() == rhs.asFloat(), resultType);
|
||||
}
|
||||
default: {
|
||||
return new Value(lhs.asObject() == rhs.asObject(), resultType);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Value visit(EqualityExpression e) {
|
||||
var lhs = e.lhs.welcome(this);
|
||||
var rhs = e.rhs.welcome(this);
|
||||
var combinedType = lhs.type.combine(rhs.type);
|
||||
|
||||
return new Value(combinedType.valuesEqual(lhs, rhs), Type.getBooleanType());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -413,13 +400,16 @@ public class EvalVisitor implements Visitor<Value> {
|
||||
|
||||
@Override
|
||||
public Value visit(ReturnStatement e) {
|
||||
if (e.expression == null) {
|
||||
return new Value(null, Type.getVoidType());
|
||||
}
|
||||
return e.expression.welcome(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(Block e) {
|
||||
for (var stmt : e.statements) {
|
||||
Value result = stmt.welcome(this);
|
||||
for (var stmt : e.statementsOrFunctionCalls) {
|
||||
var result = stmt.welcome(this);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
@@ -447,7 +437,7 @@ public class EvalVisitor implements Visitor<Value> {
|
||||
this.env = newEnv;
|
||||
|
||||
// Execute
|
||||
Value result = func.block.welcome(this);
|
||||
var result = func.block.welcome(this);
|
||||
|
||||
// Das alte env wiederherstellen
|
||||
this.env = oldEnv;
|
||||
@@ -471,6 +461,16 @@ public class EvalVisitor implements Visitor<Value> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(EnumDefinition e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(EnumValue e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(StructDefinition e) {
|
||||
// We get these from a previous visitor
|
||||
@@ -484,7 +484,7 @@ public class EvalVisitor implements Visitor<Value> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(StructFieldAccessExpression e) {
|
||||
public Value visit(MemberAccessExpression e) {
|
||||
Value var = this.env.get(e.varName);
|
||||
Map<String, Value> struct = var.asStruct();
|
||||
|
||||
@@ -496,6 +496,11 @@ public class EvalVisitor implements Visitor<Value> {
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(EnumAccessExpression e) {
|
||||
return new Value(e.enumValueName, e.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(ConstructorCall e) {
|
||||
StructDefinition structDef = this.structs.get(e.structName);
|
||||
@@ -506,12 +511,17 @@ public class EvalVisitor implements Visitor<Value> {
|
||||
struct.put(structDef.fields[i].name, arg);
|
||||
}
|
||||
|
||||
return new Value(struct);
|
||||
var structValue = new Value(struct);
|
||||
structValue.type = structDef.type;
|
||||
|
||||
return structValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(NullExpression e) {
|
||||
return null;
|
||||
var nullValue = new Value(null);
|
||||
nullValue.type = new NullType();
|
||||
return nullValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,271 +0,0 @@
|
||||
package de.hsrm.compiler.Klang.visitors;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import de.hsrm.compiler.Klang.nodes.*;
|
||||
import de.hsrm.compiler.Klang.nodes.expressions.*;
|
||||
import de.hsrm.compiler.Klang.nodes.loops.DoWhileLoop;
|
||||
import de.hsrm.compiler.Klang.nodes.loops.ForLoop;
|
||||
import de.hsrm.compiler.Klang.nodes.loops.WhileLoop;
|
||||
import de.hsrm.compiler.Klang.nodes.statements.*;
|
||||
import de.hsrm.compiler.Klang.types.Type;
|
||||
|
||||
class GetVars implements Visitor<Void> {
|
||||
|
||||
public Set<String> vars;
|
||||
public Map<String, Type> types;
|
||||
|
||||
public GetVars(Set<String> vars, Map<String, Type> types) {
|
||||
this.vars = vars;
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(IntegerExpression e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(FloatExpression e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(BooleanExpression e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(Variable e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(EqualityExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
e.rhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(NotEqualityExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
e.rhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(GTExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
e.rhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(GTEExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
e.rhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(LTExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
e.rhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(LTEExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
e.rhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(AdditionExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
e.rhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(SubstractionExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
e.rhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(MultiplicationExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
e.rhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(DivisionExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
e.rhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(ModuloExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
e.rhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(NegateExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(OrExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
e.rhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(AndExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
e.rhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(NotExpression e) {
|
||||
e.lhs.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(IfStatement e) {
|
||||
e.cond.welcome(this);
|
||||
e.then.welcome(this);
|
||||
if (e.alt != null) {
|
||||
e.alt.welcome(this);
|
||||
} else if (e.elif != null) {
|
||||
e.elif.welcome(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(WhileLoop e) {
|
||||
e.cond.welcome(this);
|
||||
e.block.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(DoWhileLoop e) {
|
||||
e.cond.welcome(this);
|
||||
e.block.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(ForLoop e) {
|
||||
e.init.welcome(this);
|
||||
e.condition.welcome(this);
|
||||
e.step.welcome(this);
|
||||
e.block.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(VariableDeclaration e) {
|
||||
vars.add(e.name);
|
||||
types.put(e.name, e.type);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(VariableAssignment e) {
|
||||
e.expression.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(ReturnStatement e) {
|
||||
e.expression.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(Block e) {
|
||||
for (var statement : e.statements) {
|
||||
statement.welcome(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(FunctionDefinition e) {
|
||||
e.block.welcome(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(FunctionCall e) {
|
||||
for (var expression : e.arguments) {
|
||||
expression.welcome(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(Program e) {
|
||||
e.expression.welcome(this);
|
||||
for (var func : e.funcs) {
|
||||
func.welcome(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(Parameter e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructDefinition e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructField e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructFieldAccessExpression e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(ConstructorCall e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(NullExpression e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(DestructorCall e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(FieldAssignment e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -68,6 +68,12 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
||||
ex.nl();
|
||||
}
|
||||
|
||||
for (var enumDef: e.enums.values()) {
|
||||
enumDef.welcome(this);
|
||||
ex.nl();
|
||||
ex.nl();
|
||||
}
|
||||
|
||||
e.expression.welcome(this);
|
||||
ex.write(";");
|
||||
return null;
|
||||
@@ -91,6 +97,14 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(CharExpression e) {
|
||||
ex.write("'");
|
||||
ex.write(e.c);
|
||||
ex.write("'");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(EqualityExpression e) {
|
||||
ex.write("(");
|
||||
@@ -304,8 +318,11 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
||||
|
||||
@Override
|
||||
public Void visit(ReturnStatement e) {
|
||||
ex.write("return ");
|
||||
e.expression.welcome(this);
|
||||
ex.write("return");
|
||||
if (e.expression != null) {
|
||||
ex.write(" ");
|
||||
e.expression.welcome(this);
|
||||
}
|
||||
ex.write(";");
|
||||
return null;
|
||||
}
|
||||
@@ -314,7 +331,7 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
||||
public Void visit(Block e) {
|
||||
ex.write("{");
|
||||
ex.addIndent();
|
||||
for (Statement stmt : e.statements) {
|
||||
for (var stmt : e.statementsOrFunctionCalls) {
|
||||
ex.nl();
|
||||
stmt.welcome(this);
|
||||
if (stmt.getClass() == VariableAssignment.class || stmt.getClass() == VariableDeclaration.class) {
|
||||
@@ -377,6 +394,28 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(EnumDefinition e) {
|
||||
ex.write("enum " + e.name + " { ");
|
||||
var first = true;
|
||||
for(var enumValue: e.enums) {
|
||||
if (!first) {
|
||||
ex.write(", ");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
enumValue.welcome(this);
|
||||
}
|
||||
ex.write(" }");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(EnumValue e) {
|
||||
ex.write(e.value);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructDefinition e) {
|
||||
ex.write("struct " + e.name + " {");
|
||||
@@ -398,7 +437,7 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructFieldAccessExpression e) {
|
||||
public Void visit(MemberAccessExpression e) {
|
||||
ex.write(e.varName);
|
||||
for (int i = 0; i < e.path.length; i++) {
|
||||
ex.write(".");
|
||||
@@ -407,6 +446,15 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(EnumAccessExpression e) {
|
||||
ex.write(e.enumName);
|
||||
ex.write(".");
|
||||
ex.write(e.enumValueName);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(ConstructorCall e) {
|
||||
ex.write("create " + e.structName + "(");
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
package de.hsrm.compiler.Klang.visitors;
|
||||
|
||||
import de.hsrm.compiler.Klang.nodes.Block;
|
||||
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.*;
|
||||
import de.hsrm.compiler.Klang.nodes.expressions.*;
|
||||
import de.hsrm.compiler.Klang.nodes.loops.*;
|
||||
import de.hsrm.compiler.Klang.nodes.statements.*;
|
||||
@@ -17,6 +12,7 @@ public interface Visitor<R> {
|
||||
R visit(IntegerExpression e);
|
||||
R visit(FloatExpression e);
|
||||
R visit(BooleanExpression e);
|
||||
R visit(CharExpression e);
|
||||
R visit(Variable e);
|
||||
R visit(AdditionExpression e);
|
||||
R visit(EqualityExpression e);
|
||||
@@ -42,9 +38,12 @@ public interface Visitor<R> {
|
||||
R visit(FunctionCall e);
|
||||
R visit(Program e);
|
||||
R visit(Parameter e);
|
||||
R visit(EnumDefinition e);
|
||||
R visit(EnumValue e);
|
||||
R visit(StructDefinition e);
|
||||
R visit(StructField e);
|
||||
R visit(StructFieldAccessExpression e);
|
||||
R visit(MemberAccessExpression e);
|
||||
R visit(EnumAccessExpression e);
|
||||
R visit(ConstructorCall e);
|
||||
R visit(NullExpression e);
|
||||
R visit(DestructorCall e);
|
||||
|
||||
@@ -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);
|
||||
|
||||
21
src/test/java/AndTest.java
Normal file
21
src/test/java/AndTest.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 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);
|
||||
var enums = Helper.getEnums(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:30 && is only defined for bool.", e.getMessage());
|
||||
}
|
||||
}
|
||||
164
src/test/java/CharTest.java
Normal file
164
src/test/java/CharTest.java
Normal file
@@ -0,0 +1,164 @@
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class CharTest {
|
||||
|
||||
@Test
|
||||
void shouldNotThrowIfComparingCharsEquality() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("""
|
||||
function bar(): int {
|
||||
let b: char = 'b';
|
||||
if ('a' == b) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
bar();
|
||||
""");
|
||||
var ctxAnal = new ContextAnalysis(Helper.getFuncs(tree), Helper.getStructs(tree), Helper.getEnums(tree));
|
||||
|
||||
// when / then
|
||||
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotThrowIfComparingCharsInequality() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("""
|
||||
function bar(): int {
|
||||
let b: char = 'b';
|
||||
if ('a' > b) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
bar();
|
||||
""");
|
||||
var ctxAnal = new ContextAnalysis(Helper.getFuncs(tree), Helper.getStructs(tree), Helper.getEnums(tree));
|
||||
|
||||
// when / then
|
||||
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotThrowIfCharLiteralIsAssignedToCharVariable() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("""
|
||||
function bar(): int {
|
||||
let c: char = 'c';
|
||||
return 1;
|
||||
}
|
||||
bar();
|
||||
""");
|
||||
var ctxAnal = new ContextAnalysis(Helper.getFuncs(tree), Helper.getStructs(tree), Helper.getEnums(tree));
|
||||
|
||||
// when / then
|
||||
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotThrowIfCharLiteralIsReturnedFromFunction() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("""
|
||||
function bar(): char {
|
||||
return 'c';
|
||||
}
|
||||
bar();
|
||||
""");
|
||||
var ctxAnal = new ContextAnalysis(Helper.getFuncs(tree), Helper.getStructs(tree), Helper.getEnums(tree));
|
||||
|
||||
// when / then
|
||||
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotThrowIfCharIsUsedInStruct() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("""
|
||||
struct myChar { c: char; }
|
||||
function bar(): myChar {
|
||||
let x: myChar = create myChar('c');
|
||||
return x;
|
||||
}
|
||||
bar();
|
||||
""");
|
||||
var ctxAnal = new ContextAnalysis(Helper.getFuncs(tree), Helper.getStructs(tree), Helper.getEnums(tree));
|
||||
|
||||
// when / then
|
||||
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowIfCharIsAssignedToOtherTypedVariable() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("""
|
||||
struct foo { f: float; }
|
||||
function bar(): int {
|
||||
let c: foo = 'c';
|
||||
return 1;
|
||||
}
|
||||
bar();
|
||||
""");
|
||||
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 3:4 Type mismatch: cannot combine foo and char", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowWhenReturningCharFromOtherTypedFunction() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("""
|
||||
function bar(): float {
|
||||
return 'c';
|
||||
}
|
||||
bar();
|
||||
""");
|
||||
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 2:4 Type mismatch: cannot combine float and char", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowPassingCharToOtherTypedFunctionParameter() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("""
|
||||
function foo(a: float): void {
|
||||
let x: bool = false;
|
||||
}
|
||||
function bar(): void {
|
||||
foo('c');
|
||||
}
|
||||
bar();
|
||||
""");
|
||||
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 5:4 argument 0 Expected float but got: char", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowWhenAssigningCharToOtherTypedStructField() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("""
|
||||
struct foo { a: bool; }
|
||||
function bar(): void {
|
||||
let x: foo = create foo(false);
|
||||
x.a = 'c';
|
||||
}
|
||||
bar();
|
||||
""");
|
||||
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 4:4 Type mismatch: cannot combine bool and char", e.getMessage());
|
||||
}
|
||||
}
|
||||
46
src/test/java/ConstructorCallTest.java
Normal file
46
src/test/java/ConstructorCallTest.java
Normal file
@@ -0,0 +1,46 @@
|
||||
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);
|
||||
var enums = Helper.getEnums(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:52 Struct with name \"schwurbel\" not defined.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void numConstructorParametermismatch() {
|
||||
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);
|
||||
var enums = Helper.getEnums(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||
|
||||
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);
|
||||
var enums = Helper.getEnums(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:63 argument 0 Type mismatch: cannot combine bool and int", e.getMessage());
|
||||
}
|
||||
}
|
||||
22
src/test/java/DestroyStatementTest.java
Normal file
22
src/test/java/DestroyStatementTest.java
Normal file
@@ -0,0 +1,22 @@
|
||||
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);
|
||||
var enums = Helper.getEnums(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:45 Variable or parameter with name \"x\" not defined.", e.getMessage());
|
||||
}
|
||||
}
|
||||
34
src/test/java/FieldAssignmentTest.java
Normal file
34
src/test/java/FieldAssignmentTest.java
Normal file
@@ -0,0 +1,34 @@
|
||||
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);
|
||||
var enums = Helper.getEnums(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:46 Variable or parameter 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);
|
||||
var enums = Helper.getEnums(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:62 Variable or parameter must reference a struct but references int.", e.getMessage());
|
||||
}
|
||||
}
|
||||
46
src/test/java/FunctionCallTest.java
Normal file
46
src/test/java/FunctionCallTest.java
Normal file
@@ -0,0 +1,46 @@
|
||||
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);
|
||||
var enums = Helper.getEnums(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||
|
||||
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);
|
||||
var enums = Helper.getEnums(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||
|
||||
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 parameterTypeMismatch() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(x: int): int { return x; } foo(false);");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
var enums = Helper.getEnums(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:40 argument 0 Expected int but got: bool", e.getMessage());
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user