Compare commits
42 Commits
abgabe_com
...
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 |
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
|
||||
|
||||
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>
|
||||
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>
|
||||
7
pom.xml
7
pom.xml
@@ -40,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
|
||||
@@ -72,6 +72,11 @@
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>de.hsrm.compiler.Klang.Klang</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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());
|
||||
@@ -122,18 +120,19 @@ public class Klang {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -12,7 +12,8 @@ public class AndTest {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): bool { return 1 && 2; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -13,18 +13,20 @@ public class ConstructorCallTest {
|
||||
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): bar { return create schwurbel(1); } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
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 numConstructorParameterMissmatch() {
|
||||
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);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
var enums = Helper.getEnums(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:52 Struct \"bar\" defined 1 fields, but got 2 constructor parameters.", e.getMessage());
|
||||
@@ -35,9 +37,10 @@ public class ConstructorCallTest {
|
||||
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): bar { return create bar(false); } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
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 missmatch: cannot combine bool and int", e.getMessage());
|
||||
assertEquals("Error in line 1:63 argument 0 Type mismatch: cannot combine bool and int", e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,10 @@ public class DestroyStatementTest {
|
||||
ParseTree tree = Helper.prepareParser("struct bar { a: int; } function foo(): int { destroy x; return 1; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
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 with name \"x\" not defined.", e.getMessage());
|
||||
assertEquals("Error in line 1:45 Variable or parameter with name \"x\" not defined.", e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -13,10 +13,11 @@ public class FieldAssignmentTest {
|
||||
ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { str.a = 1; return 1; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
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 with name str not defined.", e.getMessage());
|
||||
assertEquals("Error in line 1:46 Variable or parameter with name \"str\" not defined.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -24,9 +25,10 @@ public class FieldAssignmentTest {
|
||||
ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { let x: int = 0; x.a = 0; return 1; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
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 must reference a struct but references int.", e.getMessage());
|
||||
assertEquals("Error in line 1:62 Variable or parameter must reference a struct but references int.", e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,8 @@ public class FunctionCallTest {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): int { return 1; } bar();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
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());
|
||||
@@ -24,18 +25,20 @@ public class FunctionCallTest {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): int { return 1; } foo(5);");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
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 parameterTypeMissmatch() {
|
||||
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);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
var enums = Helper.getEnums(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:40 argument 0 Expected int but got: bool", e.getMessage());
|
||||
|
||||
@@ -1,32 +1,119 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class FunctionDefinitionTest {
|
||||
|
||||
@Test
|
||||
void typeNotDefined() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): schwurbel { return 1; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:0 Type schwurbel not defined.", e.getMessage());
|
||||
void shouldNotThrowIfReturnTypeIsReferringToAnEnum() {
|
||||
// given
|
||||
var tree = Helper.prepareParser(" enum bar {A,B,C} function foo(a: int): bar { return bar.A; } foo(1);");
|
||||
var ctxAnal = new ContextAnalysis(
|
||||
Helper.getFuncs(tree),
|
||||
Helper.getStructs(tree),
|
||||
Helper.getEnums(tree)
|
||||
);
|
||||
|
||||
// when / then
|
||||
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||
}
|
||||
|
||||
@Test
|
||||
void noReturnExpression() {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): int { let x: int; x = 0; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:0 Function foo has to return something of type int.", e.getMessage());
|
||||
void shouldNotThrowIfParameterTypeIsReferringToAnEnum() {
|
||||
// given
|
||||
var tree = Helper.prepareParser(" enum bar {A,B,C} function foo(a: bar): int { return 1; } foo(bar.A);");
|
||||
var ctxAnal = new ContextAnalysis(
|
||||
Helper.getFuncs(tree),
|
||||
Helper.getStructs(tree),
|
||||
Helper.getEnums(tree)
|
||||
);
|
||||
|
||||
// when / then
|
||||
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionIfParameterTypeIsNotDefined() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("function foo(a: schwurbel): int { return 1; } foo();");
|
||||
var ctxAnal = new ContextAnalysis(
|
||||
Helper.getFuncs(tree),
|
||||
Helper.getStructs(tree),
|
||||
Helper.getEnums(tree)
|
||||
);
|
||||
|
||||
// when / then
|
||||
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:14 Type schwurbel not defined.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionIfReturnTypeIsNotDefined() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("function foo(): schwurbel { return 1; } foo();");
|
||||
var ctxAnal = new ContextAnalysis(
|
||||
Helper.getFuncs(tree),
|
||||
Helper.getStructs(tree),
|
||||
Helper.getEnums(tree)
|
||||
);
|
||||
|
||||
// when / then
|
||||
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:14 Type schwurbel not defined.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionIfReturnStatementIsMissing() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("function foo(): int { let x: int; x = 0; } foo();");
|
||||
var ctxAnal = new ContextAnalysis(
|
||||
Helper.getFuncs(tree),
|
||||
Helper.getStructs(tree),
|
||||
Helper.getEnums(tree)
|
||||
);
|
||||
|
||||
// when / then
|
||||
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:20 Function foo has to return something of type int.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionIfParameterNameMatchesEnumName() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("enum Bar { A, B } function foo(Bar: int): int { return 1; } foo(1);");
|
||||
var ctxAnal = new ContextAnalysis(
|
||||
Helper.getFuncs(tree),
|
||||
Helper.getStructs(tree),
|
||||
Helper.getEnums(tree)
|
||||
);
|
||||
|
||||
// when / then
|
||||
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:31 Parameter name Bar duplicates an enum of the same name.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResetVariablesAndParameterEnvironment() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("""
|
||||
function foo(x: int): int {
|
||||
return 1;
|
||||
}
|
||||
function bar(): int {
|
||||
let x: int = 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
bar();
|
||||
""");
|
||||
var ctxAnal = new ContextAnalysis(
|
||||
Helper.getFuncs(tree),
|
||||
Helper.getStructs(tree),
|
||||
Helper.getEnums(tree)
|
||||
);
|
||||
|
||||
// when / then
|
||||
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||
}
|
||||
}
|
||||
@@ -16,21 +16,21 @@ public class Helper {
|
||||
return parser.parse();
|
||||
}
|
||||
|
||||
public static Map<String, FunctionInformation> getFuncs(ParseTree tree) {
|
||||
var functionDefinitions = new HashMap<String, FunctionInformation>();
|
||||
new GetFunctions(functionDefinitions).visit(tree);
|
||||
public static Map<String, FunctionDefinition> getFuncs(ParseTree tree) {
|
||||
var functionDefinitions = new HashMap<String, FunctionDefinition>();
|
||||
new GetDefinitions(functionDefinitions, new HashMap<>(), new HashMap<>()).visit(tree);
|
||||
return functionDefinitions;
|
||||
}
|
||||
|
||||
public static Set<String> getStructNames(ParseTree tree) {
|
||||
var structNames = new HashSet<String>();
|
||||
new GetStructNames(structNames).visit(tree);
|
||||
return structNames;
|
||||
}
|
||||
|
||||
public static Map<String, StructDefinition> getStructs(ParseTree tree) {
|
||||
var structs = new HashMap<String, StructDefinition>();
|
||||
new GetStructs(getStructNames(tree), structs).visit(tree);
|
||||
new GetDefinitions(new HashMap<>(), structs, new HashMap<>()).visit(tree);
|
||||
return structs;
|
||||
}
|
||||
|
||||
public static Map<String, EnumDefinition> getEnums(ParseTree tree) {
|
||||
var enums = new HashMap<String, EnumDefinition>();
|
||||
new GetDefinitions(new HashMap<>(), new HashMap<>(), enums).visit(tree);
|
||||
return enums;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,8 @@ public class ModuloTest {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): float { return 1.0 % 2.3; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
var enums = Helper.getEnums(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs, enums);
|
||||
|
||||
Exception e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:31 Only integers are allowed for modulo.", e.getMessage());
|
||||
|
||||
72
src/test/java/NaughtTest.java
Normal file
72
src/test/java/NaughtTest.java
Normal file
@@ -0,0 +1,72 @@
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class NaughtTest {
|
||||
@Test
|
||||
void shouldBeComparableToStruct() {
|
||||
ParseTree tree = Helper.prepareParser("""
|
||||
struct bar { a: int; }
|
||||
|
||||
function foo(): int {
|
||||
let a: bar = create bar(1);
|
||||
if (a == naught) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
foo();
|
||||
""");
|
||||
var ctxAnal = new ContextAnalysis(
|
||||
Helper.getFuncs(tree),
|
||||
Helper.getStructs(tree),
|
||||
Helper.getEnums(tree)
|
||||
);
|
||||
|
||||
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBeAssignableToStruct() {
|
||||
ParseTree tree = Helper.prepareParser("""
|
||||
struct bar { a: int; }
|
||||
|
||||
function foo(): int {
|
||||
let a: bar = naught;
|
||||
return 1;
|
||||
}
|
||||
|
||||
foo();
|
||||
""");
|
||||
var ctxAnal = new ContextAnalysis(
|
||||
Helper.getFuncs(tree),
|
||||
Helper.getStructs(tree),
|
||||
Helper.getEnums(tree)
|
||||
);
|
||||
|
||||
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBeReturnable() {
|
||||
ParseTree tree = Helper.prepareParser("""
|
||||
struct bar { a: int; }
|
||||
|
||||
function foo(): bar {
|
||||
return naught;
|
||||
}
|
||||
|
||||
foo();
|
||||
""");
|
||||
var ctxAnal = new ContextAnalysis(
|
||||
Helper.getFuncs(tree),
|
||||
Helper.getStructs(tree),
|
||||
Helper.getEnums(tree)
|
||||
);
|
||||
|
||||
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,8 @@ public class OrTest {
|
||||
ParseTree tree = Helper.prepareParser("function foo(): bool { return 1 || 2; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
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());
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ParameterTest {
|
||||
@Test
|
||||
void typeNotDefined() {
|
||||
ParseTree tree = Helper.prepareParser("struct test { a: schwurbel; } function foo(): int { return 1; } foo();");
|
||||
Exception e = assertThrows(RuntimeException.class, () -> Helper.getStructs(tree));
|
||||
assertEquals("Error in line 1:14 Type schwurbel not defined.", e.getMessage());
|
||||
}
|
||||
}
|
||||
94
src/test/java/StructDefinitionTest.java
Normal file
94
src/test/java/StructDefinitionTest.java
Normal file
@@ -0,0 +1,94 @@
|
||||
import de.hsrm.compiler.Klang.ContextAnalysis;
|
||||
import de.hsrm.compiler.Klang.GetDefinitions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class StructDefinitionTest {
|
||||
@Test
|
||||
void shouldNotThrowIfStructIsWellDefined() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("struct test { a: int; } function foo(): int { return 1; } foo();");
|
||||
var ctxAnal = new ContextAnalysis(Helper.getFuncs(tree), Helper.getStructs(tree), Helper.getEnums(tree));
|
||||
|
||||
// when / then
|
||||
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotThrowIfStructFieldTypeIsReferringToEnum() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("struct test { a: bar; } enum bar {A,B,C} function foo(): int { return 1; } foo();");
|
||||
var ctxAnal = new ContextAnalysis(Helper.getFuncs(tree), Helper.getStructs(tree), Helper.getEnums(tree));
|
||||
|
||||
// when / then
|
||||
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotThrowIfStructFieldTypeIsReferringToStruct() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("struct a { hello: int; } struct b { world: a; } function foo(): int { return 1; } foo();");
|
||||
var ctxAnal = new ContextAnalysis(Helper.getFuncs(tree), Helper.getStructs(tree), Helper.getEnums(tree));
|
||||
|
||||
// when / then
|
||||
assertDoesNotThrow(() -> ctxAnal.visit(tree));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionIfStructFieldNameShadowsAStruct() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("struct bar { a: int; } struct baz { bar: int; } function foo(): int { return 1; } foo();");
|
||||
var ctxAnal = new ContextAnalysis(Helper.getFuncs(tree), Helper.getStructs(tree), Helper.getEnums(tree));
|
||||
|
||||
// when / then
|
||||
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:36 Struct field name bar shadows a struct of the same name.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionIfStructFieldNameShadowsAnEnum() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("enum bar { A, B } struct baz { bar: int; } function foo(): int { return 1; } foo();");
|
||||
var ctxAnal = new ContextAnalysis(Helper.getFuncs(tree), Helper.getStructs(tree), Helper.getEnums(tree));
|
||||
|
||||
// when / then
|
||||
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:31 Struct field name bar shadows an enum of the same name.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionIfStructFieldTypeIsNotDefined() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("struct test { a: schwurbel; } function foo(): int { return 1; } foo();");
|
||||
var ctxAnal = new ContextAnalysis(Helper.getFuncs(tree), Helper.getStructs(tree), Helper.getEnums(tree));
|
||||
|
||||
// when / then
|
||||
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:14 Type schwurbel not defined.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionIfStructFieldTypeIsReferringToAFunction() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("struct test { a: foo; } function foo(): int { return 1; } foo();");
|
||||
var ctxAnal = new ContextAnalysis(Helper.getFuncs(tree), Helper.getStructs(tree), Helper.getEnums(tree));
|
||||
|
||||
// when / then
|
||||
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
|
||||
assertEquals("Error in line 1:14 Type foo not defined.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionIfStructFieldNameIsDuplicated() {
|
||||
// given
|
||||
var tree = Helper.prepareParser("struct test { a: int; a: bool; } function foo(): int { return 1; } foo();");
|
||||
var getDefs = new GetDefinitions(new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||
|
||||
// when / then
|
||||
var e = assertThrows(RuntimeException.class, () -> getDefs.visit(tree));
|
||||
assertEquals("Error in line 1:22 Duplicate struct field a in struct test.", e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -12,10 +12,11 @@ public class StructFieldAccessTest {
|
||||
ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { return str.a; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
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:53 Variable with name str not defined.", e.getMessage());
|
||||
assertEquals("Error in line 1:53 Variable or parameter with name \"str\" not defined.", e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -23,9 +24,10 @@ public class StructFieldAccessTest {
|
||||
ParseTree tree = Helper.prepareParser("struct test { a: int; } function foo(): int { let x: int = 0; return x.a; } foo();");
|
||||
var funcs = Helper.getFuncs(tree);
|
||||
var structs = Helper.getStructs(tree);
|
||||
ContextAnalysis ctxAnal = new ContextAnalysis(funcs, structs);
|
||||
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:69 Variable must reference a struct but references int.", e.getMessage());
|
||||
assertEquals("Error in line 1:69 Variable or parameter must reference a struct but references int.", e.getMessage());
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user