mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
tmp
This commit is contained in:
parent
5adc255b3c
commit
987278385e
@ -39,88 +39,130 @@ ASTTransform::ASTTransform(Analysis& _analysis): m_analysis(_analysis), m_errorR
|
||||
{
|
||||
}
|
||||
|
||||
bool ASTTransform::visit(legacy::ContractDefinition const& _contractDefinition)
|
||||
bool ASTTransform::visit(legacy::TypeDefinition const& _typeDefinition)
|
||||
{
|
||||
SetNode setNode(*this, _contractDefinition);
|
||||
auto [it, newlyInserted] = m_ast->contracts.emplace(&_contractDefinition, AST::ContractInfo{});
|
||||
SetNode setNode(*this, _typeDefinition);
|
||||
auto [it, newlyInserted] = m_ast->typeDefinitions.emplace(&_typeDefinition, term(_typeDefinition));
|
||||
solAssert(newlyInserted);
|
||||
AST::ContractInfo& contractInfo = it->second;
|
||||
for (auto const& node: _contractDefinition.subNodes())
|
||||
if (auto const* function = dynamic_cast<legacy::FunctionDefinition const*>(node.get()))
|
||||
solAssert(contractInfo.functions.emplace(string{}, functionDefinition(*function)).second);
|
||||
else
|
||||
m_errorReporter.typeError(0000_error, node->location(), "Unsupported contract element.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ASTTransform::visit(legacy::FunctionDefinition const& _functionDefinition)
|
||||
{
|
||||
SetNode setNode(*this, _functionDefinition);
|
||||
solAssert(m_ast->functions.emplace(&_functionDefinition, functionDefinition(_functionDefinition)).second);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ASTTransform::visit(legacy::TypeClassDefinition const& _typeClassDefinition)
|
||||
{
|
||||
SetNode setNode(*this, _typeClassDefinition);
|
||||
auto [it, newlyInserted] = m_ast->typeClasses.emplace(&_typeClassDefinition, AST::TypeClassInformation{});
|
||||
auto [it, newlyInserted] = m_ast->typeClasses.emplace(&_typeClassDefinition, term(_typeClassDefinition));
|
||||
solAssert(newlyInserted);
|
||||
auto& info = it->second;
|
||||
info.typeVariable = term(_typeClassDefinition.typeVariable());
|
||||
info.declaration = reference(_typeClassDefinition);
|
||||
declare(_typeClassDefinition, *info.declaration);
|
||||
map<std::string, AST::FunctionInfo>& functions = info.functions;
|
||||
for (auto subNode: _typeClassDefinition.subNodes())
|
||||
{
|
||||
auto const *function = dynamic_cast<FunctionDefinition const*>(subNode.get());
|
||||
solAssert(function);
|
||||
solAssert(functions.emplace(function->name(), functionDefinition(*function)).second);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ASTTransform::visit(legacy::TypeClassInstantiation const& _typeClassInstantiation)
|
||||
{
|
||||
SetNode setNode(*this, _typeClassInstantiation);
|
||||
auto [it, newlyInserted] = m_ast->typeClassInstantiations.emplace(&_typeClassInstantiation, AST::TypeClassInstantiationInformation{});
|
||||
auto [it, newlyInserted] = m_ast->typeClassInstantiations.emplace(&_typeClassInstantiation, term(_typeClassInstantiation));
|
||||
solAssert(newlyInserted);
|
||||
auto& info = it->second;
|
||||
info.typeClass = std::visit(util::GenericVisitor{
|
||||
[&](Token _token) -> unique_ptr<Term> { return builtinTypeClass(_token); },
|
||||
[&](ASTPointer<legacy::IdentifierPath> _identifierPath) -> unique_ptr<Term> {
|
||||
solAssert(_identifierPath->annotation().referencedDeclaration);
|
||||
return reference(*_identifierPath->annotation().referencedDeclaration);
|
||||
}
|
||||
}, _typeClassInstantiation.typeClass().name());
|
||||
info.typeConstructor = term(_typeClassInstantiation.typeConstructor());
|
||||
info.argumentSorts = termOrConstant(_typeClassInstantiation.argumentSorts(), BuiltinConstant::Unit);
|
||||
map<std::string, AST::FunctionInfo>& functions = info.functions;
|
||||
for (auto subNode: _typeClassInstantiation.subNodes())
|
||||
{
|
||||
auto const *function = dynamic_cast<FunctionDefinition const*>(subNode.get());
|
||||
solAssert(function);
|
||||
solAssert(functions.emplace(function->name(), functionDefinition(*function)).second);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ASTTransform::visit(legacy::TypeDefinition const& _typeDefinition)
|
||||
bool ASTTransform::visit(legacy::ContractDefinition const& _contractDefinition)
|
||||
{
|
||||
SetNode setNode(*this, _contractDefinition);
|
||||
auto [it, newlyInserted] = m_ast->contracts.emplace(&_contractDefinition, term(_contractDefinition));
|
||||
solAssert(newlyInserted);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ASTTransform::visit(legacy::FunctionDefinition const& _functionDefinition)
|
||||
{
|
||||
SetNode setNode(*this, _functionDefinition);
|
||||
solAssert(m_ast->functions.emplace(&_functionDefinition, term(_functionDefinition)).second);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ASTTransform::visitNode(ASTNode const& _node)
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _node.location(), "Unexpected AST node during AST transform.");
|
||||
return false;
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::term(legacy::TypeDefinition const& _typeDefinition)
|
||||
{
|
||||
SetNode setNode(*this, _typeDefinition);
|
||||
auto [it, newlyInserted] = m_ast->typeDefinitions.emplace(&_typeDefinition, AST::TypeInformation{});
|
||||
solAssert(newlyInserted);
|
||||
auto& info = it->second;
|
||||
info.declaration = makeTerm<VariableDeclaration>(reference(_typeDefinition), nullptr);
|
||||
declare(_typeDefinition, *info.declaration);
|
||||
if (_typeDefinition.arguments())
|
||||
info.arguments = tuple(_typeDefinition.arguments()->parameters() | ranges::view::transform([&](auto argument){
|
||||
solAssert(!argument->typeExpression()); // TODO: error handling
|
||||
return term(*argument);
|
||||
}) | ranges::view::move | ranges::to<list<unique_ptr<Term>>>);
|
||||
unique_ptr<Term> name = reference(_typeDefinition);
|
||||
unique_ptr<Term> arguments = termOrConstant(_typeDefinition.arguments(), BuiltinConstant::Unit);
|
||||
if (_typeDefinition.typeExpression())
|
||||
info.value = term(*_typeDefinition.typeExpression());
|
||||
return false;
|
||||
{
|
||||
unique_ptr<Term> definiens = term(*_typeDefinition.typeExpression());
|
||||
return application(BuiltinConstant::TypeDefinition, std::move(name), std::move(arguments), std::move(definiens));
|
||||
}
|
||||
else
|
||||
return application(BuiltinConstant::TypeDeclaration, std::move(name), std::move(arguments));
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::term(legacy::TypeClassDefinition const& _typeClassDefinition)
|
||||
{
|
||||
SetNode setNode(*this, _typeClassDefinition);
|
||||
unique_ptr<Term> typeVariable = term(_typeClassDefinition.typeVariable());
|
||||
unique_ptr<Term> name = reference(_typeClassDefinition);
|
||||
unique_ptr<Term> functions = namedFunctionList(_typeClassDefinition.subNodes());
|
||||
return application(
|
||||
BuiltinConstant::TypeClassDefinition,
|
||||
std::move(typeVariable),
|
||||
std::move(name),
|
||||
std::move(functions)
|
||||
);
|
||||
}
|
||||
|
||||
std::unique_ptr<Term> ASTTransform::term(legacy::TypeClassInstantiation const& _typeClassInstantiation)
|
||||
{
|
||||
SetNode setNode(*this, _typeClassInstantiation);
|
||||
unique_ptr<Term> typeConstructor = term(_typeClassInstantiation.typeConstructor());
|
||||
unique_ptr<Term> argumentSorts = termOrConstant(_typeClassInstantiation.argumentSorts(), BuiltinConstant::Unit);
|
||||
unique_ptr<Term> typeClass = term(_typeClassInstantiation.typeClass());
|
||||
unique_ptr<Term> functions = namedFunctionList(_typeClassInstantiation.subNodes());
|
||||
return application(
|
||||
BuiltinConstant::TypeClassInstantiation,
|
||||
std::move(typeConstructor),
|
||||
std::move(argumentSorts),
|
||||
std::move(typeClass),
|
||||
std::move(functions)
|
||||
);
|
||||
}
|
||||
|
||||
std::unique_ptr<Term> ASTTransform::term(legacy::FunctionDefinition const& _functionDefinition)
|
||||
{
|
||||
SetNode setNode(*this, _functionDefinition);
|
||||
unique_ptr<Term> name = reference(_functionDefinition);
|
||||
unique_ptr<Term> arguments = term(_functionDefinition.parameterList());
|
||||
unique_ptr<Term> returnType = termOrConstant(_functionDefinition.experimentalReturnExpression(), BuiltinConstant::Unit);
|
||||
if (_functionDefinition.isImplemented())
|
||||
{
|
||||
unique_ptr<Term> body = term(_functionDefinition.body());
|
||||
return application(
|
||||
BuiltinConstant::FunctionDefinition,
|
||||
std::move(name),
|
||||
std::move(arguments),
|
||||
std::move(returnType),
|
||||
std::move(body)
|
||||
);
|
||||
}
|
||||
else
|
||||
return application(
|
||||
BuiltinConstant::FunctionDeclaration,
|
||||
std::move(name),
|
||||
std::move(arguments),
|
||||
std::move(returnType)
|
||||
);
|
||||
}
|
||||
|
||||
std::unique_ptr<Term> ASTTransform::term(legacy::ContractDefinition const& _contractDefinition)
|
||||
{
|
||||
SetNode setNode(*this, _contractDefinition);
|
||||
unique_ptr<Term> name = reference(_contractDefinition);
|
||||
return application(
|
||||
BuiltinConstant::ContractDefinition,
|
||||
std::move(name),
|
||||
namedFunctionList(_contractDefinition.subNodes())
|
||||
);
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::term(legacy::VariableDeclarationStatement const& _declaration)
|
||||
@ -142,10 +184,44 @@ unique_ptr<Term> ASTTransform::term(legacy::Assignment const& _assignment)
|
||||
solAssert(false);
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::term(TypeName const& _name)
|
||||
unique_ptr<Term> ASTTransform::term(legacy::Block const& _block)
|
||||
{
|
||||
SetNode setNode(*this, _block);
|
||||
if (auto statements = ranges::fold_right_last(
|
||||
_block.statements() | ranges::view::transform([&](auto stmt) { return term(*stmt); }) | ranges::view::move,
|
||||
[&](auto stmt, auto acc) {
|
||||
return application(BuiltinConstant::ChainStatements, std::move(stmt), std::move(acc));
|
||||
}
|
||||
))
|
||||
return application(BuiltinConstant::Block, std::move(*statements));
|
||||
else
|
||||
return application(BuiltinConstant::Block, constant(BuiltinConstant::Unit));
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::term(legacy::Statement const& _statement)
|
||||
{
|
||||
SetNode setNode(*this, _statement);
|
||||
if (auto const* assembly = dynamic_cast<legacy::InlineAssembly const*>(&_statement))
|
||||
return application(BuiltinConstant::RegularStatement, *assembly);
|
||||
else if (auto const* declaration = dynamic_cast<legacy::VariableDeclarationStatement const*>(&_statement))
|
||||
return application(BuiltinConstant::RegularStatement, *declaration);
|
||||
else if (auto const* assign = dynamic_cast<legacy::Assignment const*>(&_statement))
|
||||
return application(BuiltinConstant::RegularStatement, *assign);
|
||||
else if (auto const* expressionStatement = dynamic_cast<legacy::ExpressionStatement const*>(&_statement))
|
||||
return application(BuiltinConstant::RegularStatement, expressionStatement->expression());
|
||||
else if (auto const* returnStatement = dynamic_cast<legacy::Return const*>(&_statement))
|
||||
return application(BuiltinConstant::ReturnStatement, termOrConstant(returnStatement->expression(), BuiltinConstant::Unit));
|
||||
else
|
||||
{
|
||||
m_analysis.errorReporter().fatalTypeError(0000_error, _statement.location(), "Unsupported statement.");
|
||||
solAssert(false);
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::term(legacy::TypeName const& _name)
|
||||
{
|
||||
SetNode setNode(*this, _name);
|
||||
if (auto const* elementaryTypeName = dynamic_cast<ElementaryTypeName const*>(&_name))
|
||||
if (auto const* elementaryTypeName = dynamic_cast<legacy::ElementaryTypeName const*>(&_name))
|
||||
{
|
||||
switch (elementaryTypeName->typeName().token())
|
||||
{
|
||||
@ -178,69 +254,23 @@ unique_ptr<Term> ASTTransform::term(TypeName const& _name)
|
||||
solAssert(false);
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::term(legacy::Statement const& _statement)
|
||||
unique_ptr<Term> ASTTransform::term(legacy::TypeClassName const& _typeClassName)
|
||||
{
|
||||
SetNode setNode(*this, _statement);
|
||||
if (auto const* assembly = dynamic_cast<legacy::InlineAssembly const*>(&_statement))
|
||||
return term(*assembly);
|
||||
else if (auto const* declaration = dynamic_cast<legacy::VariableDeclarationStatement const*>(&_statement))
|
||||
return term(*declaration);
|
||||
else if (auto const* assign = dynamic_cast<legacy::Assignment const*>(&_statement))
|
||||
return term(*assign);
|
||||
else if (auto const* expressionStatement = dynamic_cast<legacy::ExpressionStatement const*>(&_statement))
|
||||
return term(expressionStatement->expression());
|
||||
else if (auto const* returnStatement = dynamic_cast<legacy::Return const*>(&_statement))
|
||||
return application(BuiltinConstant::Return, termOrConstant(returnStatement->expression(), BuiltinConstant::Unit));
|
||||
else
|
||||
{
|
||||
m_analysis.errorReporter().fatalTypeError(0000_error, _statement.location(), "Unsupported statement.");
|
||||
solAssert(false);
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::term(legacy::Block const& _block)
|
||||
{
|
||||
SetNode setNode(*this, _block);
|
||||
if (_block.statements().empty())
|
||||
return application(BuiltinConstant::Block, constant(BuiltinConstant::Unit));
|
||||
auto makeStatement = [&](auto _stmt) {
|
||||
return application(BuiltinConstant::Statement, *_stmt);
|
||||
};
|
||||
|
||||
return application(
|
||||
BuiltinConstant::Block,
|
||||
ranges::fold_right(
|
||||
_block.statements() | ranges::view::drop(1),
|
||||
makeStatement(_block.statements().front()),
|
||||
[&](auto stmt, auto acc) {
|
||||
return application(BuiltinConstant::ChainStatements, std::move(acc), makeStatement(stmt));
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
AST::FunctionInfo ASTTransform::functionDefinition(legacy::FunctionDefinition const& _functionDefinition)
|
||||
{
|
||||
SetNode setNode(*this, _functionDefinition);
|
||||
std::unique_ptr<Term> body = nullptr;
|
||||
unique_ptr<Term> argumentExpression = term(_functionDefinition.parameterList());
|
||||
if (_functionDefinition.isImplemented())
|
||||
body = term(_functionDefinition.body());
|
||||
unique_ptr<Term> returnType = termOrConstant(_functionDefinition.experimentalReturnExpression(), BuiltinConstant::Unit);
|
||||
unique_ptr<Term> name = reference(_functionDefinition);
|
||||
unique_ptr<Term> function = makeTerm<VariableDeclaration>(std::move(name), std::move(body));
|
||||
declare(_functionDefinition, *function);
|
||||
return AST::FunctionInfo{
|
||||
std::move(function),
|
||||
std::move(argumentExpression),
|
||||
std::move(returnType)
|
||||
};
|
||||
SetNode setNode(*this, _typeClassName);
|
||||
return std::visit(util::GenericVisitor{
|
||||
[&](Token _token) -> unique_ptr<Term> { return builtinTypeClass(_token); },
|
||||
[&](ASTPointer<legacy::IdentifierPath> _identifierPath) -> unique_ptr<Term> {
|
||||
solAssert(_identifierPath->annotation().referencedDeclaration);
|
||||
return reference(*_identifierPath->annotation().referencedDeclaration);
|
||||
}
|
||||
}, _typeClassName.name());
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::term(legacy::ParameterList const& _parameterList)
|
||||
{
|
||||
SetNode setNode(*this, _parameterList);
|
||||
return tuple(_parameterList.parameters() | ranges::view::transform([&](auto parameter) {
|
||||
solAssert(!parameter->value());
|
||||
return term(*parameter);
|
||||
}) | ranges::view::move | ranges::to<list<unique_ptr<Term>>>);
|
||||
}
|
||||
@ -252,9 +282,10 @@ unique_ptr<Term> ASTTransform::term(legacy::VariableDeclaration const& _variable
|
||||
unique_ptr<Term> name = reference(_variableDeclaration);
|
||||
if (_variableDeclaration.typeExpression())
|
||||
name = constrain(std::move(name), term(*_variableDeclaration.typeExpression()));
|
||||
unique_ptr<Term> declaration = makeTerm<VariableDeclaration>(std::move(name), std::move(_initialValue));
|
||||
declare(_variableDeclaration, *declaration);
|
||||
return declaration;
|
||||
if (_initialValue)
|
||||
return application(BuiltinConstant::VariableDefinition, std::move(name), std::move(_initialValue));
|
||||
else
|
||||
return application(BuiltinConstant::VariableDeclaration, std::move(name));
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::term(legacy::InlineAssembly const& _inlineAssembly)
|
||||
@ -349,47 +380,17 @@ unique_ptr<Term> ASTTransform::term(legacy::Expression const& _expression)
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::binaryOperation(
|
||||
Token _operator,
|
||||
unique_ptr<Term> _leftHandSide,
|
||||
unique_ptr<Term> _rightHandSide
|
||||
)
|
||||
{
|
||||
return application(builtinBinaryOperator(_operator), std::move(_leftHandSide), std::move(_rightHandSide));
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::reference(legacy::Declaration const& _declaration)
|
||||
{
|
||||
auto [it, newlyInserted] = m_declarationIndices.emplace(&_declaration, m_ast->declarations.size());
|
||||
if (newlyInserted)
|
||||
m_ast->declarations.emplace_back(AST::DeclarationInfo{nullptr, {}});
|
||||
return makeTerm<Reference>(it->second);
|
||||
return makeTerm<Reference>(static_cast<size_t>(_declaration.id()), _declaration.name());
|
||||
}
|
||||
|
||||
size_t ASTTransform::declare(legacy::Declaration const& _declaration, Term& _term)
|
||||
unique_ptr<Term> ASTTransform::tuple(list<unique_ptr<Term>> _components)
|
||||
{
|
||||
auto [it, newlyInserted] = m_declarationIndices.emplace(&_declaration, m_ast->declarations.size());
|
||||
if (newlyInserted)
|
||||
m_ast->declarations.emplace_back(AST::DeclarationInfo{&_term, _declaration.name()});
|
||||
if (auto term = ranges::fold_right_last(_components | ranges::view::move, [&](auto a, auto b) { return pair(std::move(a), std::move(b)); }))
|
||||
return std::move(*term);
|
||||
else
|
||||
{
|
||||
auto& info = m_ast->declarations.at(it->second);
|
||||
solAssert(!info.target);
|
||||
info.target = &_term;
|
||||
info.name = _declaration.name();
|
||||
}
|
||||
termBase(_term).declaration = it->second;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
TermBase ASTTransform::makeTermBase()
|
||||
{
|
||||
return TermBase{
|
||||
m_currentLocation,
|
||||
m_currentNode ? make_optional(m_currentNode->id()) : nullopt,
|
||||
std::monostate{},
|
||||
nullopt
|
||||
};
|
||||
return constant(BuiltinConstant::Unit);
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::constrain(unique_ptr<Term> _value, unique_ptr<Term> _constraint)
|
||||
@ -397,22 +398,18 @@ unique_ptr<Term> ASTTransform::constrain(unique_ptr<Term> _value, unique_ptr<Ter
|
||||
return application(BuiltinConstant::Constrain, std::move(_value), std::move(_constraint));
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::builtinTypeClass(langutil::Token _token)
|
||||
std::unique_ptr<Term> ASTTransform::namedFunctionList(std::vector<ASTPointer<ASTNode>> _nodes)
|
||||
{
|
||||
switch (_token)
|
||||
list<unique_ptr<Term>> functionList;
|
||||
for (auto subNode: _nodes)
|
||||
{
|
||||
case Token::Mul:
|
||||
return constant(BuiltinConstant::Mul);
|
||||
case Token::Add:
|
||||
return constant(BuiltinConstant::Add);
|
||||
case Token::Integer:
|
||||
return constant(BuiltinConstant::Integer);
|
||||
case Token::Equal:
|
||||
return constant(BuiltinConstant::Equal);
|
||||
default:
|
||||
m_analysis.errorReporter().typeError(0000_error, m_currentLocation, "Invalid type class.");
|
||||
return constant(BuiltinConstant::Undefined);
|
||||
auto const *function = dynamic_cast<FunctionDefinition const*>(subNode.get());
|
||||
solAssert(function);
|
||||
unique_ptr<Term> functionName = constant(function->name());
|
||||
unique_ptr<Term> functionDefinition = term(*function);
|
||||
functionList.emplace_back(application(BuiltinConstant::NamedTerm, std::move(functionName), std::move(functionDefinition)));
|
||||
}
|
||||
return tuple(std::move(functionList));
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::builtinBinaryOperator(Token _token)
|
||||
@ -435,26 +432,29 @@ unique_ptr<Term> ASTTransform::builtinBinaryOperator(Token _token)
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::pair(unique_ptr<Term> _first, unique_ptr<Term> _second)
|
||||
unique_ptr<Term> ASTTransform::builtinTypeClass(langutil::Token _token)
|
||||
{
|
||||
return application(
|
||||
application(
|
||||
BuiltinConstant::Pair,
|
||||
std::move(_first)
|
||||
),
|
||||
std::move(_second)
|
||||
);
|
||||
switch (_token)
|
||||
{
|
||||
case Token::Mul:
|
||||
return constant(BuiltinConstant::Mul);
|
||||
case Token::Add:
|
||||
return constant(BuiltinConstant::Add);
|
||||
case Token::Integer:
|
||||
return constant(BuiltinConstant::Integer);
|
||||
case Token::Equal:
|
||||
return constant(BuiltinConstant::Equal);
|
||||
default:
|
||||
m_analysis.errorReporter().typeError(0000_error, m_currentLocation, "Invalid type class.");
|
||||
return constant(BuiltinConstant::Undefined);
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::tuple(list<unique_ptr<Term>> _components)
|
||||
TermBase ASTTransform::makeTermBase()
|
||||
{
|
||||
if (auto term = ranges::fold_right_last(_components | ranges::view::move, [&](auto a, auto b) { return pair(std::move(a), std::move(b)); }))
|
||||
return std::move(*term);
|
||||
else
|
||||
return constant(BuiltinConstant::Unit);
|
||||
}
|
||||
|
||||
unique_ptr<Term> ASTTransform::application(unique_ptr<Term> _function, std::list<unique_ptr<Term>> _arguments)
|
||||
{
|
||||
return makeTerm<Application>(std::move(_function), tuple(std::move(_arguments)));
|
||||
return TermBase{
|
||||
m_currentLocation,
|
||||
m_currentNode ? make_optional(m_currentNode->id()) : nullopt,
|
||||
std::monostate{}
|
||||
};
|
||||
}
|
||||
|
@ -35,52 +35,74 @@ class ASTTransform: public ASTConstVisitor
|
||||
public:
|
||||
ASTTransform(Analysis& _analysis);
|
||||
|
||||
std::unique_ptr<AST> ast()
|
||||
{
|
||||
return std::move(m_ast);
|
||||
}
|
||||
|
||||
std::unique_ptr<AST> ast() { return std::move(m_ast); }
|
||||
private:
|
||||
bool visit(legacy::SourceUnit const&) override { return true; }
|
||||
bool visit(legacy::PragmaDirective const&) override { return true; }
|
||||
bool visit(legacy::ImportDirective const&) override { return true; }
|
||||
bool visit(legacy::ContractDefinition const& _contractDefinition) override;
|
||||
bool visit(legacy::FunctionDefinition const& _functionDefinition) override;
|
||||
|
||||
bool visit(legacy::TypeDefinition const& _typeDefinition) override;
|
||||
bool visit(legacy::TypeClassDefinition const& _typeClassDefinition) override;
|
||||
bool visit(legacy::TypeClassInstantiation const& _typeClassInstantiation) override;
|
||||
bool visit(legacy::TypeDefinition const& _typeDefinition) override;
|
||||
bool visit(legacy::FunctionDefinition const& _functionDefinition) override;
|
||||
bool visit(legacy::ContractDefinition const& _contractDefinition) override;
|
||||
bool visitNode(ASTNode const& _node) override;
|
||||
|
||||
AST::FunctionInfo functionDefinition(legacy::FunctionDefinition const& _functionDefinition);
|
||||
std::unique_ptr<Term> term(legacy::ParameterList const& _parameterList);
|
||||
std::unique_ptr<Term> term(legacy::VariableDeclaration const& _variableDeclaration, std::unique_ptr<Term> _initialValue = nullptr);
|
||||
std::unique_ptr<Term> term(legacy::Block const& _block);
|
||||
std::unique_ptr<Term> term(std::vector<ASTPointer<legacy::Statement>> const& _statements);
|
||||
std::unique_ptr<Term> term(legacy::InlineAssembly const& _assembly);
|
||||
std::unique_ptr<Term> term(legacy::TypeClassDefinition const& _typeClassDefinition);
|
||||
std::unique_ptr<Term> term(legacy::TypeClassInstantiation const& _typeClassInstantiation);
|
||||
std::unique_ptr<Term> term(legacy::TypeDefinition const& _typeDefinition);
|
||||
std::unique_ptr<Term> term(legacy::ContractDefinition const& _contractDefinition);
|
||||
std::unique_ptr<Term> term(legacy::FunctionDefinition const& _functionDefinition);
|
||||
std::unique_ptr<Term> term(legacy::VariableDeclarationStatement const& _declaration);
|
||||
std::unique_ptr<Term> term(legacy::Statement const& _statements);
|
||||
std::unique_ptr<Term> term(legacy::Expression const& _expression);
|
||||
std::unique_ptr<Term> term(legacy::Assignment const& _assignment);
|
||||
std::unique_ptr<Term> term(legacy::Block const& _block);
|
||||
std::unique_ptr<Term> term(legacy::Statement const& _statements);
|
||||
std::unique_ptr<Term> term(legacy::TypeName const& _name);
|
||||
|
||||
std::unique_ptr<Term> binaryOperation(
|
||||
langutil::Token _operator,
|
||||
std::unique_ptr<Term> _leftHandSide,
|
||||
std::unique_ptr<Term> _rightHandSide
|
||||
);
|
||||
|
||||
std::unique_ptr<Term> constant(BuiltinConstant _constant)
|
||||
{
|
||||
return makeTerm<Constant>(_constant);
|
||||
}
|
||||
std::unique_ptr<Term> constant(std::string _name)
|
||||
{
|
||||
return makeTerm<Constant>(_name);
|
||||
}
|
||||
std::unique_ptr<Term> term(legacy::TypeClassName const& _typeClassName);
|
||||
std::unique_ptr<Term> term(legacy::ParameterList const& _parameterList);
|
||||
std::unique_ptr<Term> term(legacy::VariableDeclaration const& _variableDeclaration, std::unique_ptr<Term> _initialValue = {});
|
||||
std::unique_ptr<Term> term(legacy::InlineAssembly const& _assembly);
|
||||
std::unique_ptr<Term> term(legacy::Expression const& _expression);
|
||||
|
||||
// Allows for easy uniform treatment in the variadic templates below.
|
||||
std::unique_ptr<Term> term(std::unique_ptr<Term> _term) { return _term; }
|
||||
|
||||
std::unique_ptr<Term> namedFunctionList(std::vector<ASTPointer<ASTNode>> _nodes);
|
||||
std::unique_ptr<Term> binaryOperation(
|
||||
langutil::Token _operator,
|
||||
std::unique_ptr<Term> _leftHandSide,
|
||||
std::unique_ptr<Term> _rightHandSide
|
||||
)
|
||||
{
|
||||
return application(builtinBinaryOperator(_operator), std::move(_leftHandSide), std::move(_rightHandSide));
|
||||
}
|
||||
std::unique_ptr<Term> reference(legacy::Declaration const& _declaration);
|
||||
std::unique_ptr<Term> constant(BuiltinConstant _constant) { return makeTerm<Constant>(_constant); }
|
||||
std::unique_ptr<Term> constant(std::string _name) { return makeTerm<Constant>(_name); }
|
||||
template<typename T>
|
||||
std::unique_ptr<Term> termOrConstant(T const* _node, BuiltinConstant _constant)
|
||||
{
|
||||
return _node ? term(*_node) : constant(_constant);
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<Term> pair(std::unique_ptr<Term> _first, std::unique_ptr<Term> _second)
|
||||
{
|
||||
// Note: BuiltinConstant::Pair has signature a -> (b -> (a, b))
|
||||
// This reduces n-ary functions to unary functions only as primitives.
|
||||
return application(
|
||||
application(
|
||||
BuiltinConstant::Pair,
|
||||
std::move(_first)
|
||||
),
|
||||
std::move(_second)
|
||||
);
|
||||
}
|
||||
std::unique_ptr<Term> tuple(std::list<std::unique_ptr<Term>> _components);
|
||||
std::unique_ptr<Term> constrain(std::unique_ptr<Term> _value, std::unique_ptr<Term> _constraint);
|
||||
std::unique_ptr<Term> builtinBinaryOperator(langutil::Token);
|
||||
std::unique_ptr<Term> builtinTypeClass(langutil::Token);
|
||||
|
||||
template<typename... Args>
|
||||
std::unique_ptr<Term> tuple(Args&&... _args)
|
||||
{
|
||||
@ -88,8 +110,10 @@ private:
|
||||
(components.emplace_back(term(std::forward<Args>(_args))), ...);
|
||||
return tuple(std::move(components));
|
||||
}
|
||||
std::unique_ptr<Term> pair(std::unique_ptr<Term> _first, std::unique_ptr<Term> _second);
|
||||
std::unique_ptr<Term> application(std::unique_ptr<Term> _function, std::list<std::unique_ptr<Term>> _argument);
|
||||
std::unique_ptr<Term> application(std::unique_ptr<Term> _function, std::list<std::unique_ptr<Term>> _arguments)
|
||||
{
|
||||
return makeTerm<Application>(std::move(_function), tuple(std::move(_arguments)));
|
||||
}
|
||||
template<typename... Args>
|
||||
std::unique_ptr<Term> application(std::unique_ptr<Term> _function, Args&&... _args)
|
||||
{
|
||||
@ -97,7 +121,6 @@ private:
|
||||
(components.emplace_back(term(std::forward<Args>(_args))), ...);
|
||||
return application(std::move(_function), std::move(components));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
std::unique_ptr<Term> application(BuiltinConstant _function, Args&&... _args)
|
||||
{
|
||||
@ -106,25 +129,34 @@ private:
|
||||
return application(constant(_function), std::move(components));
|
||||
}
|
||||
|
||||
std::unique_ptr<Term> constrain(std::unique_ptr<Term> _value, std::unique_ptr<Term> _constraint);
|
||||
std::unique_ptr<Term> builtinBinaryOperator(langutil::Token);
|
||||
std::unique_ptr<Term> builtinTypeClass(langutil::Token);
|
||||
std::unique_ptr<Term> reference(legacy::Declaration const& _declaration);
|
||||
size_t declare(legacy::Declaration const& _declaration, Term& _term);
|
||||
TermBase makeTermBase();
|
||||
template<typename TermKind, typename... Args>
|
||||
std::unique_ptr<Term> makeTerm(Args&&... _args)
|
||||
{
|
||||
return std::make_unique<Term>(TermKind{
|
||||
makeTermBase(),
|
||||
std::forward<Args>(_args)...
|
||||
});
|
||||
}
|
||||
|
||||
Analysis& m_analysis;
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
|
||||
std::unique_ptr<AST> m_ast;
|
||||
|
||||
struct SetNode {
|
||||
SetNode(ASTTransform& _parent, ASTNode const& _node):
|
||||
m_parent(_parent),
|
||||
m_previousNode(_parent.m_currentNode),
|
||||
m_previousLocation(_parent.m_currentLocation)
|
||||
m_parent(_parent),
|
||||
m_previousNode(_parent.m_currentNode),
|
||||
m_previousLocation(_parent.m_currentLocation)
|
||||
{
|
||||
_parent.m_currentNode = &_node;
|
||||
_parent.m_currentLocation = _node.location();
|
||||
}
|
||||
SetNode(ASTTransform& _parent, langutil::SourceLocation const& _location):
|
||||
m_parent(_parent),
|
||||
m_previousNode(_parent.m_currentNode),
|
||||
m_previousLocation(_parent.m_currentLocation)
|
||||
m_parent(_parent),
|
||||
m_previousNode(_parent.m_currentNode),
|
||||
m_previousLocation(_parent.m_currentLocation)
|
||||
{
|
||||
_parent.m_currentNode = nullptr;
|
||||
_parent.m_currentLocation = _location;
|
||||
@ -138,31 +170,8 @@ private:
|
||||
ASTNode const* m_previousNode = nullptr;
|
||||
langutil::SourceLocation m_previousLocation;
|
||||
};
|
||||
TermBase makeTermBase();
|
||||
template<typename TermKind, typename... Args>
|
||||
std::unique_ptr<Term> makeTerm(Args&&... _args)
|
||||
{
|
||||
return std::make_unique<Term>(TermKind{
|
||||
makeTermBase(),
|
||||
std::forward<Args>(_args)...
|
||||
});
|
||||
}
|
||||
template<typename T>
|
||||
std::unique_ptr<Term> termOrConstant(T const* _node, BuiltinConstant _constant)
|
||||
{
|
||||
if (_node)
|
||||
return term(*_node);
|
||||
else
|
||||
return constant(_constant);
|
||||
}
|
||||
|
||||
Analysis& m_analysis;
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
ASTNode const* m_currentNode = nullptr;
|
||||
langutil::SourceLocation m_currentLocation;
|
||||
std::unique_ptr<AST> m_ast;
|
||||
|
||||
std::map<frontend::Declaration const*, size_t, ASTCompareByID<frontend::Declaration>> m_declarationIndices;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -18,13 +18,17 @@
|
||||
#include <libsolidity/experimental/analysis/TypeCheck.h>
|
||||
#include <libsolidity/experimental/ast/TypeSystemHelper.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolutil/CommonIO.h>
|
||||
#include <libsolutil/Visitor.h>
|
||||
#include <range/v3/view/map.hpp>
|
||||
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
#include <liblangutil/Exceptions.h>
|
||||
|
||||
#include <libsolutil/AnsiColorized.h>
|
||||
#include <libsolutil/CommonIO.h>
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
#include <range/v3/view/map.hpp>
|
||||
#include <range/v3/view/reverse.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace langutil;
|
||||
@ -32,8 +36,143 @@ using namespace solidity::frontend::experimental;
|
||||
|
||||
namespace
|
||||
{
|
||||
using Term = std::variant<Application, Lambda, InlineAssembly, VariableDeclaration, Reference, Constant>;
|
||||
|
||||
struct TPat
|
||||
{
|
||||
using Unifier = std::function<void(Type, Type)>;
|
||||
template<typename R, typename... Args>
|
||||
TPat(R _f(Args...)): generator([f = _f](TypeEnvironment& _env, Unifier _unifier) -> Type {
|
||||
return invoke(_env, _unifier, f, std::make_index_sequence<sizeof...(Args)>{});
|
||||
}) {}
|
||||
TPat(PrimitiveType _type): generator([type = _type](TypeEnvironment& _env, Unifier) { return _env.typeSystem().type(type, {}); }) {}
|
||||
Type realize(TypeEnvironment& _env, Unifier _unifier) const { return generator(_env, _unifier); }
|
||||
TPat(std::function<Type(TypeEnvironment&, Unifier)> _generator):generator(std::move(_generator)) {}
|
||||
TPat(Type _t): generator([t = _t](TypeEnvironment&, Unifier) -> Type { return t; }) {}
|
||||
private:
|
||||
template<size_t I>
|
||||
static TPat makeFreshVariable(TypeEnvironment& _env) { return TPat{_env.typeSystem().freshTypeVariable({})}; }
|
||||
template<typename Generator, size_t... Is>
|
||||
static Type invoke(TypeEnvironment& _env, Unifier _unifier, Generator const& _generator, std::index_sequence<Is...>)
|
||||
{
|
||||
// Use an auxiliary array to ensure deterministic evaluation order.
|
||||
[[maybe_unused]] std::array<TPat, sizeof...(Is)> patterns{makeFreshVariable<Is>(_env)...};
|
||||
return (_generator(std::move(patterns[Is])...)).realize(_env, _unifier);
|
||||
}
|
||||
std::function<Type(TypeEnvironment&, Unifier)> generator;
|
||||
};
|
||||
namespace pattern_ops
|
||||
{
|
||||
using Unifier = std::function<void(Type, Type)>;
|
||||
inline TPat operator>>(TPat _a, TPat _b)
|
||||
{
|
||||
return TPat([a = std::move(_a), b = std::move(_b)](TypeEnvironment& _env, Unifier _unifier) -> Type {
|
||||
return TypeSystemHelpers{_env.typeSystem()}.functionType(a.realize(_env, _unifier), b.realize(_env, _unifier));
|
||||
});
|
||||
}
|
||||
inline TPat operator==(TPat _a, TPat _b)
|
||||
{
|
||||
return TPat([a = std::move(_a), b = std::move(_b)](TypeEnvironment& _env, Unifier _unifier) -> Type {
|
||||
Type left = a.realize(_env, _unifier);
|
||||
Type right = b.realize(_env, _unifier);
|
||||
_unifier(left, right);
|
||||
return left;
|
||||
});
|
||||
}
|
||||
template<typename... Args>
|
||||
TPat tuple(Args... args)
|
||||
{
|
||||
return TPat([args = std::array<TPat, sizeof...(Args)>{{std::move(args)...}}](TypeEnvironment& _env, Unifier _unifier) -> Type {
|
||||
return TypeSystemHelpers{_env.typeSystem()}.tupleType(
|
||||
args | ranges::view::transform([&](TPat _pat) { return _pat.realize(_env, _unifier); }) | ranges::to<vector<Type>>
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
struct BuiltinConstantInfo
|
||||
{
|
||||
std::string name;
|
||||
std::optional<TPat> builtinType;
|
||||
};
|
||||
[[maybe_unused]] BuiltinConstantInfo const& builtinConstantInfo(BuiltinConstant _constant)
|
||||
{
|
||||
using namespace pattern_ops;
|
||||
static const TPat unit{PrimitiveType::Unit};
|
||||
static const auto info = std::map<BuiltinConstant, BuiltinConstantInfo>{
|
||||
{BuiltinConstant::Unit, {"Unit", unit}},
|
||||
{BuiltinConstant::Pair, {"Pair", +[](TPat a, TPat b) { return a >> (b >> tuple(a,b)); }}},
|
||||
{BuiltinConstant::Fun, {"Fun", +[](TPat a, TPat b) { return tuple(a,b) >> (a >> b); }}},
|
||||
{BuiltinConstant::Constrain, {"Constrain", +[](TPat a) { return tuple(a,a) >> a; }}},
|
||||
{BuiltinConstant::NamedTerm, {"NamedTerm", +[](TPat a) { return tuple(unit, a) >> a; /* TODO: (name, a) >> a */ }}},
|
||||
{BuiltinConstant::TypeDeclaration, {"TypeDeclaration", nullopt}},
|
||||
{BuiltinConstant::TypeDefinition, {"TypeDefinition", +[](TPat type, TPat args, TPat value) {
|
||||
return tuple(type, args, value) >> (args >> type);
|
||||
}}},
|
||||
{BuiltinConstant::TypeClassDefinition, {"TypeClassDefinition", nullopt}},
|
||||
{BuiltinConstant::TypeClassInstantiation, {"TypeClassInstantiation", nullopt}},
|
||||
{BuiltinConstant::FunctionDeclaration, {"FunctionDeclaration", nullopt}},
|
||||
{BuiltinConstant::FunctionDefinition, {"FunctionDefinition", +[](TPat a, TPat r) {
|
||||
return tuple(a >> r, a, r, r) >> (a >> r);
|
||||
}}},
|
||||
{BuiltinConstant::ContractDefinition, {"ContractDefinition", +[]() {
|
||||
return tuple(unit, (unit >> unit)) >> unit;
|
||||
}}},
|
||||
{BuiltinConstant::VariableDeclaration, {"VariableDeclaration", +[](TPat a) { return a >> a; }}},
|
||||
{BuiltinConstant::VariableDefinition, {"VariableDefinition", nullopt}},
|
||||
{BuiltinConstant::Block, {"Block", +[](TPat a) { return a >> a; }}},
|
||||
{BuiltinConstant::ReturnStatement, {"ReturnStatement", +[](TPat a) { return a >> a; }}},
|
||||
{BuiltinConstant::RegularStatement, {"RegularStatement", +[](TPat a) { return a >> unit; }}},
|
||||
{BuiltinConstant::ChainStatements, {"ChainStatements", +[](TPat a, TPat b) { return tuple(a,b) >> b; }}},
|
||||
{BuiltinConstant::Assign, {"Assign", +[](TPat a) { return tuple(a,a) >> unit; }}},
|
||||
{BuiltinConstant::MemberAccess, {"MemberAccess", nullopt}},
|
||||
{BuiltinConstant::Mul, {"Mul", nullopt}},
|
||||
{BuiltinConstant::Add, {"Add", nullopt}},
|
||||
{BuiltinConstant::Void, {"Void", nullopt}},
|
||||
{BuiltinConstant::Word, {"Word", PrimitiveType::Word}},
|
||||
{BuiltinConstant::Integer, {"Integer", nullopt}},
|
||||
{BuiltinConstant::Bool, {"Bool", nullopt}},
|
||||
{BuiltinConstant::Undefined, {"Undefined", nullopt}},
|
||||
{BuiltinConstant::Equal, {"Equal", nullopt}},
|
||||
};
|
||||
return info.at(_constant);
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
void forEachTopLevelTerm(AST& _ast, Visitor _visitor)
|
||||
{
|
||||
for (auto& term: _ast.typeDefinitions | ranges::view::values)
|
||||
_visitor(*term);
|
||||
for (auto& term: _ast.typeClasses | ranges::view::values)
|
||||
_visitor(*term);
|
||||
for (auto& term: _ast.typeClassInstantiations | ranges::view::values)
|
||||
_visitor(*term);
|
||||
for (auto& term: _ast.functions | ranges::views::values)
|
||||
_visitor(*term);
|
||||
for (auto& term: _ast.contracts | ranges::views::values)
|
||||
_visitor(*term);
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
void forEachImmediateSubTerm(Term& _term, Visitor _visitor)
|
||||
{
|
||||
std::visit(util::GenericVisitor{
|
||||
[&](Application const& _app) {
|
||||
_visitor(*_app.expression);
|
||||
_visitor(*_app.argument);
|
||||
},
|
||||
[&](Lambda const& _lambda)
|
||||
{
|
||||
_visitor(*_lambda.argument);
|
||||
_visitor(*_lambda.value);
|
||||
},
|
||||
[&](InlineAssembly const&)
|
||||
{
|
||||
// TODO
|
||||
},
|
||||
[&](Reference const&) {},
|
||||
[&](Constant const&) {}
|
||||
}, _term);
|
||||
}
|
||||
|
||||
optional<pair<reference_wrapper<Term const>, reference_wrapper<Term const>>> destPair(Term const& _term)
|
||||
{
|
||||
@ -71,29 +210,15 @@ void setType(Term& _term, Type _type)
|
||||
std::visit([&](auto& term) { term.type = _type; }, _term);
|
||||
}
|
||||
|
||||
string colorize(string _color, string _string)
|
||||
{
|
||||
return _color + _string + util::formatting::RESET;
|
||||
}
|
||||
|
||||
string termPrinter(AST& _ast, Term const& _term, TypeEnvironment* _env = nullptr, bool _sugarPairs = true, bool _sugarConsts = true, size_t _indent = 0)
|
||||
{
|
||||
using namespace util::formatting;
|
||||
auto recurse = [&](Term const& _next) { return termPrinter(_ast, _next, _env, _sugarPairs, _sugarConsts, _indent); };
|
||||
static const std::map<BuiltinConstant, const char*> builtinConstants = {
|
||||
{BuiltinConstant::Unit, "()"},
|
||||
{BuiltinConstant::Pair, "Pair"},
|
||||
{BuiltinConstant::Fun, "Fun"},
|
||||
{BuiltinConstant::Constrain, "Constrain"},
|
||||
{BuiltinConstant::Return, "Return"},
|
||||
{BuiltinConstant::Block, "Block"},
|
||||
{BuiltinConstant::Statement, "Statement"},
|
||||
{BuiltinConstant::ChainStatements, "ChainStatements"},
|
||||
{BuiltinConstant::Assign, "Assign"},
|
||||
{BuiltinConstant::MemberAccess, "MemberAccess"},
|
||||
{BuiltinConstant::Mul, "Mul"},
|
||||
{BuiltinConstant::Add, "Add"},
|
||||
{BuiltinConstant::Void, "void"},
|
||||
{BuiltinConstant::Word, "word"},
|
||||
{BuiltinConstant::Integer, "Integer"},
|
||||
{BuiltinConstant::Bool, "Bool"},
|
||||
{BuiltinConstant::Undefined, "Undefined"},
|
||||
{BuiltinConstant::Equal, "Equal"}
|
||||
};
|
||||
string result = std::visit(util::GenericVisitor{
|
||||
[&](Application const& _app) {
|
||||
if (_sugarPairs)
|
||||
@ -154,8 +279,10 @@ string termPrinter(AST& _ast, Term const& _term, TypeEnvironment* _env = nullptr
|
||||
if (auto pair = destPair(*_app.argument))
|
||||
return recurse(pair->first) + "\n" + std::string(_indent, '\t') + recurse(pair->second);
|
||||
break;
|
||||
case BuiltinConstant::Statement:
|
||||
case BuiltinConstant::RegularStatement:
|
||||
return recurse(*_app.argument) + ";";
|
||||
case BuiltinConstant::ReturnStatement:
|
||||
return colorize(CYAN, "return ") + recurse(*_app.argument) + ";";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -166,23 +293,20 @@ string termPrinter(AST& _ast, Term const& _term, TypeEnvironment* _env = nullptr
|
||||
return "(" + recurse(*_lambda.argument) + " -> " + recurse(*_lambda.value) + ")";
|
||||
},
|
||||
[&](InlineAssembly const&) -> string {
|
||||
return "assembly";
|
||||
},
|
||||
[&](VariableDeclaration const& _varDecl) {
|
||||
return "let " + recurse(*_varDecl.namePattern) + (_varDecl.initialValue ? " = " + recurse(*_varDecl.initialValue) : "");
|
||||
return colorize(CYAN, "assembly");
|
||||
},
|
||||
[&](Reference const& _reference) {
|
||||
return "" + _ast.declarations.at(_reference.index).name + "";
|
||||
return _reference.name.empty() ? util::toString(_reference.index) : _reference.name;
|
||||
},
|
||||
[&](Constant const& _constant) {
|
||||
return "" + std::visit(util::GenericVisitor{
|
||||
return colorize(BLUE, std::visit(util::GenericVisitor{
|
||||
[](BuiltinConstant _constant) -> string {
|
||||
return builtinConstants.at(_constant);
|
||||
return builtinConstantInfo(_constant).name;
|
||||
},
|
||||
[](std::string const& _name) {
|
||||
return _name;
|
||||
}
|
||||
}, _constant.name) + "";
|
||||
}, _constant.name));
|
||||
}
|
||||
}, _term);
|
||||
if (_env)
|
||||
@ -190,140 +314,39 @@ string termPrinter(AST& _ast, Term const& _term, TypeEnvironment* _env = nullptr
|
||||
Type termType = type(_term);
|
||||
if (!holds_alternative<std::monostate>(termType))
|
||||
{
|
||||
result += "[:" + TypeEnvironmentHelpers{*_env}.typeToString(termType) + "]";
|
||||
result += colorize(GREEN, "[:" + TypeEnvironmentHelpers{*_env}.typeToString(termType) + "]");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string functionPrinter(AST& _ast, AST::FunctionInfo const& _info, TypeEnvironment* _env = nullptr, bool _sugarPairs = true, bool _sugarConsts = true, size_t _indent = 0)
|
||||
{
|
||||
auto printTerm = [&](Term const& _term) { return termPrinter(_ast, _term, _env, _sugarPairs, _sugarConsts, _indent + 1); };
|
||||
return "function (" + printTerm(*_info.arguments) + ") -> " + printTerm(*_info.returnType) + " = " + printTerm(*_info.function) + "\n";
|
||||
}
|
||||
|
||||
std::string astPrinter(AST& _ast, TypeEnvironment* _env = nullptr, bool _sugarPairs = true, bool _sugarConsts = true, size_t _indent = 0)
|
||||
{
|
||||
auto printTerm = [&](Term const& _term) { return termPrinter(_ast, _term, _env, _sugarPairs, _sugarConsts, _indent + 1); };
|
||||
auto printFunction = [&](AST::FunctionInfo const& _info) { return functionPrinter(_ast, _info, _env, _sugarPairs, _sugarConsts, _indent + 1); };
|
||||
std::string result;
|
||||
for (auto& info: _ast.typeDefinitions | ranges::view::values)
|
||||
{
|
||||
result += "type " + printTerm(*info.declaration);
|
||||
if (info.arguments)
|
||||
result += " " + printTerm(*info.arguments);
|
||||
if (info.value)
|
||||
result += " = " + printTerm(*info.declaration);
|
||||
result += "\n\n";
|
||||
}
|
||||
for (auto& info: _ast.typeClasses | ranges::view::values)
|
||||
{
|
||||
result += "class " + printTerm(*info.typeVariable) + ":" + printTerm(*info.declaration) + " {";
|
||||
_indent++;
|
||||
for (auto&& functionInfo: info.functions | ranges::view::values)
|
||||
result += printFunction(functionInfo);
|
||||
_indent--;
|
||||
result += "}\n\n";
|
||||
}
|
||||
for (auto& info: _ast.typeClassInstantiations | ranges::view::values)
|
||||
{
|
||||
result += "instantiation " + printTerm(*info.typeConstructor) + "(" + printTerm(*info.argumentSorts) + "):" + printTerm(*info.typeClass) + "{\n";
|
||||
_indent++;
|
||||
for (auto&& functionInfo: info.functions | ranges::view::values)
|
||||
result += printFunction(functionInfo);
|
||||
_indent--;
|
||||
}
|
||||
for (auto& functionInfo: _ast.functions | ranges::views::values)
|
||||
{
|
||||
result += printFunction(functionInfo);
|
||||
result += "\n";
|
||||
}
|
||||
for (auto& [contract, info]: _ast.contracts)
|
||||
{
|
||||
result += "contract " + contract->name() + " {\n";
|
||||
_indent++;
|
||||
for(auto& function: info.functions | ranges::view::values)
|
||||
result += printFunction(function);
|
||||
_indent--;
|
||||
result += "}\n\n";
|
||||
|
||||
}
|
||||
auto printTerm = [&](Term const& _term) { result += termPrinter(_ast, _term, _env, _sugarPairs, _sugarConsts, _indent + 1) + "\n\n"; };
|
||||
forEachTopLevelTerm(_ast, printTerm);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct TVar
|
||||
{
|
||||
TypeEnvironment& env;
|
||||
Type type;
|
||||
};
|
||||
inline TVar operator>>(TVar a, TVar b)
|
||||
{
|
||||
TypeSystemHelpers helper{a.env.typeSystem()};
|
||||
return TVar{a.env, helper.functionType(a.type, b.type)};
|
||||
}
|
||||
inline TVar operator,(TVar a, TVar b)
|
||||
{
|
||||
TypeSystemHelpers helper{a.env.typeSystem()};
|
||||
return TVar{a.env, helper.tupleType({a.type, b.type})};
|
||||
}
|
||||
template <typename T>
|
||||
struct ArgumentCount;
|
||||
template <typename R, typename... Args>
|
||||
struct ArgumentCount<std::function<R(Args...)>> {
|
||||
static constexpr size_t value = sizeof...(Args);
|
||||
};
|
||||
struct TypeGenerator
|
||||
{
|
||||
template<typename Generator>
|
||||
TypeGenerator(Generator&& _generator):generator([generator = std::move(_generator)](TypeEnvironment& _env) -> Type {
|
||||
return invoke(_env, generator, std::make_index_sequence<ArgumentCount<decltype(std::function{_generator})>::value>{});
|
||||
}) {}
|
||||
TypeGenerator(TVar _type):generator([type = _type.type](TypeEnvironment& _env) -> Type { return _env.fresh(type); }) {}
|
||||
TypeGenerator(PrimitiveType _type): generator([type = _type](TypeEnvironment& _env) -> Type { return _env.typeSystem().type(type, {}); }) {}
|
||||
Type operator()(TypeEnvironment& _env) const { return generator(_env); }
|
||||
private:
|
||||
template<size_t I>
|
||||
static TVar makeFreshVariable(TypeEnvironment& _env) { return TVar{_env, _env.typeSystem().freshTypeVariable({}) }; }
|
||||
template<typename Generator, size_t... Is>
|
||||
static Type invoke(TypeEnvironment& _env, Generator&& _generator, std::index_sequence<Is...>)
|
||||
{
|
||||
// Use an auxiliary array to ensure deterministic evaluation order.
|
||||
std::array<TVar, sizeof...(Is)> tvars{makeFreshVariable<Is>(_env)...};
|
||||
return std::invoke(_generator, tvars[Is]...).type;
|
||||
}
|
||||
std::function<Type(TypeEnvironment&)> generator;
|
||||
};
|
||||
}
|
||||
|
||||
void TypeCheck::operator()(AST& _ast)
|
||||
{
|
||||
TypeSystem& typeSystem = m_analysis.typeSystem();
|
||||
TypeSystemHelpers helper{typeSystem};
|
||||
TypeEnvironment& env = typeSystem.env();
|
||||
|
||||
TVar unit = TVar{env, typeSystem.type(PrimitiveType::Unit, {})};
|
||||
TVar word = TVar{env, typeSystem.type(PrimitiveType::Word, {})};
|
||||
std::unique_ptr<TVar> currentReturn;
|
||||
std::map<BuiltinConstant, TypeGenerator> builtinConstantTypeGenerators{
|
||||
{BuiltinConstant::Unit, unit},
|
||||
{BuiltinConstant::Pair, [](TVar a, TVar b) { return a >> (b >> (a,b)); }},
|
||||
{BuiltinConstant::Word, word},
|
||||
{BuiltinConstant::Assign, [=](TVar a) { return (a,a) >> unit; }}, // TODO: (a,a) >> a
|
||||
{BuiltinConstant::Block, [](TVar a) { return a >> a; }},
|
||||
{BuiltinConstant::ChainStatements, [](TVar a, TVar b) { return (a,b) >> b; }},
|
||||
{BuiltinConstant::Statement, [=](TVar a) { return a >> unit; }},
|
||||
{BuiltinConstant::Return, [&]() {
|
||||
solAssert(currentReturn);
|
||||
return *currentReturn >> unit;
|
||||
}},
|
||||
{BuiltinConstant::Fun, [&](TVar a, TVar b) {
|
||||
return (a,b) >> (a >> b);
|
||||
}},
|
||||
};
|
||||
list<reference_wrapper<Term>> toCheck;
|
||||
forEachTopLevelTerm(_ast, [&](Term& _root) {
|
||||
list<reference_wrapper<Term>> staged{{_root}};
|
||||
while (!staged.empty())
|
||||
{
|
||||
Term& term = staged.front().get();
|
||||
staged.pop_front();
|
||||
toCheck.push_back(term);
|
||||
forEachImmediateSubTerm(term, [&](Term& _subTerm) { staged.push_back(_subTerm); });
|
||||
}
|
||||
});
|
||||
|
||||
auto unifyForTerm = [&](Type _a, Type _b, Term* _term) {
|
||||
for (auto failure: env.unify(_a, _b))
|
||||
@ -361,161 +384,65 @@ void TypeCheck::operator()(AST& _ast)
|
||||
}, failure);
|
||||
}
|
||||
};
|
||||
auto checkTerm = [&](Term& _root) {
|
||||
std::list<reference_wrapper<Term>> heap;
|
||||
heap.emplace_back(_root);
|
||||
auto checked = [](Term const& _term) {
|
||||
return !holds_alternative<std::monostate>(type(_term));
|
||||
};
|
||||
auto canCheck = [&](Term& _term) -> bool {
|
||||
bool hasUnchecked = false;
|
||||
auto stage = [&](Term& _term) {
|
||||
if (!checked(_term))
|
||||
{
|
||||
heap.push_back(_term);
|
||||
hasUnchecked = true;
|
||||
}
|
||||
};
|
||||
std::visit(util::GenericVisitor{
|
||||
[&](Application const& _app) {
|
||||
stage(*_app.expression);
|
||||
stage(*_app.argument);
|
||||
},
|
||||
[&](Lambda const& _lambda)
|
||||
{
|
||||
stage(*_lambda.argument);
|
||||
stage(*_lambda.value);
|
||||
},
|
||||
[&](InlineAssembly const&)
|
||||
{
|
||||
// TODO
|
||||
},
|
||||
[&](VariableDeclaration const& _varDecl)
|
||||
{
|
||||
stage(*_varDecl.namePattern);
|
||||
if (_varDecl.initialValue)
|
||||
stage(*_varDecl.initialValue);
|
||||
},
|
||||
[&](Reference const&)
|
||||
{
|
||||
},
|
||||
[&](Constant const&) {}
|
||||
}, _term);
|
||||
if (hasUnchecked)
|
||||
{
|
||||
stage(_term);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
std::map<size_t, Type> declarationTypes;
|
||||
while (!heap.empty())
|
||||
{
|
||||
Term& current = heap.front();
|
||||
heap.pop_front();
|
||||
if (checked(current))
|
||||
continue;
|
||||
if (!canCheck(current))
|
||||
continue;
|
||||
|
||||
auto unify = [&](Type _a, Type _b) { unifyForTerm(_a, _b, ¤t); };
|
||||
|
||||
std::visit(util::GenericVisitor{
|
||||
[&](Application const& _app) {
|
||||
if (auto* constant = get_if<Constant>(_app.expression.get()))
|
||||
if (auto* builtin = get_if<BuiltinConstant>(&constant->name))
|
||||
if (*builtin == BuiltinConstant::Constrain)
|
||||
if (auto args = destPair(*_app.argument))
|
||||
{
|
||||
Type result = type(args->first);
|
||||
unify(result, type(args->second));
|
||||
setType(current, result);
|
||||
return;
|
||||
}
|
||||
Type resultType = typeSystem.freshTypeVariable({});
|
||||
unify(helper.functionType(type(*_app.argument), resultType), type(*_app.expression));
|
||||
setType(current, resultType);
|
||||
},
|
||||
[&](Lambda const& _lambda)
|
||||
{
|
||||
setType(current, helper.functionType(type(*_lambda.argument), type(*_lambda.value)));
|
||||
},
|
||||
[&](InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
// TODO
|
||||
(void)_inlineAssembly;
|
||||
setType(current, typeSystem.type(PrimitiveType::Unit, {}));
|
||||
},
|
||||
[&](VariableDeclaration const& _varDecl)
|
||||
{
|
||||
Type name = type(*_varDecl.namePattern);
|
||||
if (_varDecl.initialValue)
|
||||
unify(name, type(*_varDecl.initialValue));
|
||||
setType(current, name);
|
||||
},
|
||||
[&](Reference const& _reference)
|
||||
{
|
||||
Type result = typeSystem.freshTypeVariable({});
|
||||
if (
|
||||
auto [it, newlyInserted] = declarationTypes.emplace(_reference.index, result);
|
||||
!newlyInserted
|
||||
)
|
||||
unify(result, it->second);
|
||||
setType(current, result);
|
||||
},
|
||||
[&](Constant const& _constant)
|
||||
{
|
||||
bool assigned = std::visit(util::GenericVisitor{
|
||||
[&](std::string const&) { return false; },
|
||||
[&](BuiltinConstant const& _constant) {
|
||||
if (auto* generator = util::valueOrNullptr(builtinConstantTypeGenerators, _constant))
|
||||
std::map<size_t, Type> declarationTypes;
|
||||
for(auto term: toCheck | ranges::view::reverse)
|
||||
{
|
||||
auto unify = [&](Type _a, Type _b) { unifyForTerm(_a, _b, &term.get()); };
|
||||
std::visit(util::GenericVisitor{
|
||||
[&](Application const& _app) {
|
||||
/*if (auto* constant = get_if<Constant>(_app.expression.get()))
|
||||
if (auto* builtin = get_if<BuiltinConstant>(&constant->name))
|
||||
if (*builtin == BuiltinConstant::Constrain)
|
||||
if (auto args = destPair(*_app.argument))
|
||||
{
|
||||
setType(current, (*generator)(env));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}, _constant.name);
|
||||
if (!assigned)
|
||||
setType(current, typeSystem.freshTypeVariable({}));
|
||||
}
|
||||
}, current);
|
||||
solAssert(checked(current));
|
||||
if (auto declaration = termBase(current).declaration)
|
||||
Type result = type(args->first);
|
||||
unify(result, type(args->second));
|
||||
setType(term, result);
|
||||
return;
|
||||
}*/
|
||||
Type resultType = typeSystem.freshTypeVariable({});
|
||||
unify(helper.functionType(type(*_app.argument), resultType), type(*_app.expression));
|
||||
setType(term, resultType);
|
||||
},
|
||||
[&](Lambda const& _lambda)
|
||||
{
|
||||
setType(term, helper.functionType(type(*_lambda.argument), type(*_lambda.value)));
|
||||
},
|
||||
[&](InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
// TODO
|
||||
(void)_inlineAssembly;
|
||||
setType(term, typeSystem.type(PrimitiveType::Unit, {}));
|
||||
},
|
||||
[&](Reference const& _reference)
|
||||
{
|
||||
Type result = typeSystem.freshTypeVariable({});
|
||||
if (
|
||||
auto [it, newlyInserted] = declarationTypes.emplace(*declaration, type(current));
|
||||
auto [it, newlyInserted] = declarationTypes.emplace(_reference.index, result);
|
||||
!newlyInserted
|
||||
)
|
||||
unify(type(current), it->second);
|
||||
unify(result, it->second);
|
||||
setType(term, result);
|
||||
},
|
||||
[&](Constant const& _constant)
|
||||
{
|
||||
bool assigned = std::visit(util::GenericVisitor{
|
||||
[&](std::string const&) { return false; },
|
||||
[&](BuiltinConstant const& _constant) {
|
||||
if (auto generator = builtinConstantInfo(_constant).builtinType)
|
||||
{
|
||||
setType(term, (*generator).realize(env, unify));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}, _constant.name);
|
||||
if (!assigned)
|
||||
setType(term, typeSystem.freshTypeVariable({}));
|
||||
}
|
||||
}
|
||||
};
|
||||
for(auto& info: _ast.typeDefinitions | ranges::view::values)
|
||||
{
|
||||
if (info.arguments)
|
||||
checkTerm(*info.arguments);
|
||||
if (info.value)
|
||||
checkTerm(*info.value);
|
||||
checkTerm(*info.declaration);
|
||||
}
|
||||
for(auto& info: _ast.contracts | ranges::view::values)
|
||||
for(auto& function: info.functions | ranges::view::values)
|
||||
{
|
||||
checkTerm(*function.returnType);
|
||||
ScopedSaveAndRestore returnType{currentReturn, std::make_unique<TVar>(TVar{env,type(*function.returnType)})};
|
||||
checkTerm(*function.function);
|
||||
checkTerm(*function.arguments);
|
||||
// TODO: unify stuff?
|
||||
|
||||
}
|
||||
for(auto&& info: _ast.functions | ranges::view::values)
|
||||
{
|
||||
checkTerm(*info.returnType);
|
||||
ScopedSaveAndRestore returnType{currentReturn, std::make_unique<TVar>(TVar{env,type(*info.returnType)})};
|
||||
checkTerm(*info.function);
|
||||
checkTerm(*info.arguments);
|
||||
// TODO: unify stuff
|
||||
}, term.get());
|
||||
solAssert(!holds_alternative<std::monostate>(type(term)));
|
||||
}
|
||||
|
||||
std::cout << astPrinter(_ast, &env) << std::endl;
|
||||
|
@ -34,17 +34,16 @@ struct TermBase
|
||||
langutil::SourceLocation location;
|
||||
std::optional<int64_t> legacyId;
|
||||
Type type;
|
||||
std::optional<size_t> declaration;
|
||||
};
|
||||
|
||||
|
||||
struct Application;
|
||||
struct Lambda;
|
||||
struct InlineAssembly;
|
||||
struct VariableDeclaration;
|
||||
struct Reference: TermBase
|
||||
{
|
||||
size_t index = std::numeric_limits<size_t>::max();
|
||||
std::string name;
|
||||
};
|
||||
|
||||
enum class BuiltinConstant
|
||||
@ -54,9 +53,19 @@ enum class BuiltinConstant
|
||||
Pair,
|
||||
Fun,
|
||||
Constrain,
|
||||
Return,
|
||||
NamedTerm,
|
||||
TypeDeclaration,
|
||||
TypeDefinition,
|
||||
TypeClassDefinition,
|
||||
TypeClassInstantiation,
|
||||
FunctionDeclaration,
|
||||
FunctionDefinition,
|
||||
ContractDefinition,
|
||||
VariableDeclaration,
|
||||
VariableDefinition,
|
||||
Block,
|
||||
Statement,
|
||||
ReturnStatement,
|
||||
RegularStatement,
|
||||
ChainStatements,
|
||||
Assign,
|
||||
MemberAccess,
|
||||
@ -75,7 +84,7 @@ struct Constant: TermBase
|
||||
std::variant<std::string, BuiltinConstant> name;
|
||||
};
|
||||
|
||||
using Term = std::variant<Application, Lambda, InlineAssembly, VariableDeclaration, Reference, Constant>;
|
||||
using Term = std::variant<Application, Lambda, InlineAssembly, Reference, Constant>;
|
||||
|
||||
struct InlineAssembly: TermBase
|
||||
{
|
||||
@ -83,12 +92,6 @@ struct InlineAssembly: TermBase
|
||||
std::map<yul::Identifier const*, std::unique_ptr<Term>> references;
|
||||
};
|
||||
|
||||
struct VariableDeclaration: TermBase
|
||||
{
|
||||
std::unique_ptr<Term> namePattern;
|
||||
std::unique_ptr<Term> initialValue;
|
||||
};
|
||||
|
||||
struct Application: TermBase
|
||||
{
|
||||
std::unique_ptr<Term> expression;
|
||||
@ -145,41 +148,11 @@ langutil::SourceLocation locationOf(T const& _t)
|
||||
|
||||
struct AST
|
||||
{
|
||||
struct FunctionInfo {
|
||||
std::unique_ptr<Term> function;
|
||||
std::unique_ptr<Term> arguments;
|
||||
std::unique_ptr<Term> returnType;
|
||||
};
|
||||
std::map<frontend::FunctionDefinition const*, FunctionInfo, ASTCompareByID<frontend::FunctionDefinition>> functions;
|
||||
struct ContractInfo {
|
||||
std::map<std::string, FunctionInfo> functions;
|
||||
};
|
||||
std::map<frontend::ContractDefinition const*, ContractInfo, ASTCompareByID<frontend::ContractDefinition>> contracts;
|
||||
struct TypeInformation {
|
||||
std::unique_ptr<Term> declaration;
|
||||
std::unique_ptr<Term> arguments;
|
||||
std::unique_ptr<Term> value;
|
||||
};
|
||||
std::map<frontend::TypeDefinition const*, TypeInformation, ASTCompareByID<frontend::TypeDefinition>> typeDefinitions;
|
||||
struct TypeClassInformation {
|
||||
std::unique_ptr<Term> declaration;
|
||||
std::unique_ptr<Term> typeVariable;
|
||||
std::map<std::string, FunctionInfo> functions;
|
||||
};
|
||||
struct TypeClassInstantiationInformation {
|
||||
std::unique_ptr<Term> typeConstructor;
|
||||
std::unique_ptr<Term> argumentSorts;
|
||||
std::unique_ptr<Term> typeClass;
|
||||
std::map<std::string, FunctionInfo> functions;
|
||||
};
|
||||
std::map<frontend::TypeClassDefinition const*, TypeClassInformation, ASTCompareByID<frontend::TypeClassDefinition>> typeClasses;
|
||||
std::map<frontend::TypeClassInstantiation const*, TypeClassInstantiationInformation, ASTCompareByID<frontend::TypeClassInstantiation>> typeClassInstantiations;
|
||||
struct DeclarationInfo
|
||||
{
|
||||
Term const* target = nullptr;
|
||||
std::string name;
|
||||
};
|
||||
std::vector<DeclarationInfo> declarations;
|
||||
std::map<frontend::TypeDefinition const*, std::unique_ptr<Term>, ASTCompareByID<frontend::TypeDefinition>> typeDefinitions;
|
||||
std::map<frontend::TypeClassDefinition const*, std::unique_ptr<Term>, ASTCompareByID<frontend::TypeClassDefinition>> typeClasses;
|
||||
std::map<frontend::TypeClassInstantiation const*, std::unique_ptr<Term>, ASTCompareByID<frontend::TypeClassInstantiation>> typeClassInstantiations;
|
||||
std::map<frontend::FunctionDefinition const*, std::unique_ptr<Term>, ASTCompareByID<frontend::FunctionDefinition>> functions;
|
||||
std::map<frontend::ContractDefinition const*, std::unique_ptr<Term>, ASTCompareByID<frontend::ContractDefinition>> contracts;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -37,45 +37,6 @@ using namespace solidity::langutil;
|
||||
using namespace solidity::frontend;
|
||||
using namespace solidity::frontend::experimental;
|
||||
|
||||
/*std::optional<TypeConstructor> experimental::typeConstructorFromTypeName(Analysis const& _analysis, TypeName const& _typeName)
|
||||
{
|
||||
if (auto const* elementaryTypeName = dynamic_cast<ElementaryTypeName const*>(&_typeName))
|
||||
{
|
||||
if (auto constructor = typeConstructorFromToken(_analysis, elementaryTypeName->typeName().token()))
|
||||
return *constructor;
|
||||
}
|
||||
else if (auto const* userDefinedType = dynamic_cast<UserDefinedTypeName const*>(&_typeName))
|
||||
{
|
||||
if (auto const* referencedDeclaration = userDefinedType->pathNode().annotation().referencedDeclaration)
|
||||
return _analysis.annotation<TypeRegistration>(*referencedDeclaration).typeConstructor;
|
||||
}
|
||||
return nullopt;
|
||||
}*/
|
||||
/*
|
||||
std::optional<TypeConstructor> experimental::typeConstructorFromToken(Analysis const& _analysis, langutil::Token _token)
|
||||
{
|
||||
TypeSystem const& typeSystem = _analysis.typeSystem();
|
||||
switch(_token)
|
||||
{
|
||||
case Token::Void:
|
||||
return typeSystem.builtinConstructor(BuiltinType::Void);
|
||||
case Token::Fun:
|
||||
return typeSystem.builtinConstructor(BuiltinType::Function);
|
||||
case Token::Unit:
|
||||
return typeSystem.builtinConstructor(BuiltinType::Unit);
|
||||
case Token::Pair:
|
||||
return typeSystem.builtinConstructor(BuiltinType::Pair);
|
||||
case Token::Word:
|
||||
return typeSystem.builtinConstructor(BuiltinType::Word);
|
||||
case Token::Integer:
|
||||
return typeSystem.builtinConstructor(BuiltinType::Integer);
|
||||
case Token::Bool:
|
||||
return typeSystem.builtinConstructor(BuiltinType::Bool);
|
||||
default:
|
||||
return nullopt;
|
||||
}
|
||||
}*/
|
||||
|
||||
std::optional<BuiltinClass> experimental::builtinClassFromToken(langutil::Token _token)
|
||||
{
|
||||
switch (_token)
|
||||
@ -100,22 +61,7 @@ std::optional<BuiltinClass> experimental::builtinClassFromToken(langutil::Token
|
||||
return nullopt;
|
||||
}
|
||||
}
|
||||
/*
|
||||
std::optional<TypeClass> experimental::typeClassFromTypeClassName(TypeClassName const& _typeClass)
|
||||
{
|
||||
return std::visit(util::GenericVisitor{
|
||||
[&](ASTPointer<IdentifierPath> _path) -> optional<TypeClass> {
|
||||
auto classDefinition = dynamic_cast<TypeClassDefinition const*>(_path->annotation().referencedDeclaration);
|
||||
if (!classDefinition)
|
||||
return nullopt;
|
||||
return TypeClass{classDefinition};
|
||||
},
|
||||
[&](Token _token) -> optional<TypeClass> {
|
||||
return typeClassFromToken(_token);
|
||||
}
|
||||
}, _typeClass.name());
|
||||
}
|
||||
*/
|
||||
|
||||
experimental::Type TypeSystemHelpers::tupleType(vector<Type> _elements) const
|
||||
{
|
||||
if (_elements.empty())
|
||||
|
@ -18,16 +18,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/experimental/ast/TypeSystem.h>
|
||||
#include <libsolidity/ast/ASTForward.h>
|
||||
#include <liblangutil/Token.h>
|
||||
|
||||
namespace solidity::frontend::experimental
|
||||
{
|
||||
class Analysis;
|
||||
enum class BuiltinClass;
|
||||
//std::optional<TypeConstructor> typeConstructorFromTypeName(Analysis const& _analysis, TypeName const& _typeName);
|
||||
//std::optional<TypeConstructor> typeConstructorFromToken(Analysis const& _analysis, langutil::Token _token);
|
||||
//std::optional<TypeClass> typeClassFromTypeClassName(TypeClassName const& _typeClass);
|
||||
|
||||
std::optional<BuiltinClass> builtinClassFromToken(langutil::Token _token);
|
||||
|
||||
struct TypeSystemHelpers
|
||||
|
@ -1,6 +1,8 @@
|
||||
pragma experimental solidity;
|
||||
|
||||
type uint256 = word;
|
||||
/*
|
||||
type double(a) = (a,a);
|
||||
|
||||
instantiation uint256: + {
|
||||
function add(x, y) -> uint256 {
|
||||
@ -51,18 +53,22 @@ instantiation word: == {
|
||||
|
||||
function f(x:uint256->uint256,y:uint256) -> uint256
|
||||
{
|
||||
return x(y);
|
||||
x(y);
|
||||
}
|
||||
|
||||
function g(x:uint256) -> uint256
|
||||
*/
|
||||
function g(x) -> word
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
contract C {
|
||||
fallback() external {
|
||||
let z : uint256;
|
||||
let x : word;
|
||||
assembly {
|
||||
let y;
|
||||
y = (x:word);
|
||||
x = g(x);
|
||||
/*assembly {
|
||||
x := 0x10
|
||||
}
|
||||
let w = uint256.abs(x);
|
||||
@ -75,7 +81,7 @@ contract C {
|
||||
assembly {
|
||||
mstore(0, y)
|
||||
return(0, 32)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
// ====
|
||||
|
Loading…
Reference in New Issue
Block a user