Compare commits
5 Commits
55a5b8f54a
...
e835bd0f06
| Author | SHA1 | Date | |
|---|---|---|---|
| e835bd0f06 | |||
| ea1c04ae0a | |||
| 198bd74a47 | |||
| 0594542167 | |||
| 77fe360ffa |
5
pom.xml
5
pom.xml
@@ -72,6 +72,11 @@
|
|||||||
<descriptorRefs>
|
<descriptorRefs>
|
||||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
</descriptorRefs>
|
</descriptorRefs>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>de.hsrm.compiler.Klang.Klang</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
|
|||||||
@@ -355,12 +355,15 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var enumValueName = path.get(0);
|
var enumValueName = path.get(0);
|
||||||
if (Arrays.stream(enumDef.enums).noneMatch(e -> e.equals(enumValueName))) {
|
var enumValue = Arrays.stream(enumDef.enums)
|
||||||
|
.filter(e -> e.value.equals(enumValueName))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> {
|
||||||
var error = "Unknown enum value " + enumValueName + " of enum " + enumDef.name + ".";
|
var error = "Unknown enum value " + enumValueName + " of enum " + enumDef.name + ".";
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
}
|
});
|
||||||
|
|
||||||
var enumAccessExpression = new EnumAccessExpression(baseName, enumValueName);
|
var enumAccessExpression = new EnumAccessExpression(baseName, enumValueName, enumValue);
|
||||||
enumAccessExpression.type = enumDef.type;
|
enumAccessExpression.type = enumDef.type;
|
||||||
enumAccessExpression.line = line;
|
enumAccessExpression.line = line;
|
||||||
enumAccessExpression.col = col;
|
enumAccessExpression.col = col;
|
||||||
|
|||||||
@@ -107,20 +107,26 @@ public class GetDefinitions extends KlangBaseVisitor<Node> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IDENT() includes the enumName as the first entry, which we skip
|
// IDENT() includes the enumName as the first entry, which we skip
|
||||||
var enumFields = new LinkedHashSet<String>();
|
var enumValues = new LinkedHashMap<String, EnumValue>();
|
||||||
for (int i = 1; i < ctx.IDENT().size(); i++) {
|
for (int i = 1; i < ctx.IDENT().size(); i++) {
|
||||||
var currentEnumField = ctx.IDENT(i);
|
var currentEnumField = ctx.IDENT(i);
|
||||||
var currentEnumFieldName = currentEnumField.getText();
|
var currentEnumFieldName = currentEnumField.getText();
|
||||||
if (enumFields.contains(currentEnumFieldName)) {
|
|
||||||
var line = currentEnumField.getSymbol().getLine();
|
var line = currentEnumField.getSymbol().getLine();
|
||||||
var col = currentEnumField.getSymbol().getCharPositionInLine();
|
var col = currentEnumField.getSymbol().getCharPositionInLine();
|
||||||
|
|
||||||
|
if (enumValues.containsKey(currentEnumFieldName)) {
|
||||||
var error = " Duplicate enum value " + currentEnumFieldName + " in enum " + enumName + ".";
|
var error = " Duplicate enum value " + currentEnumFieldName + " in enum " + enumName + ".";
|
||||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||||
}
|
}
|
||||||
enumFields.add(currentEnumFieldName);
|
|
||||||
|
var enumValue = new EnumValue(currentEnumFieldName, i - 1);
|
||||||
|
enumValue.line = line;
|
||||||
|
enumValue.col = col;
|
||||||
|
|
||||||
|
enumValues.put(currentEnumFieldName, enumValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
var enumDef = new EnumDefinition(enumName, enumFields.toArray(new String[0]));
|
var enumDef = new EnumDefinition(enumName, enumValues.values().toArray(new EnumValue[0]));
|
||||||
enumDef.line = ctx.start.getLine();
|
enumDef.line = ctx.start.getLine();
|
||||||
enumDef.col = ctx.start.getCharPositionInLine();
|
enumDef.col = ctx.start.getCharPositionInLine();
|
||||||
enumDef.type = new NamedType(enumName);
|
enumDef.type = new NamedType(enumName);
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import de.hsrm.compiler.Klang.visitors.Visitor;
|
|||||||
public class EnumDefinition extends Node {
|
public class EnumDefinition extends Node {
|
||||||
|
|
||||||
public String name;
|
public String name;
|
||||||
public String[] enums;
|
public EnumValue[] enums;
|
||||||
|
|
||||||
public EnumDefinition(String name, String[] enums) {
|
public EnumDefinition(String name, EnumValue[] enums) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.enums = enums;
|
this.enums = enums;
|
||||||
}
|
}
|
||||||
|
|||||||
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,14 +1,22 @@
|
|||||||
package de.hsrm.compiler.Klang.nodes.expressions;
|
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;
|
import de.hsrm.compiler.Klang.visitors.Visitor;
|
||||||
|
|
||||||
public class EnumAccessExpression extends Expression {
|
public class EnumAccessExpression extends Expression {
|
||||||
public String enumName;
|
public String enumName;
|
||||||
public String enumValueName;
|
public String enumValueName;
|
||||||
|
public EnumValue enumValue;
|
||||||
|
|
||||||
public EnumAccessExpression(String enumName, String enumValueName) {
|
public EnumAccessExpression(
|
||||||
|
String enumName,
|
||||||
|
String enumValueName,
|
||||||
|
EnumValue enumValue
|
||||||
|
) {
|
||||||
this.enumName = enumName;
|
this.enumName = enumName;
|
||||||
this.enumValueName = enumValueName;
|
this.enumValueName = enumValueName;
|
||||||
|
this.enumValue = enumValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package de.hsrm.compiler.Klang.types;
|
package de.hsrm.compiler.Klang.types;
|
||||||
|
|
||||||
|
import de.hsrm.compiler.Klang.Value;
|
||||||
|
|
||||||
public class BooleanType extends PrimitiveType {
|
public class BooleanType extends PrimitiveType {
|
||||||
|
|
||||||
private static BooleanType instance = null;
|
private static BooleanType instance = null;
|
||||||
@@ -33,4 +35,8 @@ public class BooleanType extends PrimitiveType {
|
|||||||
throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName());
|
throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean valuesEqual(Value a, Value b) {
|
||||||
|
return a.asBoolean() == b.asBoolean();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package de.hsrm.compiler.Klang.types;
|
package de.hsrm.compiler.Klang.types;
|
||||||
|
|
||||||
|
import de.hsrm.compiler.Klang.Value;
|
||||||
|
|
||||||
public class FloatType extends NumericType {
|
public class FloatType extends NumericType {
|
||||||
|
|
||||||
private static FloatType instance = null;
|
private static FloatType instance = null;
|
||||||
@@ -37,4 +39,8 @@ public class FloatType extends NumericType {
|
|||||||
throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName());
|
throw new RuntimeException("Type missmatch: 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;
|
package de.hsrm.compiler.Klang.types;
|
||||||
|
|
||||||
|
import de.hsrm.compiler.Klang.Value;
|
||||||
|
|
||||||
public class IntegerType extends NumericType {
|
public class IntegerType extends NumericType {
|
||||||
|
|
||||||
private static IntegerType instance = null;
|
private static IntegerType instance = null;
|
||||||
@@ -37,4 +39,9 @@ public class IntegerType extends NumericType {
|
|||||||
throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName());
|
throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean valuesEqual(Value a, Value b) {
|
||||||
|
return a.asInteger() == b.asInteger();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,12 @@
|
|||||||
package de.hsrm.compiler.Klang.types;
|
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 class NamedType extends Type {
|
public class NamedType extends Type {
|
||||||
public String name;
|
public String name;
|
||||||
|
|
||||||
@@ -21,6 +28,11 @@ public class NamedType extends Type {
|
|||||||
throw new RuntimeException("Type mismatch: cannot combine " + getName() + " and " + that.getName());
|
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
|
@Override
|
||||||
public boolean isPrimitiveType() {
|
public boolean isPrimitiveType() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package de.hsrm.compiler.Klang.types;
|
package de.hsrm.compiler.Klang.types;
|
||||||
|
|
||||||
|
import de.hsrm.compiler.Klang.Value;
|
||||||
|
|
||||||
public class NullType extends Type {
|
public class NullType extends Type {
|
||||||
|
|
||||||
private static NullType instance = null;
|
private static NullType instance = null;
|
||||||
@@ -28,6 +30,11 @@ public class NullType extends Type {
|
|||||||
return that;
|
return that;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean valuesEqual(Value a, Value b) {
|
||||||
|
return a.asObject() == b.asObject();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPrimitiveType() {
|
public boolean isPrimitiveType() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
package de.hsrm.compiler.Klang.types;
|
package de.hsrm.compiler.Klang.types;
|
||||||
|
|
||||||
import java.util.Set;
|
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 {
|
public abstract class Type {
|
||||||
|
|
||||||
@@ -34,6 +39,7 @@ public abstract class Type {
|
|||||||
|
|
||||||
public abstract String getName();
|
public abstract String getName();
|
||||||
public abstract Type combine(Type that);
|
public abstract Type combine(Type that);
|
||||||
|
public abstract boolean valuesEqual(Value a, Value b);
|
||||||
public abstract boolean isPrimitiveType();
|
public abstract boolean isPrimitiveType();
|
||||||
public abstract boolean isNumericType();
|
public abstract boolean isNumericType();
|
||||||
}
|
}
|
||||||
@@ -46,25 +46,11 @@ public class EvalVisitor implements Visitor<Value> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Value visit(EqualityExpression e) {
|
public Value visit(EqualityExpression e) {
|
||||||
Value lhs = e.lhs.welcome(this);
|
var lhs = e.lhs.welcome(this);
|
||||||
Value rhs = e.rhs.welcome(this);
|
var rhs = e.rhs.welcome(this);
|
||||||
Type resultType = Type.getBooleanType();
|
var combinedType = lhs.type.combine(rhs.type);
|
||||||
Type combineType = lhs.type.combine(rhs.type);
|
|
||||||
|
|
||||||
switch(combineType.getName()) {
|
return new Value(combinedType.valuesEqual(lhs, rhs), Type.getBooleanType());
|
||||||
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
|
@Override
|
||||||
@@ -471,6 +457,11 @@ public class EvalVisitor implements Visitor<Value> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value visit(EnumValue e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Value visit(StructDefinition e) {
|
public Value visit(StructDefinition e) {
|
||||||
// We get these from a previous visitor
|
// We get these from a previous visitor
|
||||||
@@ -498,7 +489,7 @@ public class EvalVisitor implements Visitor<Value> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Value visit(EnumAccessExpression e) {
|
public Value visit(EnumAccessExpression e) {
|
||||||
return null;
|
return new Value(e.enumValueName, e.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -567,6 +567,13 @@ public class GenASM implements Visitor<Void> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visit(FunctionDefinition e) {
|
public Void visit(FunctionDefinition e) {
|
||||||
|
// If the user chooses "main" as one of his function names then
|
||||||
|
// rename it and hope that they didn't use the renamed function name
|
||||||
|
// as well :D
|
||||||
|
if (e.name.equals("main")) {
|
||||||
|
e.name = "main_by_user";
|
||||||
|
}
|
||||||
|
|
||||||
int lblStart = ++lCount;
|
int lblStart = ++lCount;
|
||||||
this.currentFunctionStartLabel = lblStart;
|
this.currentFunctionStartLabel = lblStart;
|
||||||
this.currentFunctionParams = e.parameters;
|
this.currentFunctionParams = e.parameters;
|
||||||
@@ -744,7 +751,8 @@ public class GenASM implements Visitor<Void> {
|
|||||||
asm.add("q", stackStartOffset, "%rsp");
|
asm.add("q", stackStartOffset, "%rsp");
|
||||||
}
|
}
|
||||||
|
|
||||||
asm.call(e.name);
|
// We rename a function name if it is "main"
|
||||||
|
asm.call(e.name.equals("main") ? "main_by_user": e.name);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -769,7 +777,7 @@ public class GenASM implements Visitor<Void> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visit(Parameter e) {
|
public Void visit(Parameter e) {
|
||||||
// The work for a paremeter node is implement
|
// The work for a parameter node is implement
|
||||||
// in the function definition visitor
|
// in the function definition visitor
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -779,6 +787,11 @@ public class GenASM implements Visitor<Void> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visit(EnumValue e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visit(StructDefinition e) {
|
public Void visit(StructDefinition e) {
|
||||||
// We get these from a previous visitor
|
// We get these from a previous visitor
|
||||||
@@ -819,6 +832,9 @@ public class GenASM implements Visitor<Void> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visit(EnumAccessExpression e) {
|
public Void visit(EnumAccessExpression e) {
|
||||||
|
// Since the access to an enum simply results in an integer (i.e. the index
|
||||||
|
// of the enum value), we can just let IntegerExpression handle the expected behaviour.
|
||||||
|
new IntegerExpression(e.enumValue.index).welcome(this);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -239,6 +239,11 @@ class GetVars implements Visitor<Void> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visit(EnumValue e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visit(StructDefinition e) {
|
public Void visit(StructDefinition e) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -387,18 +387,24 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
|||||||
public Void visit(EnumDefinition e) {
|
public Void visit(EnumDefinition e) {
|
||||||
ex.write("enum " + e.name + " { ");
|
ex.write("enum " + e.name + " { ");
|
||||||
var first = true;
|
var first = true;
|
||||||
for(var enumName: e.enums) {
|
for(var enumValue: e.enums) {
|
||||||
if (!first) {
|
if (!first) {
|
||||||
ex.write(", ");
|
ex.write(", ");
|
||||||
} else {
|
} else {
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
ex.write(enumName);
|
enumValue.welcome(this);
|
||||||
}
|
}
|
||||||
ex.write(" }");
|
ex.write(" }");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visit(EnumValue e) {
|
||||||
|
ex.write(e.value);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visit(StructDefinition e) {
|
public Void visit(StructDefinition e) {
|
||||||
ex.write("struct " + e.name + " {");
|
ex.write("struct " + e.name + " {");
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public interface Visitor<R> {
|
|||||||
R visit(Program e);
|
R visit(Program e);
|
||||||
R visit(Parameter e);
|
R visit(Parameter e);
|
||||||
R visit(EnumDefinition e);
|
R visit(EnumDefinition e);
|
||||||
|
R visit(EnumValue e);
|
||||||
R visit(StructDefinition e);
|
R visit(StructDefinition e);
|
||||||
R visit(StructField e);
|
R visit(StructField e);
|
||||||
R visit(MemberAccessExpression e);
|
R visit(MemberAccessExpression e);
|
||||||
|
|||||||
Reference in New Issue
Block a user