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>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>de.hsrm.compiler.Klang.Klang</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
|
||||
@@ -355,12 +355,15 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
||||
}
|
||||
|
||||
var enumValueName = path.get(0);
|
||||
if (Arrays.stream(enumDef.enums).noneMatch(e -> e.equals(enumValueName))) {
|
||||
var error = "Unknown enum value " + enumValueName + " of enum " + enumDef.name + ".";
|
||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||
}
|
||||
var enumValue = Arrays.stream(enumDef.enums)
|
||||
.filter(e -> e.value.equals(enumValueName))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> {
|
||||
var error = "Unknown enum value " + enumValueName + " of enum " + enumDef.name + ".";
|
||||
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.line = line;
|
||||
enumAccessExpression.col = col;
|
||||
|
||||
@@ -107,20 +107,26 @@ public class GetDefinitions extends KlangBaseVisitor<Node> {
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
var currentEnumField = ctx.IDENT(i);
|
||||
var currentEnumFieldName = currentEnumField.getText();
|
||||
if (enumFields.contains(currentEnumFieldName)) {
|
||||
var line = currentEnumField.getSymbol().getLine();
|
||||
var col = currentEnumField.getSymbol().getCharPositionInLine();
|
||||
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);
|
||||
}
|
||||
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.col = ctx.start.getCharPositionInLine();
|
||||
enumDef.type = new NamedType(enumName);
|
||||
|
||||
@@ -5,9 +5,9 @@ import de.hsrm.compiler.Klang.visitors.Visitor;
|
||||
public class EnumDefinition extends Node {
|
||||
|
||||
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.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;
|
||||
|
||||
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) {
|
||||
public EnumAccessExpression(
|
||||
String enumName,
|
||||
String enumValueName,
|
||||
EnumValue enumValue
|
||||
) {
|
||||
this.enumName = enumName;
|
||||
this.enumValueName = enumValueName;
|
||||
this.enumValue = enumValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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;
|
||||
@@ -33,4 +35,8 @@ public class BooleanType extends PrimitiveType {
|
||||
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;
|
||||
|
||||
import de.hsrm.compiler.Klang.Value;
|
||||
|
||||
public class FloatType extends NumericType {
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@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;
|
||||
@@ -37,4 +39,9 @@ public class IntegerType extends NumericType {
|
||||
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;
|
||||
|
||||
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 String name;
|
||||
|
||||
@@ -21,6 +28,11 @@ public class NamedType extends Type {
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
@@ -28,6 +30,11 @@ public class NullType extends Type {
|
||||
return that;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean valuesEqual(Value a, Value b) {
|
||||
return a.asObject() == b.asObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrimitiveType() {
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
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 {
|
||||
|
||||
@@ -34,6 +39,7 @@ public abstract class Type {
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -46,25 +46,11 @@ 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);
|
||||
var lhs = e.lhs.welcome(this);
|
||||
var rhs = e.rhs.welcome(this);
|
||||
var combinedType = lhs.type.combine(rhs.type);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
return new Value(combinedType.valuesEqual(lhs, rhs), Type.getBooleanType());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -471,6 +457,11 @@ public class EvalVisitor implements Visitor<Value> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(EnumValue e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(StructDefinition e) {
|
||||
// We get these from a previous visitor
|
||||
@@ -498,7 +489,7 @@ public class EvalVisitor implements Visitor<Value> {
|
||||
|
||||
@Override
|
||||
public Value visit(EnumAccessExpression e) {
|
||||
return null;
|
||||
return new Value(e.enumValueName, e.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -567,6 +567,13 @@ public class GenASM implements Visitor<Void> {
|
||||
|
||||
@Override
|
||||
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;
|
||||
this.currentFunctionStartLabel = lblStart;
|
||||
this.currentFunctionParams = e.parameters;
|
||||
@@ -744,7 +751,8 @@ public class GenASM implements Visitor<Void> {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -769,7 +777,7 @@ public class GenASM implements Visitor<Void> {
|
||||
|
||||
@Override
|
||||
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
|
||||
return null;
|
||||
}
|
||||
@@ -779,6 +787,11 @@ public class GenASM implements Visitor<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(EnumValue e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructDefinition e) {
|
||||
// We get these from a previous visitor
|
||||
@@ -819,6 +832,9 @@ public class GenASM implements Visitor<Void> {
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -239,6 +239,11 @@ class GetVars implements Visitor<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(EnumValue e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructDefinition e) {
|
||||
return null;
|
||||
|
||||
@@ -387,18 +387,24 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
||||
public Void visit(EnumDefinition e) {
|
||||
ex.write("enum " + e.name + " { ");
|
||||
var first = true;
|
||||
for(var enumName: e.enums) {
|
||||
for(var enumValue: e.enums) {
|
||||
if (!first) {
|
||||
ex.write(", ");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
ex.write(enumName);
|
||||
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 + " {");
|
||||
|
||||
@@ -38,6 +38,7 @@ public interface Visitor<R> {
|
||||
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(MemberAccessExpression e);
|
||||
|
||||
Reference in New Issue
Block a user