Skip to content

Commit d2d6559

Browse files
committed
check case conditions for overlaps
1 parent debcc6a commit d2d6559

File tree

3 files changed

+149
-3
lines changed

3 files changed

+149
-3
lines changed

ast.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,13 +911,15 @@ class CaseStatement: public Statement {
911911
class WhenCondition {
912912
public:
913913
virtual ~WhenCondition() {}
914+
virtual bool overlaps(const WhenCondition *cond) const = 0;
914915
virtual void generate(Emitter &emitter) const = 0;
915916
};
916917
class ComparisonWhenCondition: public WhenCondition {
917918
public:
918919
ComparisonWhenCondition(ComparisonExpression::Comparison comp, const Expression *expr): comp(comp), expr(expr) {}
919920
ComparisonExpression::Comparison comp;
920921
const Expression *expr;
922+
virtual bool overlaps(const WhenCondition *cond) const;
921923
virtual void generate(Emitter &emitter) const;
922924
private:
923925
ComparisonWhenCondition(const ComparisonWhenCondition &);
@@ -928,6 +930,7 @@ class CaseStatement: public Statement {
928930
RangeWhenCondition(const Expression *low_expr, const Expression *high_expr): low_expr(low_expr), high_expr(high_expr) {}
929931
const Expression *low_expr;
930932
const Expression *high_expr;
933+
virtual bool overlaps(const WhenCondition *cond) const;
931934
virtual void generate(Emitter &emitter) const;
932935
private:
933936
RangeWhenCondition(const RangeWhenCondition &);

parser.cpp

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,18 @@ static const Statement *parseCaseStatement(Scope *scope, const std::vector<Token
892892
error(2086, tokens[i], "WHEN condition must be constant");
893893
}
894894
const CaseStatement::WhenCondition *cond = new CaseStatement::ComparisonWhenCondition(comparisonFromToken(op), when);
895+
for (auto clause: clauses) {
896+
for (auto c: clause.first) {
897+
if (cond->overlaps(c)) {
898+
error(2106, tokens[i], "overlapping case condition");
899+
}
900+
}
901+
}
902+
for (auto c: conditions) {
903+
if (cond->overlaps(c)) {
904+
error(2107, tokens[i], "overlapping case condition");
905+
}
906+
}
895907
conditions.push_back(cond);
896908
break;
897909
}
@@ -913,9 +925,33 @@ static const Statement *parseCaseStatement(Scope *scope, const std::vector<Token
913925
error(2090, tokens[i], "WHEN condition must be constant");
914926
}
915927
const CaseStatement::WhenCondition *cond = new CaseStatement::RangeWhenCondition(when, when2);
928+
for (auto clause: clauses) {
929+
for (auto c: clause.first) {
930+
if (cond->overlaps(c)) {
931+
error(2108, tokens[i], "overlapping case condition");
932+
}
933+
}
934+
}
935+
for (auto c: conditions) {
936+
if (cond->overlaps(c)) {
937+
error(2109, tokens[i], "overlapping case condition");
938+
}
939+
}
916940
conditions.push_back(cond);
917941
} else {
918942
const CaseStatement::WhenCondition *cond = new CaseStatement::ComparisonWhenCondition(ComparisonExpression::EQ, when);
943+
for (auto clause: clauses) {
944+
for (auto c: clause.first) {
945+
if (cond->overlaps(c)) {
946+
error(2110, tokens[i], "overlapping case condition");
947+
}
948+
}
949+
}
950+
for (auto c: conditions) {
951+
if (cond->overlaps(c)) {
952+
error(2111, tokens[i], "overlapping case condition");
953+
}
954+
}
919955
conditions.push_back(cond);
920956
}
921957
break;
@@ -953,6 +989,115 @@ static const Statement *parseCaseStatement(Scope *scope, const std::vector<Token
953989
return new CaseStatement(expr, clauses);
954990
}
955991

992+
namespace overlap {
993+
994+
static bool operator==(const Number &x, const Number &y) { return number_is_equal(x, y); }
995+
static bool operator!=(const Number &x, const Number &y) { return number_is_not_equal(x, y); }
996+
static bool operator<(const Number &x, const Number &y) { return number_is_less(x, y); }
997+
static bool operator>(const Number &x, const Number &y) { return number_is_greater(x, y); }
998+
static bool operator<=(const Number &x, const Number &y) { return number_is_less_equal(x, y); }
999+
static bool operator>=(const Number &x, const Number &y) { return number_is_greater_equal(x, y); }
1000+
1001+
template <typename T> bool check(ComparisonExpression::Comparison comp1, const T &value1, ComparisonExpression::Comparison comp2, const T &value2)
1002+
{
1003+
switch (comp1) {
1004+
case ComparisonExpression::EQ:
1005+
switch (comp2) {
1006+
case ComparisonExpression::EQ:
1007+
return value1 == value2;
1008+
case ComparisonExpression::NE:
1009+
return value1 != value2;
1010+
case ComparisonExpression::LT:
1011+
return value1 < value2;
1012+
case ComparisonExpression::GT:
1013+
return value1 > value2;
1014+
case ComparisonExpression::LE:
1015+
return value1 <= value2;
1016+
case ComparisonExpression::GE:
1017+
return value1 >= value2;
1018+
}
1019+
break;
1020+
case ComparisonExpression::NE:
1021+
return false; // TODO
1022+
case ComparisonExpression::LT:
1023+
return false; // TODO
1024+
case ComparisonExpression::GT:
1025+
return false; // TODO
1026+
case ComparisonExpression::LE:
1027+
return false; // TODO
1028+
case ComparisonExpression::GE:
1029+
return false; // TODO
1030+
}
1031+
}
1032+
1033+
template <typename T> bool check(ComparisonExpression::Comparison comp1, const T &value1, const T &value2low, const T &value2high)
1034+
{
1035+
return false; // TODO
1036+
}
1037+
1038+
template <typename T> bool check(const T &value1low, const T &value1high, const T &value2low, const T &value2high)
1039+
{
1040+
return false; // TODO
1041+
}
1042+
1043+
} // namespace overlap
1044+
1045+
bool CaseStatement::ComparisonWhenCondition::overlaps(const WhenCondition *cond) const
1046+
{
1047+
const ComparisonWhenCondition *cwhen = dynamic_cast<const ComparisonWhenCondition *>(cond);
1048+
const RangeWhenCondition *rwhen = dynamic_cast<const RangeWhenCondition *>(cond);
1049+
if (cwhen != nullptr) {
1050+
if (expr->type->is_equivalent(TYPE_NUMBER)) {
1051+
return overlap::check(comp, expr->eval_number(), cwhen->comp, cwhen->expr->eval_number());
1052+
} else if (expr->type->is_equivalent(TYPE_STRING)) {
1053+
return overlap::check(comp, expr->eval_string(), cwhen->comp, cwhen->expr->eval_string());
1054+
} else {
1055+
fprintf(stderr, "compiler internal error");
1056+
abort();
1057+
}
1058+
} else if (rwhen != nullptr) {
1059+
if (expr->type->is_equivalent(TYPE_NUMBER)) {
1060+
return overlap::check(comp, expr->eval_number(), rwhen->low_expr->eval_number(), rwhen->high_expr->eval_number());
1061+
} else if (expr->type->is_equivalent(TYPE_STRING)) {
1062+
return overlap::check(comp, expr->eval_string(), rwhen->low_expr->eval_string(), rwhen->high_expr->eval_string());
1063+
} else {
1064+
fprintf(stderr, "compiler internal error");
1065+
abort();
1066+
}
1067+
} else {
1068+
fprintf(stderr, "compiler internal error");
1069+
abort();
1070+
}
1071+
}
1072+
1073+
bool CaseStatement::RangeWhenCondition::overlaps(const WhenCondition *cond) const
1074+
{
1075+
const ComparisonWhenCondition *cwhen = dynamic_cast<const ComparisonWhenCondition *>(cond);
1076+
const RangeWhenCondition *rwhen = dynamic_cast<const RangeWhenCondition *>(cond);
1077+
if (cwhen != nullptr) {
1078+
if (low_expr->type->is_equivalent(TYPE_NUMBER)) {
1079+
return overlap::check(cwhen->comp, cwhen->expr->eval_number(), low_expr->eval_number(), high_expr->eval_number());
1080+
} else if (low_expr->type->is_equivalent(TYPE_STRING)) {
1081+
return overlap::check(cwhen->comp, cwhen->expr->eval_string(), low_expr->eval_string(), high_expr->eval_string());
1082+
} else {
1083+
fprintf(stderr, "compiler internal error");
1084+
abort();
1085+
}
1086+
} else if (rwhen != nullptr) {
1087+
if (low_expr->type->is_equivalent(TYPE_NUMBER)) {
1088+
return overlap::check(low_expr->eval_number(), high_expr->eval_number(), rwhen->low_expr->eval_number(), rwhen->high_expr->eval_number());
1089+
} else if (low_expr->type->is_equivalent(TYPE_STRING)) {
1090+
return overlap::check(low_expr->eval_string(), high_expr->eval_string(), rwhen->low_expr->eval_string(), rwhen->high_expr->eval_string());
1091+
} else {
1092+
fprintf(stderr, "compiler internal error");
1093+
abort();
1094+
}
1095+
} else {
1096+
fprintf(stderr, "compiler internal error");
1097+
abort();
1098+
}
1099+
}
1100+
9561101
static const Statement *parseImport(Scope *scope, const std::vector<Token> &tokens, std::vector<Token>::size_type &i)
9571102
{
9581103
++i;

t/case4.simple

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
% TODO
2-
31
VAR a: Number
42

53
CASE a
64
WHEN 1 DO
75
WHEN 1 DO
86
END CASE
97

10-
%! overlapping when
8+
%! overlapping case

0 commit comments

Comments
 (0)