mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #3297 from ethereum/separate_expression_and_statement
Separate expression and statement
This commit is contained in:
commit
2cdd789b5d
@ -42,11 +42,13 @@ using If = solidity::assembly::If;
|
|||||||
using Case = solidity::assembly::Case;
|
using Case = solidity::assembly::Case;
|
||||||
using Switch = solidity::assembly::Switch;
|
using Switch = solidity::assembly::Switch;
|
||||||
using ForLoop = solidity::assembly::ForLoop;
|
using ForLoop = solidity::assembly::ForLoop;
|
||||||
|
using ExpressionStatement = solidity::assembly::ExpressionStatement;
|
||||||
using Block = solidity::assembly::Block;
|
using Block = solidity::assembly::Block;
|
||||||
|
|
||||||
using TypedName = solidity::assembly::TypedName;
|
using TypedName = solidity::assembly::TypedName;
|
||||||
|
|
||||||
using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>;
|
using Expression = boost::variant<FunctionalInstruction, FunctionCall, Identifier, Literal>;
|
||||||
|
using Statement = boost::variant<ExpressionStatement, Instruction, Label, StackAssignment, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,13 @@ void CodeTransform::operator()(StackAssignment const& _assignment)
|
|||||||
checkStackHeight(&_assignment);
|
checkStackHeight(&_assignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CodeTransform::operator()(ExpressionStatement const& _statement)
|
||||||
|
{
|
||||||
|
m_assembly.setSourceLocation(_statement.location);
|
||||||
|
boost::apply_visitor(*this, _statement.expression);
|
||||||
|
checkStackHeight(&_statement);
|
||||||
|
}
|
||||||
|
|
||||||
void CodeTransform::operator()(Label const& _label)
|
void CodeTransform::operator()(Label const& _label)
|
||||||
{
|
{
|
||||||
m_assembly.setSourceLocation(_label.location);
|
m_assembly.setSourceLocation(_label.location);
|
||||||
@ -460,7 +467,7 @@ AbstractAssembly::LabelID CodeTransform::functionEntryID(string const& _name, Sc
|
|||||||
return m_context->functionEntryIDs[&_function];
|
return m_context->functionEntryIDs[&_function];
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeTransform::visitExpression(Statement const& _expression)
|
void CodeTransform::visitExpression(Expression const& _expression)
|
||||||
{
|
{
|
||||||
int height = m_assembly.stackHeight();
|
int height = m_assembly.stackHeight();
|
||||||
boost::apply_visitor(*this, _expression);
|
boost::apply_visitor(*this, _expression);
|
||||||
|
@ -101,6 +101,7 @@ public:
|
|||||||
void operator()(Identifier const& _identifier);
|
void operator()(Identifier const& _identifier);
|
||||||
void operator()(FunctionalInstruction const& _instr);
|
void operator()(FunctionalInstruction const& _instr);
|
||||||
void operator()(FunctionCall const&);
|
void operator()(FunctionCall const&);
|
||||||
|
void operator()(ExpressionStatement const& _statement);
|
||||||
void operator()(Label const& _label);
|
void operator()(Label const& _label);
|
||||||
void operator()(StackAssignment const& _assignment);
|
void operator()(StackAssignment const& _assignment);
|
||||||
void operator()(Assignment const& _assignment);
|
void operator()(Assignment const& _assignment);
|
||||||
@ -118,7 +119,7 @@ private:
|
|||||||
AbstractAssembly::LabelID labelID(solidity::assembly::Scope::Label const& _label);
|
AbstractAssembly::LabelID labelID(solidity::assembly::Scope::Label const& _label);
|
||||||
AbstractAssembly::LabelID functionEntryID(std::string const& _name, solidity::assembly::Scope::Function const& _function);
|
AbstractAssembly::LabelID functionEntryID(std::string const& _name, solidity::assembly::Scope::Function const& _function);
|
||||||
/// Generates code for an expression that is supposed to return a single value.
|
/// Generates code for an expression that is supposed to return a single value.
|
||||||
void visitExpression(Statement const& _expression);
|
void visitExpression(Expression const& _expression);
|
||||||
|
|
||||||
void visitStatements(std::vector<Statement> const& _statements);
|
void visitStatements(std::vector<Statement> const& _statements);
|
||||||
|
|
||||||
|
@ -37,6 +37,11 @@ Statement ASTCopier::operator()(Instruction const&)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Statement ASTCopier::operator()(ExpressionStatement const& _statement)
|
||||||
|
{
|
||||||
|
return ExpressionStatement{ _statement.location, translate(_statement.expression) };
|
||||||
|
}
|
||||||
|
|
||||||
Statement ASTCopier::operator()(VariableDeclaration const& _varDecl)
|
Statement ASTCopier::operator()(VariableDeclaration const& _varDecl)
|
||||||
{
|
{
|
||||||
return VariableDeclaration{
|
return VariableDeclaration{
|
||||||
@ -67,7 +72,7 @@ Statement ASTCopier::operator()(Label const&)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement ASTCopier::operator()(FunctionCall const& _call)
|
Expression ASTCopier::operator()(FunctionCall const& _call)
|
||||||
{
|
{
|
||||||
return FunctionCall{
|
return FunctionCall{
|
||||||
_call.location,
|
_call.location,
|
||||||
@ -76,7 +81,7 @@ Statement ASTCopier::operator()(FunctionCall const& _call)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement ASTCopier::operator()(FunctionalInstruction const& _instruction)
|
Expression ASTCopier::operator()(FunctionalInstruction const& _instruction)
|
||||||
{
|
{
|
||||||
return FunctionalInstruction{
|
return FunctionalInstruction{
|
||||||
_instruction.location,
|
_instruction.location,
|
||||||
@ -85,12 +90,12 @@ Statement ASTCopier::operator()(FunctionalInstruction const& _instruction)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement ASTCopier::operator()(Identifier const& _identifier)
|
Expression ASTCopier::operator()(Identifier const& _identifier)
|
||||||
{
|
{
|
||||||
return Identifier{_identifier.location, translateIdentifier(_identifier.name)};
|
return Identifier{_identifier.location, translateIdentifier(_identifier.name)};
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement ASTCopier::operator()(Literal const& _literal)
|
Expression ASTCopier::operator()(Literal const& _literal)
|
||||||
{
|
{
|
||||||
return translate(_literal);
|
return translate(_literal);
|
||||||
}
|
}
|
||||||
@ -140,9 +145,14 @@ Statement ASTCopier::operator ()(Block const& _block)
|
|||||||
return translate(_block);
|
return translate(_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expression ASTCopier::translate(Expression const& _expression)
|
||||||
|
{
|
||||||
|
return _expression.apply_visitor(static_cast<ExpressionCopier&>(*this));
|
||||||
|
}
|
||||||
|
|
||||||
Statement ASTCopier::translate(Statement const& _statement)
|
Statement ASTCopier::translate(Statement const& _statement)
|
||||||
{
|
{
|
||||||
return boost::apply_visitor(*this, _statement);
|
return _statement.apply_visitor(static_cast<StatementCopier&>(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
Block ASTCopier::translate(Block const& _block)
|
Block ASTCopier::translate(Block const& _block)
|
||||||
|
@ -34,28 +34,55 @@ namespace dev
|
|||||||
namespace julia
|
namespace julia
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class ExpressionCopier: public boost::static_visitor<Expression>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual Expression operator()(Literal const& _literal) = 0;
|
||||||
|
virtual Expression operator()(Identifier const& _identifier) = 0;
|
||||||
|
virtual Expression operator()(FunctionalInstruction const& _instr) = 0;
|
||||||
|
virtual Expression operator()(FunctionCall const&) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StatementCopier: public boost::static_visitor<Statement>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual Statement operator()(ExpressionStatement const& _statement) = 0;
|
||||||
|
virtual Statement operator()(Instruction const& _instruction) = 0;
|
||||||
|
virtual Statement operator()(Label const& _label) = 0;
|
||||||
|
virtual Statement operator()(StackAssignment const& _assignment) = 0;
|
||||||
|
virtual Statement operator()(Assignment const& _assignment) = 0;
|
||||||
|
virtual Statement operator()(VariableDeclaration const& _varDecl) = 0;
|
||||||
|
virtual Statement operator()(If const& _if) = 0;
|
||||||
|
virtual Statement operator()(Switch const& _switch) = 0;
|
||||||
|
virtual Statement operator()(FunctionDefinition const&) = 0;
|
||||||
|
virtual Statement operator()(ForLoop const&) = 0;
|
||||||
|
virtual Statement operator()(Block const& _block) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a copy of a iulia AST potentially replacing identifier names.
|
* Creates a copy of a iulia AST potentially replacing identifier names.
|
||||||
* Base class to be extended.
|
* Base class to be extended.
|
||||||
*/
|
*/
|
||||||
class ASTCopier: public boost::static_visitor<Statement>
|
class ASTCopier: public ExpressionCopier, public StatementCopier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Statement operator()(Literal const& _literal);
|
virtual Expression operator()(Literal const& _literal) override;
|
||||||
Statement operator()(Instruction const& _instruction);
|
virtual Statement operator()(Instruction const& _instruction) override;
|
||||||
Statement operator()(Identifier const& _identifier);
|
virtual Expression operator()(Identifier const& _identifier) override;
|
||||||
Statement operator()(FunctionalInstruction const& _instr);
|
virtual Expression operator()(FunctionalInstruction const& _instr) override;
|
||||||
Statement operator()(FunctionCall const&);
|
virtual Expression operator()(FunctionCall const&) override;
|
||||||
Statement operator()(Label const& _label);
|
virtual Statement operator()(ExpressionStatement const& _statement) override;
|
||||||
Statement operator()(StackAssignment const& _assignment);
|
virtual Statement operator()(Label const& _label) override;
|
||||||
Statement operator()(Assignment const& _assignment);
|
virtual Statement operator()(StackAssignment const& _assignment) override;
|
||||||
Statement operator()(VariableDeclaration const& _varDecl);
|
virtual Statement operator()(Assignment const& _assignment) override;
|
||||||
Statement operator()(If const& _if);
|
virtual Statement operator()(VariableDeclaration const& _varDecl) override;
|
||||||
Statement operator()(Switch const& _switch);
|
virtual Statement operator()(If const& _if) override;
|
||||||
Statement operator()(FunctionDefinition const&);
|
virtual Statement operator()(Switch const& _switch) override;
|
||||||
Statement operator()(ForLoop const&);
|
virtual Statement operator()(FunctionDefinition const&) override;
|
||||||
Statement operator()(Block const& _block);
|
virtual Statement operator()(ForLoop const&) override;
|
||||||
|
virtual Statement operator()(Block const& _block) override;
|
||||||
|
|
||||||
|
virtual Expression translate(Expression const& _expression);
|
||||||
virtual Statement translate(Statement const& _statement);
|
virtual Statement translate(Statement const& _statement);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -42,6 +42,11 @@ void ASTWalker::operator()(FunctionCall const& _funCall)
|
|||||||
walkVector(_funCall.arguments | boost::adaptors::reversed);
|
walkVector(_funCall.arguments | boost::adaptors::reversed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ASTWalker::operator()(ExpressionStatement const& _statement)
|
||||||
|
{
|
||||||
|
boost::apply_visitor(*this, _statement.expression);
|
||||||
|
}
|
||||||
|
|
||||||
void ASTWalker::operator()(Assignment const& _assignment)
|
void ASTWalker::operator()(Assignment const& _assignment)
|
||||||
{
|
{
|
||||||
for (auto const& name: _assignment.variableNames)
|
for (auto const& name: _assignment.variableNames)
|
||||||
@ -100,6 +105,11 @@ void ASTModifier::operator()(FunctionCall& _funCall)
|
|||||||
walkVector(_funCall.arguments | boost::adaptors::reversed);
|
walkVector(_funCall.arguments | boost::adaptors::reversed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ASTModifier::operator()(ExpressionStatement& _statement)
|
||||||
|
{
|
||||||
|
boost::apply_visitor(*this, _statement.expression);
|
||||||
|
}
|
||||||
|
|
||||||
void ASTModifier::operator()(Assignment& _assignment)
|
void ASTModifier::operator()(Assignment& _assignment)
|
||||||
{
|
{
|
||||||
for (auto& name: _assignment.variableNames)
|
for (auto& name: _assignment.variableNames)
|
||||||
|
@ -47,6 +47,7 @@ public:
|
|||||||
virtual void operator()(Identifier const&) {}
|
virtual void operator()(Identifier const&) {}
|
||||||
virtual void operator()(FunctionalInstruction const& _instr);
|
virtual void operator()(FunctionalInstruction const& _instr);
|
||||||
virtual void operator()(FunctionCall const& _funCall);
|
virtual void operator()(FunctionCall const& _funCall);
|
||||||
|
virtual void operator()(ExpressionStatement const& _statement);
|
||||||
virtual void operator()(Label const&) { solAssert(false, ""); }
|
virtual void operator()(Label const&) { solAssert(false, ""); }
|
||||||
virtual void operator()(StackAssignment const&) { solAssert(false, ""); }
|
virtual void operator()(StackAssignment const&) { solAssert(false, ""); }
|
||||||
virtual void operator()(Assignment const& _assignment);
|
virtual void operator()(Assignment const& _assignment);
|
||||||
@ -77,6 +78,7 @@ public:
|
|||||||
virtual void operator()(Identifier&) {}
|
virtual void operator()(Identifier&) {}
|
||||||
virtual void operator()(FunctionalInstruction& _instr);
|
virtual void operator()(FunctionalInstruction& _instr);
|
||||||
virtual void operator()(FunctionCall& _funCall);
|
virtual void operator()(FunctionCall& _funCall);
|
||||||
|
virtual void operator()(ExpressionStatement& _statement);
|
||||||
virtual void operator()(Label&) { solAssert(false, ""); }
|
virtual void operator()(Label&) { solAssert(false, ""); }
|
||||||
virtual void operator()(StackAssignment&) { solAssert(false, ""); }
|
virtual void operator()(StackAssignment&) { solAssert(false, ""); }
|
||||||
virtual void operator()(Assignment& _assignment);
|
virtual void operator()(Assignment& _assignment);
|
||||||
@ -98,6 +100,10 @@ protected:
|
|||||||
{
|
{
|
||||||
boost::apply_visitor(*this, _st);
|
boost::apply_visitor(*this, _st);
|
||||||
}
|
}
|
||||||
|
virtual void visit(Expression& _e)
|
||||||
|
{
|
||||||
|
boost::apply_visitor(*this, _e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,14 +26,14 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace dev::julia;
|
using namespace dev::julia;
|
||||||
|
|
||||||
Statement Substitution::translate(Statement const& _statement)
|
Expression Substitution::translate(Expression const& _expression)
|
||||||
{
|
{
|
||||||
if (_statement.type() == typeid(Identifier))
|
if (_expression.type() == typeid(Identifier))
|
||||||
{
|
{
|
||||||
string const& name = boost::get<Identifier>(_statement).name;
|
string const& name = boost::get<Identifier>(_expression).name;
|
||||||
if (m_substitutions.count(name))
|
if (m_substitutions.count(name))
|
||||||
// No recursive substitution
|
// No recursive substitution
|
||||||
return ASTCopier().translate(*m_substitutions.at(name));
|
return ASTCopier().translate(*m_substitutions.at(name));
|
||||||
}
|
}
|
||||||
return ASTCopier::translate(_statement);
|
return ASTCopier::translate(_expression);
|
||||||
}
|
}
|
||||||
|
@ -33,18 +33,17 @@ namespace julia
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Specific AST copier that replaces certain identifiers with expressions.
|
* Specific AST copier that replaces certain identifiers with expressions.
|
||||||
* Only works on ASTs that are expressions.
|
|
||||||
*/
|
*/
|
||||||
class Substitution: public ASTCopier
|
class Substitution: public ASTCopier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Substitution(std::map<std::string, Statement const*> const& _substitutions):
|
Substitution(std::map<std::string, Expression const*> const& _substitutions):
|
||||||
m_substitutions(_substitutions)
|
m_substitutions(_substitutions)
|
||||||
{}
|
{}
|
||||||
virtual Statement translate(Statement const& _statement) override;
|
virtual Expression translate(Expression const& _expression) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<std::string, Statement const*> const& m_substitutions;
|
std::map<std::string, Expression const*> const& m_substitutions;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,10 @@ public:
|
|||||||
for (auto const& arg: _instr.arguments)
|
for (auto const& arg: _instr.arguments)
|
||||||
boost::apply_visitor(*this, arg);
|
boost::apply_visitor(*this, arg);
|
||||||
}
|
}
|
||||||
|
void operator()(assembly::ExpressionStatement const& _expr)
|
||||||
|
{
|
||||||
|
boost::apply_visitor(*this, _expr.expression);
|
||||||
|
}
|
||||||
void operator()(assembly::StackAssignment const&) {}
|
void operator()(assembly::StackAssignment const&) {}
|
||||||
void operator()(assembly::Assignment const& _assignment)
|
void operator()(assembly::Assignment const& _assignment)
|
||||||
{
|
{
|
||||||
|
@ -155,6 +155,16 @@ bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr)
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AsmAnalyzer::operator()(assembly::ExpressionStatement const& _statement)
|
||||||
|
{
|
||||||
|
// size_t initialStackHeight = m_stackHeight;
|
||||||
|
bool success = boost::apply_visitor(*this, _statement.expression);
|
||||||
|
// if (!expectDeposit(0, initialStackHeight, _statement.location))
|
||||||
|
// success = false;
|
||||||
|
m_info.stackHeightInfo[&_statement] = m_stackHeight;
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
bool AsmAnalyzer::operator()(assembly::StackAssignment const& _assignment)
|
bool AsmAnalyzer::operator()(assembly::StackAssignment const& _assignment)
|
||||||
{
|
{
|
||||||
solAssert(!m_julia, "");
|
solAssert(!m_julia, "");
|
||||||
@ -407,13 +417,13 @@ bool AsmAnalyzer::operator()(Block const& _block)
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AsmAnalyzer::expectExpression(Statement const& _statement)
|
bool AsmAnalyzer::expectExpression(Expression const& _expr)
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
int const initialHeight = m_stackHeight;
|
int const initialHeight = m_stackHeight;
|
||||||
if (!boost::apply_visitor(*this, _statement))
|
if (!boost::apply_visitor(*this, _expr))
|
||||||
success = false;
|
success = false;
|
||||||
if (!expectDeposit(1, initialHeight, locationOf(_statement)))
|
if (!expectDeposit(1, initialHeight, locationOf(_expr)))
|
||||||
success = false;
|
success = false;
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,7 @@ public:
|
|||||||
bool operator()(assembly::Identifier const&);
|
bool operator()(assembly::Identifier const&);
|
||||||
bool operator()(assembly::FunctionalInstruction const& _functionalInstruction);
|
bool operator()(assembly::FunctionalInstruction const& _functionalInstruction);
|
||||||
bool operator()(assembly::Label const& _label);
|
bool operator()(assembly::Label const& _label);
|
||||||
|
bool operator()(assembly::ExpressionStatement const&);
|
||||||
bool operator()(assembly::StackAssignment const&);
|
bool operator()(assembly::StackAssignment const&);
|
||||||
bool operator()(assembly::Assignment const& _assignment);
|
bool operator()(assembly::Assignment const& _assignment);
|
||||||
bool operator()(assembly::VariableDeclaration const& _variableDeclaration);
|
bool operator()(assembly::VariableDeclaration const& _variableDeclaration);
|
||||||
@ -77,7 +78,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
/// Visits the statement and expects it to deposit one item onto the stack.
|
/// Visits the statement and expects it to deposit one item onto the stack.
|
||||||
bool expectExpression(Statement const& _statement);
|
bool expectExpression(Expression const& _expr);
|
||||||
bool expectDeposit(int _deposit, int _oldHeight, SourceLocation const& _location);
|
bool expectDeposit(int _deposit, int _oldHeight, SourceLocation const& _location);
|
||||||
|
|
||||||
/// Verifies that a variable to be assigned to exists and has the same size
|
/// Verifies that a variable to be assigned to exists and has the same size
|
||||||
|
@ -58,23 +58,25 @@ struct StackAssignment { SourceLocation location; Identifier variableName; };
|
|||||||
/// Multiple assignment ("x, y := f()"), where the left hand side variables each occupy
|
/// Multiple assignment ("x, y := f()"), where the left hand side variables each occupy
|
||||||
/// a single stack slot and expects a single expression on the right hand returning
|
/// a single stack slot and expects a single expression on the right hand returning
|
||||||
/// the same amount of items as the number of variables.
|
/// the same amount of items as the number of variables.
|
||||||
struct Assignment { SourceLocation location; std::vector<Identifier> variableNames; std::shared_ptr<Statement> value; };
|
struct Assignment { SourceLocation location; std::vector<Identifier> variableNames; std::shared_ptr<Expression> value; };
|
||||||
/// Functional instruction, e.g. "mul(mload(20:u256), add(2:u256, x))"
|
/// Functional instruction, e.g. "mul(mload(20:u256), add(2:u256, x))"
|
||||||
struct FunctionalInstruction { SourceLocation location; solidity::Instruction instruction; std::vector<Statement> arguments; };
|
struct FunctionalInstruction { SourceLocation location; solidity::Instruction instruction; std::vector<Expression> arguments; };
|
||||||
struct FunctionCall { SourceLocation location; Identifier functionName; std::vector<Statement> arguments; };
|
struct FunctionCall { SourceLocation location; Identifier functionName; std::vector<Expression> arguments; };
|
||||||
|
/// Statement that contains only a single expression
|
||||||
|
struct ExpressionStatement { SourceLocation location; Expression expression; };
|
||||||
/// Block-scope variable declaration ("let x:u256 := mload(20:u256)"), non-hoisted
|
/// Block-scope variable declaration ("let x:u256 := mload(20:u256)"), non-hoisted
|
||||||
struct VariableDeclaration { SourceLocation location; TypedNameList variables; std::shared_ptr<Statement> value; };
|
struct VariableDeclaration { SourceLocation location; TypedNameList variables; std::shared_ptr<Expression> value; };
|
||||||
/// Block that creates a scope (frees declared stack variables)
|
/// Block that creates a scope (frees declared stack variables)
|
||||||
struct Block { SourceLocation location; std::vector<Statement> statements; };
|
struct Block { SourceLocation location; std::vector<Statement> statements; };
|
||||||
/// Function definition ("function f(a, b) -> (d, e) { ... }")
|
/// Function definition ("function f(a, b) -> (d, e) { ... }")
|
||||||
struct FunctionDefinition { SourceLocation location; std::string name; TypedNameList parameters; TypedNameList returnVariables; Block body; };
|
struct FunctionDefinition { SourceLocation location; std::string name; TypedNameList parameters; TypedNameList returnVariables; Block body; };
|
||||||
/// Conditional execution without "else" part.
|
/// Conditional execution without "else" part.
|
||||||
struct If { SourceLocation location; std::shared_ptr<Statement> condition; Block body; };
|
struct If { SourceLocation location; std::shared_ptr<Expression> condition; Block body; };
|
||||||
/// Switch case or default case
|
/// Switch case or default case
|
||||||
struct Case { SourceLocation location; std::shared_ptr<Literal> value; Block body; };
|
struct Case { SourceLocation location; std::shared_ptr<Literal> value; Block body; };
|
||||||
/// Switch statement
|
/// Switch statement
|
||||||
struct Switch { SourceLocation location; std::shared_ptr<Statement> expression; std::vector<Case> cases; };
|
struct Switch { SourceLocation location; std::shared_ptr<Expression> expression; std::vector<Case> cases; };
|
||||||
struct ForLoop { SourceLocation location; Block pre; std::shared_ptr<Statement> condition; Block post; Block body; };
|
struct ForLoop { SourceLocation location; Block pre; std::shared_ptr<Expression> condition; Block post; Block body; };
|
||||||
|
|
||||||
struct LocationExtractor: boost::static_visitor<SourceLocation>
|
struct LocationExtractor: boost::static_visitor<SourceLocation>
|
||||||
{
|
{
|
||||||
|
@ -45,11 +45,13 @@ struct If;
|
|||||||
struct Switch;
|
struct Switch;
|
||||||
struct Case;
|
struct Case;
|
||||||
struct ForLoop;
|
struct ForLoop;
|
||||||
|
struct ExpressionStatement;
|
||||||
struct Block;
|
struct Block;
|
||||||
|
|
||||||
struct TypedName;
|
struct TypedName;
|
||||||
|
|
||||||
using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>;
|
using Expression = boost::variant<FunctionalInstruction, FunctionCall, Identifier, Literal>;
|
||||||
|
using Statement = boost::variant<ExpressionStatement, Instruction, Label, StackAssignment, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,9 +77,7 @@ assembly::Statement Parser::parseStatement()
|
|||||||
{
|
{
|
||||||
assembly::If _if = createWithLocation<assembly::If>();
|
assembly::If _if = createWithLocation<assembly::If>();
|
||||||
m_scanner->next();
|
m_scanner->next();
|
||||||
_if.condition = make_shared<Statement>(parseExpression());
|
_if.condition = make_shared<Expression>(parseExpression());
|
||||||
if (_if.condition->type() == typeid(assembly::Instruction))
|
|
||||||
fatalParserError("Instructions are not supported as conditions for if - try to append \"()\".");
|
|
||||||
_if.body = parseBlock();
|
_if.body = parseBlock();
|
||||||
return _if;
|
return _if;
|
||||||
}
|
}
|
||||||
@ -87,9 +85,7 @@ assembly::Statement Parser::parseStatement()
|
|||||||
{
|
{
|
||||||
assembly::Switch _switch = createWithLocation<assembly::Switch>();
|
assembly::Switch _switch = createWithLocation<assembly::Switch>();
|
||||||
m_scanner->next();
|
m_scanner->next();
|
||||||
_switch.expression = make_shared<Statement>(parseExpression());
|
_switch.expression = make_shared<Expression>(parseExpression());
|
||||||
if (_switch.expression->type() == typeid(assembly::Instruction))
|
|
||||||
fatalParserError("Instructions are not supported as expressions for switch - try to append \"()\".");
|
|
||||||
while (m_scanner->currentToken() == Token::Case)
|
while (m_scanner->currentToken() == Token::Case)
|
||||||
_switch.cases.emplace_back(parseCase());
|
_switch.cases.emplace_back(parseCase());
|
||||||
if (m_scanner->currentToken() == Token::Default)
|
if (m_scanner->currentToken() == Token::Default)
|
||||||
@ -127,18 +123,21 @@ assembly::Statement Parser::parseStatement()
|
|||||||
// Simple instruction (might turn into functional),
|
// Simple instruction (might turn into functional),
|
||||||
// literal,
|
// literal,
|
||||||
// identifier (might turn into label or functional assignment)
|
// identifier (might turn into label or functional assignment)
|
||||||
Statement statement(parseElementaryOperation(false));
|
ElementaryOperation elementary(parseElementaryOperation(false));
|
||||||
switch (currentToken())
|
switch (currentToken())
|
||||||
{
|
{
|
||||||
case Token::LParen:
|
case Token::LParen:
|
||||||
return parseCall(std::move(statement));
|
{
|
||||||
|
Expression expr = parseCall(std::move(elementary));
|
||||||
|
return ExpressionStatement{locationOf(expr), expr};
|
||||||
|
}
|
||||||
case Token::Comma:
|
case Token::Comma:
|
||||||
{
|
{
|
||||||
// if a comma follows, a multiple assignment is assumed
|
// if a comma follows, a multiple assignment is assumed
|
||||||
|
|
||||||
if (statement.type() != typeid(assembly::Identifier))
|
if (elementary.type() != typeid(assembly::Identifier))
|
||||||
fatalParserError("Label name / variable name must precede \",\" (multiple assignment).");
|
fatalParserError("Label name / variable name must precede \",\" (multiple assignment).");
|
||||||
assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement);
|
assembly::Identifier const& identifier = boost::get<assembly::Identifier>(elementary);
|
||||||
|
|
||||||
Assignment assignment = createWithLocation<Assignment>(identifier.location);
|
Assignment assignment = createWithLocation<Assignment>(identifier.location);
|
||||||
assignment.variableNames.emplace_back(identifier);
|
assignment.variableNames.emplace_back(identifier);
|
||||||
@ -146,25 +145,25 @@ assembly::Statement Parser::parseStatement()
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
expectToken(Token::Comma);
|
expectToken(Token::Comma);
|
||||||
statement = parseElementaryOperation(false);
|
elementary = parseElementaryOperation(false);
|
||||||
if (statement.type() != typeid(assembly::Identifier))
|
if (elementary.type() != typeid(assembly::Identifier))
|
||||||
fatalParserError("Variable name expected in multiple assignemnt.");
|
fatalParserError("Variable name expected in multiple assignemnt.");
|
||||||
assignment.variableNames.emplace_back(boost::get<assembly::Identifier>(statement));
|
assignment.variableNames.emplace_back(boost::get<assembly::Identifier>(elementary));
|
||||||
}
|
}
|
||||||
while (currentToken() == Token::Comma);
|
while (currentToken() == Token::Comma);
|
||||||
|
|
||||||
expectToken(Token::Colon);
|
expectToken(Token::Colon);
|
||||||
expectToken(Token::Assign);
|
expectToken(Token::Assign);
|
||||||
|
|
||||||
assignment.value.reset(new Statement(parseExpression()));
|
assignment.value.reset(new Expression(parseExpression()));
|
||||||
assignment.location.end = locationOf(*assignment.value).end;
|
assignment.location.end = locationOf(*assignment.value).end;
|
||||||
return assignment;
|
return assignment;
|
||||||
}
|
}
|
||||||
case Token::Colon:
|
case Token::Colon:
|
||||||
{
|
{
|
||||||
if (statement.type() != typeid(assembly::Identifier))
|
if (elementary.type() != typeid(assembly::Identifier))
|
||||||
fatalParserError("Label name / variable name must precede \":\".");
|
fatalParserError("Label name / variable name must precede \":\".");
|
||||||
assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement);
|
assembly::Identifier const& identifier = boost::get<assembly::Identifier>(elementary);
|
||||||
advance();
|
advance();
|
||||||
// identifier:=: should be parsed as identifier: =: (i.e. a label),
|
// identifier:=: should be parsed as identifier: =: (i.e. a label),
|
||||||
// while identifier:= (being followed by a non-colon) as identifier := (assignment).
|
// while identifier:= (being followed by a non-colon) as identifier := (assignment).
|
||||||
@ -175,7 +174,7 @@ assembly::Statement Parser::parseStatement()
|
|||||||
fatalParserError("Cannot use instruction names for identifier names.");
|
fatalParserError("Cannot use instruction names for identifier names.");
|
||||||
advance();
|
advance();
|
||||||
assignment.variableNames.emplace_back(identifier);
|
assignment.variableNames.emplace_back(identifier);
|
||||||
assignment.value.reset(new Statement(parseExpression()));
|
assignment.value.reset(new Expression(parseExpression()));
|
||||||
assignment.location.end = locationOf(*assignment.value).end;
|
assignment.location.end = locationOf(*assignment.value).end;
|
||||||
return assignment;
|
return assignment;
|
||||||
}
|
}
|
||||||
@ -194,7 +193,21 @@ assembly::Statement Parser::parseStatement()
|
|||||||
fatalParserError("Call or assignment expected.");
|
fatalParserError("Call or assignment expected.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return statement;
|
if (elementary.type() == typeid(assembly::Identifier))
|
||||||
|
{
|
||||||
|
Expression expr = boost::get<assembly::Identifier>(elementary);
|
||||||
|
return ExpressionStatement{locationOf(expr), expr};
|
||||||
|
}
|
||||||
|
else if (elementary.type() == typeid(assembly::Literal))
|
||||||
|
{
|
||||||
|
Expression expr = boost::get<assembly::Literal>(elementary);
|
||||||
|
return ExpressionStatement{locationOf(expr), expr};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solAssert(elementary.type() == typeid(assembly::Instruction), "Invalid elementary operation.");
|
||||||
|
return boost::get<assembly::Instruction>(elementary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assembly::Case Parser::parseCase()
|
assembly::Case Parser::parseCase()
|
||||||
@ -206,10 +219,10 @@ assembly::Case Parser::parseCase()
|
|||||||
else if (m_scanner->currentToken() == Token::Case)
|
else if (m_scanner->currentToken() == Token::Case)
|
||||||
{
|
{
|
||||||
m_scanner->next();
|
m_scanner->next();
|
||||||
assembly::Statement statement = parseElementaryOperation();
|
ElementaryOperation literal = parseElementaryOperation();
|
||||||
if (statement.type() != typeid(assembly::Literal))
|
if (literal.type() != typeid(assembly::Literal))
|
||||||
fatalParserError("Literal expected.");
|
fatalParserError("Literal expected.");
|
||||||
_case.value = make_shared<Literal>(std::move(boost::get<assembly::Literal>(statement)));
|
_case.value = make_shared<Literal>(boost::get<assembly::Literal>(std::move(literal)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fatalParserError("Case or default case expected.");
|
fatalParserError("Case or default case expected.");
|
||||||
@ -224,19 +237,17 @@ assembly::ForLoop Parser::parseForLoop()
|
|||||||
ForLoop forLoop = createWithLocation<ForLoop>();
|
ForLoop forLoop = createWithLocation<ForLoop>();
|
||||||
expectToken(Token::For);
|
expectToken(Token::For);
|
||||||
forLoop.pre = parseBlock();
|
forLoop.pre = parseBlock();
|
||||||
forLoop.condition = make_shared<Statement>(parseExpression());
|
forLoop.condition = make_shared<Expression>(parseExpression());
|
||||||
if (forLoop.condition->type() == typeid(assembly::Instruction))
|
|
||||||
fatalParserError("Instructions are not supported as conditions for the for statement.");
|
|
||||||
forLoop.post = parseBlock();
|
forLoop.post = parseBlock();
|
||||||
forLoop.body = parseBlock();
|
forLoop.body = parseBlock();
|
||||||
forLoop.location.end = forLoop.body.location.end;
|
forLoop.location.end = forLoop.body.location.end;
|
||||||
return forLoop;
|
return forLoop;
|
||||||
}
|
}
|
||||||
|
|
||||||
assembly::Statement Parser::parseExpression()
|
assembly::Expression Parser::parseExpression()
|
||||||
{
|
{
|
||||||
RecursionGuard recursionGuard(*this);
|
RecursionGuard recursionGuard(*this);
|
||||||
Statement operation = parseElementaryOperation(true);
|
ElementaryOperation operation = parseElementaryOperation(true);
|
||||||
if (operation.type() == typeid(Instruction))
|
if (operation.type() == typeid(Instruction))
|
||||||
{
|
{
|
||||||
Instruction const& instr = boost::get<Instruction>(operation);
|
Instruction const& instr = boost::get<Instruction>(operation);
|
||||||
@ -252,8 +263,18 @@ assembly::Statement Parser::parseExpression()
|
|||||||
}
|
}
|
||||||
if (currentToken() == Token::LParen)
|
if (currentToken() == Token::LParen)
|
||||||
return parseCall(std::move(operation));
|
return parseCall(std::move(operation));
|
||||||
|
else if (operation.type() == typeid(Instruction))
|
||||||
|
{
|
||||||
|
Instruction& instr = boost::get<Instruction>(operation);
|
||||||
|
return FunctionalInstruction{std::move(instr.location), instr.instruction, {}};
|
||||||
|
}
|
||||||
|
else if (operation.type() == typeid(assembly::Identifier))
|
||||||
|
return boost::get<assembly::Identifier>(operation);
|
||||||
else
|
else
|
||||||
return operation;
|
{
|
||||||
|
solAssert(operation.type() == typeid(assembly::Literal), "");
|
||||||
|
return boost::get<assembly::Literal>(operation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<string, dev::solidity::Instruction> const& Parser::instructions()
|
std::map<string, dev::solidity::Instruction> const& Parser::instructions()
|
||||||
@ -296,10 +317,10 @@ std::map<dev::solidity::Instruction, string> const& Parser::instructionNames()
|
|||||||
return s_instructionNames;
|
return s_instructionNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
|
Parser::ElementaryOperation Parser::parseElementaryOperation(bool _onlySinglePusher)
|
||||||
{
|
{
|
||||||
RecursionGuard recursionGuard(*this);
|
RecursionGuard recursionGuard(*this);
|
||||||
Statement ret;
|
ElementaryOperation ret;
|
||||||
switch (currentToken())
|
switch (currentToken())
|
||||||
{
|
{
|
||||||
case Token::Identifier:
|
case Token::Identifier:
|
||||||
@ -402,7 +423,7 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration()
|
|||||||
{
|
{
|
||||||
expectToken(Token::Colon);
|
expectToken(Token::Colon);
|
||||||
expectToken(Token::Assign);
|
expectToken(Token::Assign);
|
||||||
varDecl.value.reset(new Statement(parseExpression()));
|
varDecl.value.reset(new Expression(parseExpression()));
|
||||||
varDecl.location.end = locationOf(*varDecl.value).end;
|
varDecl.location.end = locationOf(*varDecl.value).end;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -442,13 +463,13 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition()
|
|||||||
return funDef;
|
return funDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
|
assembly::Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp)
|
||||||
{
|
{
|
||||||
RecursionGuard recursionGuard(*this);
|
RecursionGuard recursionGuard(*this);
|
||||||
if (_instruction.type() == typeid(Instruction))
|
if (_initialOp.type() == typeid(Instruction))
|
||||||
{
|
{
|
||||||
solAssert(!m_julia, "Instructions are invalid in JULIA");
|
solAssert(!m_julia, "Instructions are invalid in JULIA");
|
||||||
Instruction const& instruction = std::move(boost::get<Instruction>(_instruction));
|
Instruction& instruction = boost::get<Instruction>(_initialOp);
|
||||||
FunctionalInstruction ret;
|
FunctionalInstruction ret;
|
||||||
ret.instruction = instruction.instruction;
|
ret.instruction = instruction.instruction;
|
||||||
ret.location = std::move(instruction.location);
|
ret.location = std::move(instruction.location);
|
||||||
@ -499,10 +520,10 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
|
|||||||
expectToken(Token::RParen);
|
expectToken(Token::RParen);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
else if (_instruction.type() == typeid(Identifier))
|
else if (_initialOp.type() == typeid(Identifier))
|
||||||
{
|
{
|
||||||
FunctionCall ret;
|
FunctionCall ret;
|
||||||
ret.functionName = std::move(boost::get<Identifier>(_instruction));
|
ret.functionName = std::move(boost::get<Identifier>(_initialOp));
|
||||||
ret.location = ret.functionName.location;
|
ret.location = ret.functionName.location;
|
||||||
expectToken(Token::LParen);
|
expectToken(Token::LParen);
|
||||||
while (currentToken() != Token::RParen)
|
while (currentToken() != Token::RParen)
|
||||||
|
@ -44,6 +44,8 @@ public:
|
|||||||
std::shared_ptr<Block> parse(std::shared_ptr<Scanner> const& _scanner);
|
std::shared_ptr<Block> parse(std::shared_ptr<Scanner> const& _scanner);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
using ElementaryOperation = boost::variant<assembly::Instruction, assembly::Literal, assembly::Identifier>;
|
||||||
|
|
||||||
/// Creates an inline assembly node with the given source location.
|
/// Creates an inline assembly node with the given source location.
|
||||||
template <class T> T createWithLocation(SourceLocation const& _loc = SourceLocation()) const
|
template <class T> T createWithLocation(SourceLocation const& _loc = SourceLocation()) const
|
||||||
{
|
{
|
||||||
@ -65,13 +67,13 @@ protected:
|
|||||||
Case parseCase();
|
Case parseCase();
|
||||||
ForLoop parseForLoop();
|
ForLoop parseForLoop();
|
||||||
/// Parses a functional expression that has to push exactly one stack element
|
/// Parses a functional expression that has to push exactly one stack element
|
||||||
Statement parseExpression();
|
assembly::Expression parseExpression();
|
||||||
static std::map<std::string, dev::solidity::Instruction> const& instructions();
|
static std::map<std::string, dev::solidity::Instruction> const& instructions();
|
||||||
static std::map<dev::solidity::Instruction, std::string> const& instructionNames();
|
static std::map<dev::solidity::Instruction, std::string> const& instructionNames();
|
||||||
Statement parseElementaryOperation(bool _onlySinglePusher = false);
|
ElementaryOperation parseElementaryOperation(bool _onlySinglePusher = false);
|
||||||
VariableDeclaration parseVariableDeclaration();
|
VariableDeclaration parseVariableDeclaration();
|
||||||
FunctionDefinition parseFunctionDefinition();
|
FunctionDefinition parseFunctionDefinition();
|
||||||
Statement parseCall(Statement&& _instruction);
|
assembly::Expression parseCall(ElementaryOperation&& _initialOp);
|
||||||
TypedName parseTypedName();
|
TypedName parseTypedName();
|
||||||
std::string expectAsmIdentifier();
|
std::string expectAsmIdentifier();
|
||||||
|
|
||||||
|
@ -102,6 +102,11 @@ string AsmPrinter::operator()(assembly::FunctionalInstruction const& _functional
|
|||||||
")";
|
")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string AsmPrinter::operator()(ExpressionStatement const& _statement)
|
||||||
|
{
|
||||||
|
return boost::apply_visitor(*this, _statement.expression);
|
||||||
|
}
|
||||||
|
|
||||||
string AsmPrinter::operator()(assembly::Label const& _label)
|
string AsmPrinter::operator()(assembly::Label const& _label)
|
||||||
{
|
{
|
||||||
solAssert(!m_julia, "");
|
solAssert(!m_julia, "");
|
||||||
|
@ -42,6 +42,7 @@ public:
|
|||||||
std::string operator()(assembly::Literal const& _literal);
|
std::string operator()(assembly::Literal const& _literal);
|
||||||
std::string operator()(assembly::Identifier const& _identifier);
|
std::string operator()(assembly::Identifier const& _identifier);
|
||||||
std::string operator()(assembly::FunctionalInstruction const& _functionalInstruction);
|
std::string operator()(assembly::FunctionalInstruction const& _functionalInstruction);
|
||||||
|
std::string operator()(assembly::ExpressionStatement const& _expr);
|
||||||
std::string operator()(assembly::Label const& _label);
|
std::string operator()(assembly::Label const& _label);
|
||||||
std::string operator()(assembly::StackAssignment const& _assignment);
|
std::string operator()(assembly::StackAssignment const& _assignment);
|
||||||
std::string operator()(assembly::Assignment const& _assignment);
|
std::string operator()(assembly::Assignment const& _assignment);
|
||||||
|
@ -45,6 +45,11 @@ ScopeFiller::ScopeFiller(AsmAnalysisInfo& _info, ErrorReporter& _errorReporter):
|
|||||||
m_currentScope = &scope(nullptr);
|
m_currentScope = &scope(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ScopeFiller::operator()(ExpressionStatement const& _expr)
|
||||||
|
{
|
||||||
|
return boost::apply_visitor(*this, _expr.expression);
|
||||||
|
}
|
||||||
|
|
||||||
bool ScopeFiller::operator()(Label const& _item)
|
bool ScopeFiller::operator()(Label const& _item)
|
||||||
{
|
{
|
||||||
if (!m_currentScope->registerLabel(_item.name))
|
if (!m_currentScope->registerLabel(_item.name))
|
||||||
|
@ -53,6 +53,7 @@ public:
|
|||||||
bool operator()(assembly::Literal const&) { return true; }
|
bool operator()(assembly::Literal const&) { return true; }
|
||||||
bool operator()(assembly::Identifier const&) { return true; }
|
bool operator()(assembly::Identifier const&) { return true; }
|
||||||
bool operator()(assembly::FunctionalInstruction const&) { return true; }
|
bool operator()(assembly::FunctionalInstruction const&) { return true; }
|
||||||
|
bool operator()(assembly::ExpressionStatement const& _expr);
|
||||||
bool operator()(assembly::Label const& _label);
|
bool operator()(assembly::Label const& _label);
|
||||||
bool operator()(assembly::StackAssignment const&) { return true; }
|
bool operator()(assembly::StackAssignment const&) { return true; }
|
||||||
bool operator()(assembly::Assignment const&) { return true; }
|
bool operator()(assembly::Assignment const&) { return true; }
|
||||||
|
@ -266,7 +266,7 @@ BOOST_AUTO_TEST_CASE(if_statement_scope)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(if_statement_invalid)
|
BOOST_AUTO_TEST_CASE(if_statement_invalid)
|
||||||
{
|
{
|
||||||
CHECK_PARSE_ERROR("{ if calldatasize {}", ParserError, "Instructions are not supported as conditions for if");
|
CHECK_PARSE_ERROR("{ if mload {} }", ParserError, "Expected token \"(\"");
|
||||||
BOOST_CHECK("{ if calldatasize() {}");
|
BOOST_CHECK("{ if calldatasize() {}");
|
||||||
CHECK_PARSE_ERROR("{ if mstore(1, 1) {} }", ParserError, "Instruction \"mstore\" not allowed in this context");
|
CHECK_PARSE_ERROR("{ if mstore(1, 1) {} }", ParserError, "Instruction \"mstore\" not allowed in this context");
|
||||||
CHECK_PARSE_ERROR("{ if 32 let x := 3 }", ParserError, "Expected token LBrace");
|
CHECK_PARSE_ERROR("{ if 32 let x := 3 }", ParserError, "Expected token LBrace");
|
||||||
@ -296,7 +296,7 @@ BOOST_AUTO_TEST_CASE(switch_duplicate_case)
|
|||||||
BOOST_AUTO_TEST_CASE(switch_invalid_expression)
|
BOOST_AUTO_TEST_CASE(switch_invalid_expression)
|
||||||
{
|
{
|
||||||
CHECK_PARSE_ERROR("{ switch {} default {} }", ParserError, "Literal, identifier or instruction expected.");
|
CHECK_PARSE_ERROR("{ switch {} default {} }", ParserError, "Literal, identifier or instruction expected.");
|
||||||
CHECK_PARSE_ERROR("{ switch calldatasize default {} }", ParserError, "Instructions are not supported as expressions for switch");
|
CHECK_PARSE_ERROR("{ switch mload default {} }", ParserError, "Expected token \"(\"");
|
||||||
CHECK_PARSE_ERROR("{ switch mstore(1, 1) default {} }", ParserError, "Instruction \"mstore\" not allowed in this context");
|
CHECK_PARSE_ERROR("{ switch mstore(1, 1) default {} }", ParserError, "Instruction \"mstore\" not allowed in this context");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +332,7 @@ BOOST_AUTO_TEST_CASE(for_invalid_expression)
|
|||||||
CHECK_PARSE_ERROR("{ for 1 1 {} {} }", ParserError, "Expected token LBrace got 'Number'");
|
CHECK_PARSE_ERROR("{ for 1 1 {} {} }", ParserError, "Expected token LBrace got 'Number'");
|
||||||
CHECK_PARSE_ERROR("{ for {} 1 1 {} }", ParserError, "Expected token LBrace got 'Number'");
|
CHECK_PARSE_ERROR("{ for {} 1 1 {} }", ParserError, "Expected token LBrace got 'Number'");
|
||||||
CHECK_PARSE_ERROR("{ for {} 1 {} 1 }", ParserError, "Expected token LBrace got 'Number'");
|
CHECK_PARSE_ERROR("{ for {} 1 {} 1 }", ParserError, "Expected token LBrace got 'Number'");
|
||||||
CHECK_PARSE_ERROR("{ for {} calldatasize {} {} }", ParserError, "Instructions are not supported as conditions for the for statement.");
|
CHECK_PARSE_ERROR("{ for {} mload {} {} }", ParserError, "Expected token \"(\"");
|
||||||
CHECK_PARSE_ERROR("{ for {} mstore(1, 1) {} {} }", ParserError, "Instruction \"mstore\" not allowed in this context");
|
CHECK_PARSE_ERROR("{ for {} mstore(1, 1) {} {} }", ParserError, "Instruction \"mstore\" not allowed in this context");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,7 +540,7 @@ BOOST_AUTO_TEST_CASE(function_calls)
|
|||||||
function g(a, b, c)
|
function g(a, b, c)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
g(1, mul(2, address), f(mul(2, caller)))
|
g(1, mul(2, address()), f(mul(2, caller())))
|
||||||
y()
|
y()
|
||||||
})";
|
})";
|
||||||
boost::replace_all(source, "\t", " ");
|
boost::replace_all(source, "\t", " ");
|
||||||
|
Loading…
Reference in New Issue
Block a user