feature/char-support #3

Merged
nitrix merged 5 commits from feature/char-support into master 2023-03-24 17:03:24 +01:00
4 changed files with 104 additions and 70 deletions
Showing only changes of commit 259ac49981 - Show all commits

View File

@@ -427,18 +427,21 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
@Override
public Node visitEqualityExpression(KlangParser.EqualityExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
var lhs = visit(ctx.lhs);
var rhs = visit(ctx.rhs);
var line = ctx.start.getLine();
var col = ctx.start.getCharPositionInLine();
// Since there are countless combinations of types that are comparable
// to each other we use Type::combine to figure out if two types
// may be compared to each other
try {
lhs.type.combine(rhs.type);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
}
EqualityExpression result = new EqualityExpression((Expression) lhs, (Expression) rhs);
var result = new EqualityExpression((Expression) lhs, (Expression) rhs);
result.type = Type.getBooleanType();
result.line = line;
result.col = col;
@@ -447,18 +450,17 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
@Override
public Node visitNotEqualityExpression(KlangParser.NotEqualityExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
var lhs = visit(ctx.lhs);
var rhs = visit(ctx.rhs);
var line = ctx.start.getLine();
var col = ctx.start.getCharPositionInLine();
try {
lhs.type.combine(rhs.type);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
if (!lhs.type.isPrimitiveType() || !rhs.type.isPrimitiveType()) {
var error = "Can only compare primitives.";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
NotEqualityExpression result = new NotEqualityExpression((Expression) lhs, (Expression) rhs);
var result = new NotEqualityExpression((Expression) lhs, (Expression) rhs);
result.type = Type.getBooleanType();
result.line = line;
result.col = col;
@@ -467,20 +469,17 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
@Override
public Node visitLessThanExpression(KlangParser.LessThanExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
var lhs = visit(ctx.lhs);
var rhs = visit(ctx.rhs);
var line = ctx.start.getLine();
var col = ctx.start.getCharPositionInLine();
try {
lhs.type.combine(rhs.type);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
if (!lhs.type.isPrimitiveType() || !rhs.type.isPrimitiveType()) {
var error = "Can only compare primitives.";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
checkNumeric(lhs, rhs, line, col);
LTExpression result = new LTExpression((Expression) lhs, (Expression) rhs);
var result = new LTExpression((Expression) lhs, (Expression) rhs);
result.type = Type.getBooleanType();
result.line = line;
result.col = col;
@@ -489,23 +488,17 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
@Override
public Node visitGreaterThanExpression(KlangParser.GreaterThanExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
var lhs = visit(ctx.lhs);
var rhs = visit(ctx.rhs);
var line = ctx.start.getLine();
var col = ctx.start.getCharPositionInLine();
try {
lhs.type.combine(rhs.type);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
}
if (!lhs.type.isNumericType() || !rhs.type.isNumericType()) {
String error = "Only numeric types are allowed for this expression.";
if (!lhs.type.isPrimitiveType() || !rhs.type.isPrimitiveType()) {
var error = "Can only compare primitives.";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
GTExpression result = new GTExpression((Expression) lhs, (Expression) rhs);
var result = new GTExpression((Expression) lhs, (Expression) rhs);
result.type = Type.getBooleanType();
result.line = line;
result.col = col;
@@ -514,20 +507,17 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
@Override
public Node visitLessThanOrEqualToExpression(KlangParser.LessThanOrEqualToExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
var lhs = visit(ctx.lhs);
var rhs = visit(ctx.rhs);
var line = ctx.start.getLine();
var col = ctx.start.getCharPositionInLine();
try {
lhs.type.combine(rhs.type);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
if (!lhs.type.isPrimitiveType() || !rhs.type.isPrimitiveType()) {
var error = "Can only compare primitives.";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
checkNumeric(lhs, rhs, line, col);
LTEExpression result = new LTEExpression((Expression) lhs, (Expression) rhs);
var result = new LTEExpression((Expression) lhs, (Expression) rhs);
result.type = Type.getBooleanType();
result.line = line;
result.col = col;
@@ -536,20 +526,17 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
@Override
public Node visitGreaterThanOrEqualToExpression(KlangParser.GreaterThanOrEqualToExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
var lhs = visit(ctx.lhs);
var rhs = visit(ctx.rhs);
var line = ctx.start.getLine();
var col = ctx.start.getCharPositionInLine();
try {
lhs.type.combine(rhs.type);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
if (!lhs.type.isPrimitiveType() || !rhs.type.isPrimitiveType()) {
var error = "Can only compare primitives.";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
checkNumeric(lhs, rhs, line, col);
GTEExpression result = new GTEExpression((Expression) lhs, (Expression) rhs);
var result = new GTEExpression((Expression) lhs, (Expression) rhs);
result.type = Type.getBooleanType();
result.line = line;
result.col = col;

View File

@@ -20,11 +20,15 @@ public class CharType extends PrimitiveType {
@Override
public Type combine(Type that) {
if (!this.equals(that)) {
throw new RuntimeException("Type mismatch: cannot combine " + getName() + " and " + getName());
if (this.equals(that)) {
return this;
}
return this;
if (that.equals(Type.getIntegerType())) {
return this;
}
throw new RuntimeException("Type mismatch: cannot combine " + getName() + " and " + that.getName());
}
@Override

View File

@@ -35,6 +35,10 @@ 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 mismatch: cannot combine " + this.getName() + " and " + that.getName());
}

View File

@@ -5,6 +5,44 @@ 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
@@ -57,8 +95,9 @@ public class CharTest {
void shouldThrowIfCharIsAssignedToOtherTypedVariable() {
// given
var tree = Helper.prepareParser("""
struct foo { f: float; }
function bar(): int {
let c: int = 'c';
let c: foo = 'c';
return 1;
}
bar();
@@ -67,14 +106,14 @@ public class CharTest {
// when / then
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
assertEquals("Error in line 2:4 Type mismatch: cannot combine int and char", e.getMessage());
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(): int {
function bar(): float {
return 'c';
}
bar();
@@ -83,7 +122,7 @@ public class CharTest {
// when / then
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
assertEquals("Error in line 2:4 Type mismatch: cannot combine int and char", e.getMessage());
assertEquals("Error in line 2:4 Type mismatch: cannot combine float and char", e.getMessage());
}
@Test
@@ -109,9 +148,9 @@ public class CharTest {
void shouldThrowWhenAssigningCharToOtherTypedStructField() {
// given
var tree = Helper.prepareParser("""
struct foo { a: int; }
struct foo { a: bool; }
function bar(): void {
let x: foo = create foo(1);
let x: foo = create foo(false);
x.a = 'c';
}
bar();
@@ -120,6 +159,6 @@ public class CharTest {
// when / then
var e = assertThrows(RuntimeException.class, () -> ctxAnal.visit(tree));
assertEquals("Error in line 4:4 Type mismatch: cannot combine int and char", e.getMessage());
assertEquals("Error in line 4:4 Type mismatch: cannot combine bool and char", e.getMessage());
}
}