Skip to content

Commit a31d2d1

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

3 files changed

Lines changed: 150 additions & 3 deletions

File tree

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: 146 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,116 @@ 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+
return false;
1032+
}
1033+
1034+
template <typename T> bool check(ComparisonExpression::Comparison comp1, const T &value1, const T &value2low, const T &value2high)
1035+
{
1036+
return false; // TODO
1037+
}
1038+
1039+
template <typename T> bool check(const T &value1low, const T &value1high, const T &value2low, const T &value2high)
1040+
{
1041+
return false; // TODO
1042+
}
1043+
1044+
} // namespace overlap
1045+
1046+
bool CaseStatement::ComparisonWhenCondition::overlaps(const WhenCondition *cond) const
1047+
{
1048+
const ComparisonWhenCondition *cwhen = dynamic_cast<const ComparisonWhenCondition *>(cond);
1049+
const RangeWhenCondition *rwhen = dynamic_cast<const RangeWhenCondition *>(cond);
1050+
if (cwhen != nullptr) {
1051+
if (expr->type->is_equivalent(TYPE_NUMBER)) {
1052+
return overlap::check(comp, expr->eval_number(), cwhen->comp, cwhen->expr->eval_number());
1053+
} else if (expr->type->is_equivalent(TYPE_STRING)) {
1054+
return overlap::check(comp, expr->eval_string(), cwhen->comp, cwhen->expr->eval_string());
1055+
} else {
1056+
fprintf(stderr, "compiler internal error");
1057+
abort();
1058+
}
1059+
} else if (rwhen != nullptr) {
1060+
if (expr->type->is_equivalent(TYPE_NUMBER)) {
1061+
return overlap::check(comp, expr->eval_number(), rwhen->low_expr->eval_number(), rwhen->high_expr->eval_number());
1062+
} else if (expr->type->is_equivalent(TYPE_STRING)) {
1063+
return overlap::check(comp, expr->eval_string(), rwhen->low_expr->eval_string(), rwhen->high_expr->eval_string());
1064+
} else {
1065+
fprintf(stderr, "compiler internal error");
1066+
abort();
1067+
}
1068+
} else {
1069+
fprintf(stderr, "compiler internal error");
1070+
abort();
1071+
}
1072+
}
1073+
1074+
bool CaseStatement::RangeWhenCondition::overlaps(const WhenCondition *cond) const
1075+
{
1076+
const ComparisonWhenCondition *cwhen = dynamic_cast<const ComparisonWhenCondition *>(cond);
1077+
const RangeWhenCondition *rwhen = dynamic_cast<const RangeWhenCondition *>(cond);
1078+
if (cwhen != nullptr) {
1079+
if (low_expr->type->is_equivalent(TYPE_NUMBER)) {
1080+
return overlap::check(cwhen->comp, cwhen->expr->eval_number(), low_expr->eval_number(), high_expr->eval_number());
1081+
} else if (low_expr->type->is_equivalent(TYPE_STRING)) {
1082+
return overlap::check(cwhen->comp, cwhen->expr->eval_string(), low_expr->eval_string(), high_expr->eval_string());
1083+
} else {
1084+
fprintf(stderr, "compiler internal error");
1085+
abort();
1086+
}
1087+
} else if (rwhen != nullptr) {
1088+
if (low_expr->type->is_equivalent(TYPE_NUMBER)) {
1089+
return overlap::check(low_expr->eval_number(), high_expr->eval_number(), rwhen->low_expr->eval_number(), rwhen->high_expr->eval_number());
1090+
} else if (low_expr->type->is_equivalent(TYPE_STRING)) {
1091+
return overlap::check(low_expr->eval_string(), high_expr->eval_string(), rwhen->low_expr->eval_string(), rwhen->high_expr->eval_string());
1092+
} else {
1093+
fprintf(stderr, "compiler internal error");
1094+
abort();
1095+
}
1096+
} else {
1097+
fprintf(stderr, "compiler internal error");
1098+
abort();
1099+
}
1100+
}
1101+
9561102
static const Statement *parseImport(Scope *scope, const std::vector<Token> &tokens, std::vector<Token>::size_type &i)
9571103
{
9581104
++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)