Skip to content

Commit

Permalink
Closes #147 (removed ranged cases)
Browse files Browse the repository at this point in the history
  • Loading branch information
JarrettBillingsley committed Nov 9, 2014
1 parent 9ae3a97 commit 117f0a9
Show file tree
Hide file tree
Showing 5 changed files with 15 additions and 184 deletions.
2 changes: 1 addition & 1 deletion crocgrammar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ SwitchStatement:
switch Identifier? '(' Expression ')' { List(CaseStatement) DefaultStatement? }

CaseStatement:
case (List(Expression) | (Expression '..' Expression)) : Statement*
case List(Expression) : Statement*

DefaultStatement:
default : Statement*
Expand Down
5 changes: 1 addition & 4 deletions src/croc/compiler/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -824,14 +824,11 @@ namespace croc
struct CaseStmt : public Statement
{
DArray<CaseCond> conditions;
Expression* highRange;
Statement* code;

CaseStmt(CompileLoc location, CompileLoc endLocation, DArray<CaseCond> conditions, Expression* highRange,
Statement* code) :
CaseStmt(CompileLoc location, CompileLoc endLocation, DArray<CaseCond> conditions, Statement* code) :
Statement(location, endLocation, AstTag_CaseStmt),
conditions(conditions),
highRange(highRange),
code(code)
{}
};
Expand Down
52 changes: 11 additions & 41 deletions src/croc/compiler/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -791,39 +791,14 @@ namespace croc

for(auto caseStmt: s->cases)
{
if(caseStmt->highRange)
for(auto &c: caseStmt->conditions)
{
auto &c = caseStmt->conditions[0];
auto lo = c.exp;
auto hi = caseStmt->highRange;

fb->dup();
visit(lo);
fb->toSource(lo->endLocation);

auto jmp1 = fb->codeCmp(lo->location, Comparison_LT);

fb->dup();
visit(hi);
fb->toSource(hi->endLocation);

auto jmp2 = fb->codeCmp(hi->endLocation, Comparison_GT);

c.dynJump = fb->makeJump(hi->endLocation);
fb->patchJumpToHere(jmp1);
fb->patchJumpToHere(jmp2);
}
else
{
for(auto &c: caseStmt->conditions)
if(!c.exp->isConstant())
{
if(!c.exp->isConstant())
{
fb->dup();
visit(c.exp);
fb->toSource(c.exp->endLocation);
c.dynJump = fb->codeSwitchCmp(c.exp->endLocation);
}
fb->dup();
visit(c.exp);
fb->toSource(c.exp->endLocation);
c.dynJump = fb->codeSwitchCmp(c.exp->endLocation);
}
}
}
Expand All @@ -845,17 +820,12 @@ namespace croc

CaseStmt* Codegen::visit(CaseStmt* s)
{
if(s->highRange)
fb->patchJumpToHere(s->conditions[0].dynJump);
else
for(auto &c: s->conditions)
{
for(auto &c: s->conditions)
{
if(c.exp->isConstant())
fb->addCase(c.exp->location, c.exp);
else
fb->patchJumpToHere(c.dynJump);
}
if(c.exp->isConstant())
fb->addCase(c.exp->location, c.exp);
else
fb->patchJumpToHere(c.dynJump);
}

visit(s->code);
Expand Down
10 changes: 2 additions & 8 deletions src/croc/compiler/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1424,14 +1424,8 @@ namespace croc

List<CaseCond> conditions(c);
conditions.add(CaseCond(parseExpression()));
Expression* highRange = nullptr;

if(l.type() == Token::DotDot)
{
l.next();
highRange = parseExpression();
}
else while(l.type() == Token::Comma)
while(l.type() == Token::Comma)
{
l.next();
conditions.add(CaseCond(parseExpression()));
Expand All @@ -1447,7 +1441,7 @@ namespace croc
auto endLocation = l.loc();

auto code = new(c) ScopeStmt(new(c) BlockStmt(location, endLocation, statements.toArray()));
return new(c) CaseStmt(location, endLocation, conditions.toArray(), highRange, code);
return new(c) CaseStmt(location, endLocation, conditions.toArray(), code);
}

DefaultStmt* Parser::parseDefaultStmt()
Expand Down
130 changes: 0 additions & 130 deletions src/croc/compiler/semantic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -587,143 +587,13 @@ namespace croc
{
VISIT(s->condition);
VISIT_ARR(s->cases);

for(auto rc: s->cases)
{
if(rc->highRange == nullptr || !rc->conditions[0].exp->isConstant() || !rc->highRange->isConstant())
continue;

auto lo = rc->conditions[0].exp;
auto hi = rc->highRange;

// this might not work for ranges using absurdly large numbers. fuh.
if(lo->isNum() && hi->isNum())
{
auto loVal = lo->asFloat();
auto hiVal = hi->asFloat();

for(auto c2: s->cases)
{
if(rc == c2)
continue;

if(c2->highRange != nullptr)
{
auto lo2 = c2->conditions[0].exp;
auto hi2 = c2->highRange;

if((lo2->isConstant() && hi2->isConstant()) && lo2->isNum() && hi2->isNum())
{
auto lo2Val = lo2->asFloat();
auto hi2Val = hi2->asFloat();

if(loVal == lo2Val ||
(loVal < lo2Val && (lo2Val - loVal) <= (hiVal - loVal)) ||
(loVal > lo2Val && (loVal - lo2Val) <= (hi2Val - lo2Val)))
c.semException(lo2->location,
"case range overlaps range at %s(%" CROC_SIZE_T_FORMAT ":%" CROC_SIZE_T_FORMAT ")",
lo->location.file.ptr, lo->location.line, lo->location.col);
}
}
else
{
for(auto cond: c2->conditions)
{
if(cond.exp->isConstant() &&
((cond.exp->isInt() && cond.exp->asInt() >= loVal && cond.exp->asInt() <= hiVal) ||
(cond.exp->isFloat() && cond.exp->asFloat() >= loVal && cond.exp->asFloat() <= hiVal)))
c.semException(cond.exp->location,
"case value overlaps range at %s(%" CROC_SIZE_T_FORMAT ":%" CROC_SIZE_T_FORMAT ")",
lo->location.file.ptr, lo->location.line, lo->location.col);
}
}
}
}
else if(lo->isString() && hi->isString())
{
auto loVal = lo->asString();
auto hiVal = hi->asString();

for(auto c2: s->cases)
{
if(rc == c2)
continue;

if(c2->highRange != nullptr)
{
auto lo2 = c2->conditions[0].exp;
auto hi2 = c2->highRange;

if((lo2->isConstant() && hi2->isConstant()) && (lo2->isString() && hi2->isString()))
{
auto lo2Val = lo2->asString();
auto hi2Val = hi2->asString();

if( (loVal >= lo2Val && loVal <= hi2Val) ||
(hiVal >= lo2Val && hiVal <= hi2Val) ||
(lo2Val >= loVal && lo2Val <= hiVal) ||
(hi2Val >= loVal && hi2Val <= hiVal))
c.semException(lo2->location,
"case range overlaps range at %s(%" CROC_SIZE_T_FORMAT ":%" CROC_SIZE_T_FORMAT ")",
lo->location.file.ptr, lo->location.line, lo->location.col);
}
}
else
{
for(auto cond: c2->conditions)
{
if(cond.exp->isConstant() && cond.exp->isString() &&
cond.exp->asString() >= loVal && cond.exp->asString() <= hiVal)
c.semException(cond.exp->location,
"case value overlaps range at %s(%" CROC_SIZE_T_FORMAT ":%" CROC_SIZE_T_FORMAT ")",
lo->location.file.ptr, lo->location.line, lo->location.col);
}
}
}
}
}

COND_VISIT(s->caseDefault);
return s;
}

CaseStmt* Semantic::visit(CaseStmt* s)
{
VISIT_ARR_FIELD(s->conditions, exp);

if(s->highRange)
{
VISIT(s->highRange);

auto lo = s->conditions[0].exp;
auto hi = s->highRange;

if(lo->isConstant() && hi->isConstant())
{
if(lo->isInt() && hi->isInt())
{
if(lo->asInt() > hi->asInt())
c.semException(lo->location, "Invalid case range (low is greater than high)");
else if(lo->asInt() == hi->asInt())
s->highRange = nullptr;
}
else if(lo->isNum() && hi->isNum())
{
if(lo->asFloat() > hi->asFloat())
c.semException(lo->location, "Invalid case range (low is greater than high)");
else if(lo->asFloat() == hi->asFloat())
s->highRange = nullptr;
}
else if(lo->isString() && hi->isString())
{
if(lo->asString() > hi->asString())
c.semException(lo->location, "Invalid case range (low is greater than high)");
else if(lo->asString() == hi->asString())
s->highRange = nullptr;
}
}
}

VISIT(s->code);
return s;
}
Expand Down

0 comments on commit 117f0a9

Please sign in to comment.