mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
User-defined operators: Code generation
This commit is contained in:
parent
e4904cd608
commit
c3d3285921
@ -410,6 +410,38 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
|
||||
bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
|
||||
{
|
||||
CompilerContext::LocationSetter locationSetter(m_context, _unaryOperation);
|
||||
|
||||
FunctionDefinition const* function = *_unaryOperation.annotation().userDefinedFunction;
|
||||
if (function)
|
||||
{
|
||||
solAssert(function->isFree() || function->libraryFunction());
|
||||
|
||||
FunctionType const* functionType = _unaryOperation.userDefinedFunctionType();
|
||||
solAssert(functionType);
|
||||
|
||||
functionType = dynamic_cast<FunctionType const&>(*functionType).withBoundFirstArgument();
|
||||
solAssert(functionType);
|
||||
evmasm::AssemblyItem returnLabel = m_context.pushNewTag();
|
||||
acceptAndConvert(_unaryOperation.subExpression(), *functionType->selfType());
|
||||
|
||||
m_context << m_context.functionEntryLabel(*function).pushTag();
|
||||
m_context.appendJump(evmasm::AssemblyItem::JumpType::IntoFunction);
|
||||
m_context << returnLabel;
|
||||
|
||||
solAssert(
|
||||
functionType->parameterTypes().size() == 0,
|
||||
"Unary operator definition is supposed to accept only the 'self' parameter."
|
||||
);
|
||||
|
||||
unsigned parameterSize = functionType->selfType()->sizeOnStack();
|
||||
unsigned returnParametersSize = CompilerUtils::sizeOnStack(functionType->returnParameterTypes());
|
||||
|
||||
// callee adds return parameters, but removes arguments and return label
|
||||
m_context.adjustStackOffset(static_cast<int>(returnParametersSize - parameterSize) - 1);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Type const& type = *_unaryOperation.annotation().type;
|
||||
if (type.category() == Type::Category::RationalNumber)
|
||||
{
|
||||
@ -502,7 +534,39 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
|
||||
CompilerContext::LocationSetter locationSetter(m_context, _binaryOperation);
|
||||
Expression const& leftExpression = _binaryOperation.leftExpression();
|
||||
Expression const& rightExpression = _binaryOperation.rightExpression();
|
||||
solAssert(!!_binaryOperation.annotation().commonType, "");
|
||||
FunctionDefinition const* function = *_binaryOperation.annotation().userDefinedFunction;
|
||||
if (function)
|
||||
{
|
||||
solAssert(function->isFree() || function->libraryFunction());
|
||||
|
||||
FunctionType const* functionType = _binaryOperation.userDefinedFunctionType();
|
||||
solAssert(functionType);
|
||||
functionType = dynamic_cast<FunctionType const&>(*functionType).withBoundFirstArgument();
|
||||
solAssert(functionType);
|
||||
|
||||
solAssert(
|
||||
functionType->parameterTypes().size() == 1,
|
||||
"Binary operator definition is supposed to accept only 'self' and one extra parameter."
|
||||
);
|
||||
evmasm::AssemblyItem returnLabel = m_context.pushNewTag();
|
||||
acceptAndConvert(leftExpression, *functionType->selfType());
|
||||
acceptAndConvert(rightExpression, *functionType->parameterTypes()[0]);
|
||||
|
||||
m_context << m_context.functionEntryLabel(*function).pushTag();
|
||||
m_context.appendJump(evmasm::AssemblyItem::JumpType::IntoFunction);
|
||||
m_context << returnLabel;
|
||||
|
||||
unsigned parameterSize =
|
||||
CompilerUtils::sizeOnStack(functionType->parameterTypes()) +
|
||||
functionType->selfType()->sizeOnStack();
|
||||
|
||||
unsigned returnParametersSize = CompilerUtils::sizeOnStack(functionType->returnParameterTypes());
|
||||
// callee adds return parameters, but removes arguments and return label
|
||||
m_context.adjustStackOffset(static_cast<int>(returnParametersSize - parameterSize) - 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
solAssert(!!_binaryOperation.annotation().commonType);
|
||||
Type const* commonType = _binaryOperation.annotation().commonType;
|
||||
Token const c_op = _binaryOperation.getOperator();
|
||||
|
||||
|
@ -672,6 +672,41 @@ void IRGeneratorForStatements::endVisit(Return const& _return)
|
||||
bool IRGeneratorForStatements::visit(UnaryOperation const& _unaryOperation)
|
||||
{
|
||||
setLocation(_unaryOperation);
|
||||
|
||||
FunctionDefinition const* function = *_unaryOperation.annotation().userDefinedFunction;
|
||||
if (function)
|
||||
{
|
||||
_unaryOperation.subExpression().accept(*this);
|
||||
setLocation(_unaryOperation);
|
||||
|
||||
solAssert(function->isFree() || function->libraryFunction());
|
||||
|
||||
FunctionType const* functionType = _unaryOperation.userDefinedFunctionType();
|
||||
solAssert(functionType);
|
||||
functionType = dynamic_cast<FunctionType const&>(*functionType).withBoundFirstArgument();
|
||||
solAssert(functionType);
|
||||
solAssert(
|
||||
functionType->parameterTypes().size() == 0,
|
||||
"Unary operator definition is supposed to accept only the 'self' parameter."
|
||||
);
|
||||
|
||||
string argument = expressionAsType(_unaryOperation.subExpression(), *functionType->selfType());
|
||||
solAssert(!argument.empty());
|
||||
solAssert(function->isImplemented());
|
||||
|
||||
solAssert(function->returnParameters().size() == 1);
|
||||
solAssert(
|
||||
*_unaryOperation.annotation().type == *function->returnParameters()[0]->type(),
|
||||
"The return type of the operator definition is supposed to match the type of the expression."
|
||||
);
|
||||
|
||||
define(_unaryOperation) <<
|
||||
m_context.enqueueFunctionForCodeGeneration(*function) <<
|
||||
("(" + argument + ")\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Type const& resultType = type(_unaryOperation);
|
||||
Token const op = _unaryOperation.getOperator();
|
||||
|
||||
@ -775,6 +810,43 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
|
||||
{
|
||||
setLocation(_binOp);
|
||||
|
||||
FunctionDefinition const* function = *_binOp.annotation().userDefinedFunction;
|
||||
if (function)
|
||||
{
|
||||
_binOp.leftExpression().accept(*this);
|
||||
_binOp.rightExpression().accept(*this);
|
||||
setLocation(_binOp);
|
||||
|
||||
solAssert(function->isFree() || function->libraryFunction());
|
||||
|
||||
FunctionType const* functionType = _binOp.userDefinedFunctionType();
|
||||
solAssert(functionType);
|
||||
functionType = dynamic_cast<FunctionType const&>(*functionType).withBoundFirstArgument();
|
||||
solAssert(functionType);
|
||||
solAssert(
|
||||
functionType->parameterTypes().size() == 1,
|
||||
"Binary operator definition is supposed to accept only 'self' and one extra parameter."
|
||||
);
|
||||
|
||||
string left = expressionAsType(_binOp.leftExpression(), *functionType->selfType());
|
||||
string right = expressionAsType(_binOp.rightExpression(), *functionType->parameterTypes()[0]);
|
||||
solAssert(!left.empty() && !right.empty());
|
||||
|
||||
solAssert(function->isImplemented());
|
||||
|
||||
solAssert(function->returnParameters().size() == 1);
|
||||
solAssert(
|
||||
*_binOp.annotation().type == *function->returnParameters()[0]->type(),
|
||||
"The return type of the operator definition is supposed to match the type of the expression."
|
||||
);
|
||||
|
||||
define(_binOp) <<
|
||||
m_context.enqueueFunctionForCodeGeneration(*function) <<
|
||||
("(" + left + ", " + right + ")\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
solAssert(!!_binOp.annotation().commonType);
|
||||
Type const* commonType = _binOp.annotation().commonType;
|
||||
langutil::Token op = _binOp.getOperator();
|
||||
|
Loading…
Reference in New Issue
Block a user