Commit 9cd8995f authored by Daniel Clifford's avatar Daniel Clifford Committed by Commit Bot

[Torque]: add assert(), unreachable and debug statements

- In debug builds, 'assert(<expr>)' evaluates and aborts execution
  if the provided Torque expression is false at runtime.
  assert(<expr>) supports the same set of expressions protocols
  as Toruqe's if statement, i.e. both bool values and BranchIf-
  style tests. Upon failure, the assertion prints the Torque
  source code of the failed expression, not the generated CSA
  code.
- 'unreachable' calls CSA's Unreachable() and signals to Torque
  that code execution cannot continue (i.e. its statement
  returns the 'never' type). In debug builds, the line number
  and position of the statement are printed before breaking.
- 'debug' calls CSA's DebugBreak(). In debug builds, the line
  number and position of the 'debug' are printed before breaking.

Change-Id: I4efd052536bb402c097a0d5f7be56e154b5b3676
Reviewed-on: https://chromium-review.googlesource.com/1042570
Commit-Queue: Daniel Clifford <danno@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52984}
parent 0f772171
...@@ -61,6 +61,9 @@ module array { ...@@ -61,6 +61,9 @@ module array {
a.elements = newElements; a.elements = newElements;
} }
// Double check that the array is still in fast elements mode
assert(IsFastSmiElementsKind(a.map.elements_kind));
// Copy over inserted elements. // Copy over inserted elements.
let k: Smi = actualStart; let k: Smi = actualStart;
if (insertCount > 0) { if (insertCount > 0) {
......
...@@ -141,10 +141,6 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler { ...@@ -141,10 +141,6 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
// Returns true iff number is NaN. // Returns true iff number is NaN.
// TOOD(szuend): Remove when UncheckedCasts are supported in Torque. // TOOD(szuend): Remove when UncheckedCasts are supported in Torque.
TNode<BoolT> NumberIsNaN(TNode<Number> number); TNode<BoolT> NumberIsNaN(TNode<Number> number);
// Always CSA_ASSERTs false.
// TODO(szuend): Remove when Unreachable is supported in Torque.
void AssertUnreachable() { CSA_ASSERT(this, Int32FalseConstant()); }
}; };
} // namespace internal } // namespace internal
......
...@@ -14,7 +14,6 @@ module typed_array { ...@@ -14,7 +14,6 @@ module typed_array {
extern builtin TypedArrayStoreElementFromTagged( extern builtin TypedArrayStoreElementFromTagged(
Context, JSTypedArray, Smi, Smi, Object); Context, JSTypedArray, Smi, Smi, Object);
extern macro AssertUnreachable();
extern macro NumberIsNaN(Number): bit; extern macro NumberIsNaN(Number): bit;
macro CallCompareWithDetachedCheck( macro CallCompareWithDetachedCheck(
...@@ -255,8 +254,7 @@ module typed_array { ...@@ -255,8 +254,7 @@ module typed_array {
TypedArrayQuickSort(context, array, elements_kind, 0, len, comparefn); TypedArrayQuickSort(context, array, elements_kind, 0, len, comparefn);
} }
label CastError { label CastError {
// TODO(szuend): Replace with Unreachable() when its supported in Torque. unreachable;
AssertUnreachable();
} }
return array; return array;
} }
......
...@@ -34,6 +34,9 @@ TAIL: 'tail'; ...@@ -34,6 +34,9 @@ TAIL: 'tail';
ISNT: 'isnt'; ISNT: 'isnt';
IS: 'is'; IS: 'is';
LET: 'let'; LET: 'let';
ASSERT: 'assert';
UNREACHABLE_TOKEN: 'unreachable';
DEBUG_TOKEN: 'debug';
ASSIGNMENT: '='; ASSIGNMENT: '=';
ASSIGNMENT_OPERATOR ASSIGNMENT_OPERATOR
...@@ -231,6 +234,8 @@ gotoStatement: GOTO labelReference argumentList?; ...@@ -231,6 +234,8 @@ gotoStatement: GOTO labelReference argumentList?;
handlerWithStatement: (CATCH IDENTIFIER | LABEL labelDeclaration) statementBlock; handlerWithStatement: (CATCH IDENTIFIER | LABEL labelDeclaration) statementBlock;
tryCatch: TRY statementBlock handlerWithStatement+; tryCatch: TRY statementBlock handlerWithStatement+;
diagnosticStatement: (ASSERT '(' expression ')') | UNREACHABLE_TOKEN | DEBUG_TOKEN;
statement : variableDeclarationWithInitialization ';' statement : variableDeclarationWithInitialization ';'
| helperCallStatement ';' | helperCallStatement ';'
| expressionStatement ';' | expressionStatement ';'
...@@ -239,6 +244,7 @@ statement : variableDeclarationWithInitialization ';' ...@@ -239,6 +244,7 @@ statement : variableDeclarationWithInitialization ';'
| continueStatement ';' | continueStatement ';'
| gotoStatement ';' | gotoStatement ';'
| ifStatement | ifStatement
| diagnosticStatement ';'
| whileLoop | whileLoop
| forOfLoop | forOfLoop
| forLoop | forLoop
......
...@@ -225,6 +225,11 @@ class TorqueBaseListener : public TorqueListener { ...@@ -225,6 +225,11 @@ class TorqueBaseListener : public TorqueListener {
void enterTryCatch(TorqueParser::TryCatchContext* /*ctx*/) override {} void enterTryCatch(TorqueParser::TryCatchContext* /*ctx*/) override {}
void exitTryCatch(TorqueParser::TryCatchContext* /*ctx*/) override {} void exitTryCatch(TorqueParser::TryCatchContext* /*ctx*/) override {}
void enterDiagnosticStatement(
TorqueParser::DiagnosticStatementContext* /*ctx*/) override {}
void exitDiagnosticStatement(
TorqueParser::DiagnosticStatementContext* /*ctx*/) override {}
void enterStatement(TorqueParser::StatementContext* /*ctx*/) override {} void enterStatement(TorqueParser::StatementContext* /*ctx*/) override {}
void exitStatement(TorqueParser::StatementContext* /*ctx*/) override {} void exitStatement(TorqueParser::StatementContext* /*ctx*/) override {}
......
...@@ -242,6 +242,11 @@ class TorqueBaseVisitor : public TorqueVisitor { ...@@ -242,6 +242,11 @@ class TorqueBaseVisitor : public TorqueVisitor {
return visitChildren(ctx); return visitChildren(ctx);
} }
antlrcpp::Any visitDiagnosticStatement(
TorqueParser::DiagnosticStatementContext* ctx) override {
return visitChildren(ctx);
}
antlrcpp::Any visitStatement(TorqueParser::StatementContext* ctx) override { antlrcpp::Any visitStatement(TorqueParser::StatementContext* ctx) override {
return visitChildren(ctx); return visitChildren(ctx);
} }
......
This diff is collapsed.
...@@ -59,38 +59,41 @@ class TorqueLexer : public antlr4::Lexer { ...@@ -59,38 +59,41 @@ class TorqueLexer : public antlr4::Lexer {
ISNT = 44, ISNT = 44,
IS = 45, IS = 45,
LET = 46, LET = 46,
ASSIGNMENT = 47, ASSERT = 47,
ASSIGNMENT_OPERATOR = 48, UNREACHABLE_TOKEN = 48,
EQUAL = 49, DEBUG_TOKEN = 49,
PLUS = 50, ASSIGNMENT = 50,
MINUS = 51, ASSIGNMENT_OPERATOR = 51,
MULTIPLY = 52, EQUAL = 52,
DIVIDE = 53, PLUS = 53,
MODULO = 54, MINUS = 54,
BIT_OR = 55, MULTIPLY = 55,
BIT_AND = 56, DIVIDE = 56,
BIT_NOT = 57, MODULO = 57,
MAX = 58, BIT_OR = 58,
MIN = 59, BIT_AND = 59,
NOT_EQUAL = 60, BIT_NOT = 60,
LESS_THAN = 61, MAX = 61,
LESS_THAN_EQUAL = 62, MIN = 62,
GREATER_THAN = 63, NOT_EQUAL = 63,
GREATER_THAN_EQUAL = 64, LESS_THAN = 64,
SHIFT_LEFT = 65, LESS_THAN_EQUAL = 65,
SHIFT_RIGHT = 66, GREATER_THAN = 66,
SHIFT_RIGHT_ARITHMETIC = 67, GREATER_THAN_EQUAL = 67,
VARARGS = 68, SHIFT_LEFT = 68,
EQUALITY_OPERATOR = 69, SHIFT_RIGHT = 69,
INCREMENT = 70, SHIFT_RIGHT_ARITHMETIC = 70,
DECREMENT = 71, VARARGS = 71,
NOT = 72, EQUALITY_OPERATOR = 72,
STRING_LITERAL = 73, INCREMENT = 73,
IDENTIFIER = 74, DECREMENT = 74,
WS = 75, NOT = 75,
BLOCK_COMMENT = 76, STRING_LITERAL = 76,
LINE_COMMENT = 77, IDENTIFIER = 77,
DECIMAL_LITERAL = 78 WS = 78,
BLOCK_COMMENT = 79,
LINE_COMMENT = 80,
DECIMAL_LITERAL = 81
}; };
explicit TorqueLexer(antlr4::CharStream* input); explicit TorqueLexer(antlr4::CharStream* input);
......
...@@ -214,6 +214,11 @@ class TorqueListener : public antlr4::tree::ParseTreeListener { ...@@ -214,6 +214,11 @@ class TorqueListener : public antlr4::tree::ParseTreeListener {
virtual void enterTryCatch(TorqueParser::TryCatchContext* ctx) = 0; virtual void enterTryCatch(TorqueParser::TryCatchContext* ctx) = 0;
virtual void exitTryCatch(TorqueParser::TryCatchContext* ctx) = 0; virtual void exitTryCatch(TorqueParser::TryCatchContext* ctx) = 0;
virtual void enterDiagnosticStatement(
TorqueParser::DiagnosticStatementContext* ctx) = 0;
virtual void exitDiagnosticStatement(
TorqueParser::DiagnosticStatementContext* ctx) = 0;
virtual void enterStatement(TorqueParser::StatementContext* ctx) = 0; virtual void enterStatement(TorqueParser::StatementContext* ctx) = 0;
virtual void exitStatement(TorqueParser::StatementContext* ctx) = 0; virtual void exitStatement(TorqueParser::StatementContext* ctx) = 0;
......
This diff is collapsed.
...@@ -59,38 +59,41 @@ class TorqueParser : public antlr4::Parser { ...@@ -59,38 +59,41 @@ class TorqueParser : public antlr4::Parser {
ISNT = 44, ISNT = 44,
IS = 45, IS = 45,
LET = 46, LET = 46,
ASSIGNMENT = 47, ASSERT = 47,
ASSIGNMENT_OPERATOR = 48, UNREACHABLE_TOKEN = 48,
EQUAL = 49, DEBUG_TOKEN = 49,
PLUS = 50, ASSIGNMENT = 50,
MINUS = 51, ASSIGNMENT_OPERATOR = 51,
MULTIPLY = 52, EQUAL = 52,
DIVIDE = 53, PLUS = 53,
MODULO = 54, MINUS = 54,
BIT_OR = 55, MULTIPLY = 55,
BIT_AND = 56, DIVIDE = 56,
BIT_NOT = 57, MODULO = 57,
MAX = 58, BIT_OR = 58,
MIN = 59, BIT_AND = 59,
NOT_EQUAL = 60, BIT_NOT = 60,
LESS_THAN = 61, MAX = 61,
LESS_THAN_EQUAL = 62, MIN = 62,
GREATER_THAN = 63, NOT_EQUAL = 63,
GREATER_THAN_EQUAL = 64, LESS_THAN = 64,
SHIFT_LEFT = 65, LESS_THAN_EQUAL = 65,
SHIFT_RIGHT = 66, GREATER_THAN = 66,
SHIFT_RIGHT_ARITHMETIC = 67, GREATER_THAN_EQUAL = 67,
VARARGS = 68, SHIFT_LEFT = 68,
EQUALITY_OPERATOR = 69, SHIFT_RIGHT = 69,
INCREMENT = 70, SHIFT_RIGHT_ARITHMETIC = 70,
DECREMENT = 71, VARARGS = 71,
NOT = 72, EQUALITY_OPERATOR = 72,
STRING_LITERAL = 73, INCREMENT = 73,
IDENTIFIER = 74, DECREMENT = 74,
WS = 75, NOT = 75,
BLOCK_COMMENT = 76, STRING_LITERAL = 76,
LINE_COMMENT = 77, IDENTIFIER = 77,
DECIMAL_LITERAL = 78 WS = 78,
BLOCK_COMMENT = 79,
LINE_COMMENT = 80,
DECIMAL_LITERAL = 81
}; };
enum { enum {
...@@ -141,23 +144,24 @@ class TorqueParser : public antlr4::Parser { ...@@ -141,23 +144,24 @@ class TorqueParser : public antlr4::Parser {
RuleGotoStatement = 44, RuleGotoStatement = 44,
RuleHandlerWithStatement = 45, RuleHandlerWithStatement = 45,
RuleTryCatch = 46, RuleTryCatch = 46,
RuleStatement = 47, RuleDiagnosticStatement = 47,
RuleStatementList = 48, RuleStatement = 48,
RuleStatementScope = 49, RuleStatementList = 49,
RuleStatementBlock = 50, RuleStatementScope = 50,
RuleHelperBody = 51, RuleStatementBlock = 51,
RuleGeneratesDeclaration = 52, RuleHelperBody = 52,
RuleExtendsDeclaration = 53, RuleGeneratesDeclaration = 53,
RuleTypeDeclaration = 54, RuleExtendsDeclaration = 54,
RuleExternalBuiltin = 55, RuleTypeDeclaration = 55,
RuleExternalMacro = 56, RuleExternalBuiltin = 56,
RuleExternalRuntime = 57, RuleExternalMacro = 57,
RuleBuiltinDeclaration = 58, RuleExternalRuntime = 58,
RuleMacroDeclaration = 59, RuleBuiltinDeclaration = 59,
RuleConstDeclaration = 60, RuleMacroDeclaration = 60,
RuleDeclaration = 61, RuleConstDeclaration = 61,
RuleModuleDeclaration = 62, RuleDeclaration = 62,
RuleFile = 63 RuleModuleDeclaration = 63,
RuleFile = 64
}; };
explicit TorqueParser(antlr4::TokenStream* input); explicit TorqueParser(antlr4::TokenStream* input);
...@@ -218,6 +222,7 @@ class TorqueParser : public antlr4::Parser { ...@@ -218,6 +222,7 @@ class TorqueParser : public antlr4::Parser {
class GotoStatementContext; class GotoStatementContext;
class HandlerWithStatementContext; class HandlerWithStatementContext;
class TryCatchContext; class TryCatchContext;
class DiagnosticStatementContext;
class StatementContext; class StatementContext;
class StatementListContext; class StatementListContext;
class StatementScopeContext; class StatementScopeContext;
...@@ -1035,6 +1040,24 @@ class TorqueParser : public antlr4::Parser { ...@@ -1035,6 +1040,24 @@ class TorqueParser : public antlr4::Parser {
TryCatchContext* tryCatch(); TryCatchContext* tryCatch();
class DiagnosticStatementContext : public antlr4::ParserRuleContext {
public:
DiagnosticStatementContext(antlr4::ParserRuleContext* parent,
size_t invokingState);
size_t getRuleIndex() const override;
antlr4::tree::TerminalNode* ASSERT();
ExpressionContext* expression();
antlr4::tree::TerminalNode* UNREACHABLE_TOKEN();
antlr4::tree::TerminalNode* DEBUG_TOKEN();
void enterRule(antlr4::tree::ParseTreeListener* listener) override;
void exitRule(antlr4::tree::ParseTreeListener* listener) override;
antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor* visitor) override;
};
DiagnosticStatementContext* diagnosticStatement();
class StatementContext : public antlr4::ParserRuleContext { class StatementContext : public antlr4::ParserRuleContext {
public: public:
StatementContext(antlr4::ParserRuleContext* parent, size_t invokingState); StatementContext(antlr4::ParserRuleContext* parent, size_t invokingState);
...@@ -1048,6 +1071,7 @@ class TorqueParser : public antlr4::Parser { ...@@ -1048,6 +1071,7 @@ class TorqueParser : public antlr4::Parser {
ContinueStatementContext* continueStatement(); ContinueStatementContext* continueStatement();
GotoStatementContext* gotoStatement(); GotoStatementContext* gotoStatement();
IfStatementContext* ifStatement(); IfStatementContext* ifStatement();
DiagnosticStatementContext* diagnosticStatement();
WhileLoopContext* whileLoop(); WhileLoopContext* whileLoop();
ForOfLoopContext* forOfLoop(); ForOfLoopContext* forOfLoop();
ForLoopContext* forLoop(); ForLoopContext* forLoop();
......
...@@ -159,6 +159,9 @@ class TorqueVisitor : public antlr4::tree::AbstractParseTreeVisitor { ...@@ -159,6 +159,9 @@ class TorqueVisitor : public antlr4::tree::AbstractParseTreeVisitor {
virtual antlrcpp::Any visitTryCatch( virtual antlrcpp::Any visitTryCatch(
TorqueParser::TryCatchContext* context) = 0; TorqueParser::TryCatchContext* context) = 0;
virtual antlrcpp::Any visitDiagnosticStatement(
TorqueParser::DiagnosticStatementContext* context) = 0;
virtual antlrcpp::Any visitStatement( virtual antlrcpp::Any visitStatement(
TorqueParser::StatementContext* context) = 0; TorqueParser::StatementContext* context) = 0;
......
...@@ -613,6 +613,26 @@ antlrcpp::Any AstGenerator::visitConditionalExpression( ...@@ -613,6 +613,26 @@ antlrcpp::Any AstGenerator::visitConditionalExpression(
return context->logicalORExpression(0)->accept(this); return context->logicalORExpression(0)->accept(this);
} }
antlrcpp::Any AstGenerator::visitDiagnosticStatement(
TorqueParser::DiagnosticStatementContext* context) {
if (context->ASSERT()) {
size_t a = context->expression()->start->getStartIndex();
size_t b = context->expression()->stop->getStopIndex();
antlr4::misc::Interval interval(a, b);
std::string source = source_file_context_->stream->getText(interval);
return base::implicit_cast<Statement*>(RegisterNode(new AssertStatement{
Pos(context), context->expression()->accept(this).as<Expression*>(),
source}));
} else if (context->UNREACHABLE_TOKEN()) {
return base::implicit_cast<Statement*>(
RegisterNode(new DebugStatement{Pos(context), "unreachable", true}));
} else {
DCHECK(context->DEBUG_TOKEN());
return base::implicit_cast<Statement*>(
RegisterNode(new DebugStatement{Pos(context), "debug", false}));
}
}
void AstGenerator::visitSourceFile(SourceFileContext* context) { void AstGenerator::visitSourceFile(SourceFileContext* context) {
source_file_context_ = context; source_file_context_ = context;
current_source_file_ = ast_.AddSource(context->name); current_source_file_ = ast_.AddSource(context->name);
......
...@@ -133,6 +133,9 @@ class AstGenerator : public TorqueBaseVisitor { ...@@ -133,6 +133,9 @@ class AstGenerator : public TorqueBaseVisitor {
antlrcpp::Any visitForOfLoop( antlrcpp::Any visitForOfLoop(
TorqueParser::ForOfLoopContext* context) override; TorqueParser::ForOfLoopContext* context) override;
antlrcpp::Any visitDiagnosticStatement(
TorqueParser::DiagnosticStatementContext* context) override;
antlrcpp::Any aggregateResult(antlrcpp::Any aggregate, antlrcpp::Any aggregateResult(antlrcpp::Any aggregate,
const antlrcpp::Any& nextResult) override { const antlrcpp::Any& nextResult) override {
if (aggregate.isNull()) if (aggregate.isNull())
......
...@@ -49,6 +49,8 @@ struct SourcePosition { ...@@ -49,6 +49,8 @@ struct SourcePosition {
V(BreakStatement) \ V(BreakStatement) \
V(ContinueStatement) \ V(ContinueStatement) \
V(ReturnStatement) \ V(ReturnStatement) \
V(DebugStatement) \
V(AssertStatement) \
V(TailCallStatement) \ V(TailCallStatement) \
V(VarDeclarationStatement) \ V(VarDeclarationStatement) \
V(GotoStatement) \ V(GotoStatement) \
...@@ -355,6 +357,22 @@ struct ReturnStatement : Statement { ...@@ -355,6 +357,22 @@ struct ReturnStatement : Statement {
base::Optional<Expression*> value; base::Optional<Expression*> value;
}; };
struct DebugStatement : Statement {
DEFINE_AST_NODE_LEAF_BOILERPLATE(DebugStatement)
DebugStatement(SourcePosition p, const std::string& r, bool n)
: Statement(kKind, p), reason(r), never_continues(n) {}
std::string reason;
bool never_continues;
};
struct AssertStatement : Statement {
DEFINE_AST_NODE_LEAF_BOILERPLATE(AssertStatement)
AssertStatement(SourcePosition p, Expression* e, const std::string& s)
: Statement(kKind, p), expression(e), source(s) {}
Expression* expression;
std::string source;
};
struct TailCallStatement : Statement { struct TailCallStatement : Statement {
DEFINE_AST_NODE_LEAF_BOILERPLATE(TailCallStatement) DEFINE_AST_NODE_LEAF_BOILERPLATE(TailCallStatement)
TailCallStatement(SourcePosition p, CallExpression* c) TailCallStatement(SourcePosition p, CallExpression* c)
......
...@@ -190,6 +190,11 @@ class DeclarationVisitor : public FileVisitor { ...@@ -190,6 +190,11 @@ class DeclarationVisitor : public FileVisitor {
void Visit(MacroDeclaration* decl); void Visit(MacroDeclaration* decl);
void Visit(ReturnStatement* stmt); void Visit(ReturnStatement* stmt);
void Visit(DebugStatement* stmt) {}
void Visit(AssertStatement* stmt) {
DeclareExpressionForBranch(stmt->expression);
}
void Visit(VarDeclarationStatement* stmt) { void Visit(VarDeclarationStatement* stmt) {
std::string variable_name = stmt->name; std::string variable_name = stmt->name;
Type type = declarations()->LookupType(stmt->pos, stmt->type); Type type = declarations()->LookupType(stmt->pos, stmt->type);
......
...@@ -49,14 +49,6 @@ struct SourceFileContext { ...@@ -49,14 +49,6 @@ struct SourceFileContext {
std::unique_ptr<antlr4::CommonTokenStream> tokens; std::unique_ptr<antlr4::CommonTokenStream> tokens;
std::unique_ptr<TorqueParser> parser; std::unique_ptr<TorqueParser> parser;
TorqueParser::FileContext* file; TorqueParser::FileContext* file;
std::string sourceFileAndLineNumber(antlr4::ParserRuleContext* context) {
antlr4::misc::Interval i = context->getSourceInterval();
auto token = tokens->get(i.a);
size_t line = token->getLine();
size_t pos = token->getCharPositionInLine();
return name + ":" + std::to_string(line) + ":" + std::to_string(pos);
}
}; };
class GlobalContext { class GlobalContext {
......
...@@ -565,6 +565,70 @@ Type ImplementationVisitor::Visit(BlockStatement* block) { ...@@ -565,6 +565,70 @@ Type ImplementationVisitor::Visit(BlockStatement* block) {
return type; return type;
} }
Type ImplementationVisitor::Visit(DebugStatement* stmt) {
#if defined(DEBUG)
GenerateIndent();
source_out() << "Print(\""
<< "halting because of '" << stmt->reason << "' at "
<< PositionAsString(stmt->pos) << "\");" << std::endl;
#endif
GenerateIndent();
if (stmt->never_continues) {
source_out() << "Unreachable();" << std::endl;
return GetTypeOracle().GetNeverType();
} else {
source_out() << "DebugBreak();" << std::endl;
return GetTypeOracle().GetVoidType();
}
}
Type ImplementationVisitor::Visit(AssertStatement* stmt) {
#if defined(DEBUG)
// CSA_ASSERT & co. are not used here on purpose for two reasons. First,
// Torque allows and handles two types of expressions in the if protocol
// automagically, ones that return TNode<BoolT> and those that use the
// BranchIf(..., Label* true, Label* false) idiom. Because the machinery to
// handle this is embedded in the expression handling and to it's not possible
// to make the decision to use CSA_ASSERT or CSA_ASSERT_BRANCH isn't trivial
// up-front. Secondly, on failure, the assert text should be the corresponding
// Torque code, not the -gen.cc code, which would be the case when using
// CSA_ASSERT_XXX.
Label* true_label = nullptr;
Label* false_label = nullptr;
Declarations::NodeScopeActivator scope(declarations(), stmt->expression);
true_label =
Label::cast(declarations()->LookupValue(stmt->pos, kTrueLabelName));
GenerateLabelDefinition(true_label);
false_label =
Label::cast(declarations()->LookupValue(stmt->pos, kFalseLabelName));
GenerateLabelDefinition(false_label);
Expression* expression = stmt->expression;
VisitResult expression_result = Visit(stmt->expression);
if (expression_result.type() == GetTypeOracle().GetBitType()) {
GenerateBranch(expression_result, true_label, false_label);
} else {
if (expression_result.type() != GetTypeOracle().GetNeverType()) {
std::stringstream s;
s << "unexpected return type " << expression_result.type()
<< " for branch expression at " << PositionAsString(expression->pos);
ReportError(s.str());
}
}
GenerateLabelBind(false_label);
GenerateIndent();
source_out() << "Print(\""
<< "assert '" << stmt->source << "' failed at "
<< PositionAsString(stmt->pos) << "\");" << std::endl;
GenerateIndent();
source_out() << "Unreachable();" << std::endl;
GenerateLabelBind(true_label);
#endif
return GetTypeOracle().GetVoidType();
}
Type ImplementationVisitor::Visit(ExpressionStatement* stmt) { Type ImplementationVisitor::Visit(ExpressionStatement* stmt) {
Type type = Visit(stmt->expression).type(); Type type = Visit(stmt->expression).type();
return type.IsNever() ? type : GetTypeOracle().GetVoidType(); return type.IsNever() ? type : GetTypeOracle().GetVoidType();
......
...@@ -131,6 +131,8 @@ class ImplementationVisitor : public FileVisitor { ...@@ -131,6 +131,8 @@ class ImplementationVisitor : public FileVisitor {
Type Visit(ForOfLoopStatement* stmt); Type Visit(ForOfLoopStatement* stmt);
Type Visit(BlockStatement* block); Type Visit(BlockStatement* block);
Type Visit(ExpressionStatement* stmt); Type Visit(ExpressionStatement* stmt);
Type Visit(DebugStatement* stmt);
Type Visit(AssertStatement* stmt);
Label* GetLabel(SourcePosition pos, const std::string& label); Label* GetLabel(SourcePosition pos, const std::string& label);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment