This commit is contained in:
Daniel Kirchner 2023-06-21 01:04:14 +02:00
parent 1c1110f734
commit 3286d1cec2
18 changed files with 307 additions and 32 deletions

View File

@ -273,6 +273,7 @@ namespace solidity::langutil
K(Class, "class", 0) \ K(Class, "class", 0) \
K(Instantiation, "instantiation", 0) \ K(Instantiation, "instantiation", 0) \
K(Word, "word", 0) \ K(Word, "word", 0) \
K(Integer, "integer", 0) \
K(Void, "void", 0) \ K(Void, "void", 0) \
K(StaticAssert, "static_assert", 0) \ K(StaticAssert, "static_assert", 0) \
T(ExperimentalEnd, nullptr, 0) /* used as experimental enum end marker */ \ T(ExperimentalEnd, nullptr, 0) /* used as experimental enum end marker */ \
@ -301,7 +302,7 @@ namespace TokenTraits
// Predicates // Predicates
constexpr bool isElementaryTypeName(Token tok) constexpr bool isElementaryTypeName(Token tok)
{ {
return (Token::Int <= tok && tok < Token::TypesEnd) || tok == Token::Word || tok == Token::Void; return (Token::Int <= tok && tok < Token::TypesEnd) || tok == Token::Word || tok == Token::Void || tok == Token::Integer;
} }
constexpr bool isAssignmentOp(Token tok) { return Token::Assign <= tok && tok <= Token::AssignMod; } constexpr bool isAssignmentOp(Token tok) { return Token::Assign <= tok && tok <= Token::AssignMod; }
constexpr bool isBinaryOp(Token op) { return Token::Comma <= op && op <= Token::Exp; } constexpr bool isBinaryOp(Token op) { return Token::Comma <= op && op <= Token::Exp; }

View File

@ -451,7 +451,9 @@ bool SyntaxChecker::visit(UsingForDirective const& _usingFor)
bool SyntaxChecker::visit(FunctionDefinition const& _function) bool SyntaxChecker::visit(FunctionDefinition const& _function)
{ {
solAssert(_function.isFree() == (m_currentContractKind == std::nullopt), ""); if (m_sourceUnit && m_sourceUnit->experimentalSolidity())
// Handled in experimental::SyntaxRestrictor instead.
return true;
if (!_function.isFree() && !_function.isConstructor() && _function.noVisibilitySpecified()) if (!_function.isFree() && !_function.isConstructor() && _function.noVisibilitySpecified())
{ {
@ -506,3 +508,13 @@ bool SyntaxChecker::visit(StructDefinition const& _struct)
return true; return true;
} }
bool SyntaxChecker::visitNode(ASTNode const& _node)
{
if (_node.experimentalSolidityOnly())
{
solAssert(m_sourceUnit);
solAssert(m_sourceUnit->experimentalSolidity());
}
return ASTConstVisitor::visitNode(_node);
}

View File

@ -97,6 +97,8 @@ private:
bool visit(StructDefinition const& _struct) override; bool visit(StructDefinition const& _struct) override;
bool visit(Literal const& _literal) override; bool visit(Literal const& _literal) override;
bool visitNode(ASTNode const&) override;
langutil::ErrorReporter& m_errorReporter; langutil::ErrorReporter& m_errorReporter;
bool m_useYulOptimizer = false; bool m_useYulOptimizer = false;

View File

@ -32,7 +32,8 @@ bool SyntaxRestrictor::check(ASTNode const& _astRoot)
bool SyntaxRestrictor::visitNode(ASTNode const& _node) bool SyntaxRestrictor::visitNode(ASTNode const& _node)
{ {
m_errorReporter.syntaxError(0000_error, _node.location(), "Unsupported AST node."); if (!_node.experimentalSolidityOnly())
m_errorReporter.syntaxError(0000_error, _node.location(), "Unsupported AST node.");
return false; return false;
} }

View File

@ -41,11 +41,13 @@ m_errorReporter(_analysis.errorReporter())
{BuiltinType::Function, "fun", 2}, {BuiltinType::Function, "fun", 2},
{BuiltinType::Unit, "unit", 0}, {BuiltinType::Unit, "unit", 0},
{BuiltinType::Pair, "pair", 2}, {BuiltinType::Pair, "pair", 2},
{BuiltinType::Word, "word", 0} {BuiltinType::Word, "word", 0},
{BuiltinType::Integer, "integer", 0}
}) })
m_typeSystem.declareBuiltinType(type, name, arity); m_typeSystem.declareBuiltinType(type, name, arity);
m_voidType = m_typeSystem.builtinType(BuiltinType::Void, {}); m_voidType = m_typeSystem.builtinType(BuiltinType::Void, {});
m_wordType = m_typeSystem.builtinType(BuiltinType::Word, {}); m_wordType = m_typeSystem.builtinType(BuiltinType::Word, {});
m_integerType = m_typeSystem.builtinType(BuiltinType::Integer, {});
m_typeAnnotations.resize(_analysis.maxAstId()); m_typeAnnotations.resize(_analysis.maxAstId());
} }
@ -84,7 +86,8 @@ bool TypeInference::visit(FunctionDefinition const& _functionDefinition)
m_currentFunctionType = functionType; m_currentFunctionType = functionType;
_functionDefinition.body().accept(*this); if (_functionDefinition.isImplemented())
_functionDefinition.body().accept(*this);
functionAnnotation.type = m_typeSystem.fresh( functionAnnotation.type = m_typeSystem.fresh(
functionType, functionType,
@ -143,13 +146,32 @@ experimental::Type TypeInference::fromTypeName(TypeName const& _typeName)
return m_wordType; return m_wordType;
case Token::Void: case Token::Void:
return m_voidType; return m_voidType;
case Token::Integer:
return m_integerType;
default: default:
m_errorReporter.typeError(0000_error, _typeName.location(), "Only elementary types are supported."); m_errorReporter.typeError(0000_error, _typeName.location(), "Only elementary types are supported.");
break; break;
} }
} }
else if (auto const* userDefinedTypeName = dynamic_cast<UserDefinedTypeName const*>(&_typeName))
{
auto const* declaration = userDefinedTypeName->pathNode().annotation().referencedDeclaration;
solAssert(declaration);
if (auto const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(declaration))
{
if (auto const* typeClass = dynamic_cast<TypeClassDefinition const*>(variableDeclaration->scope()))
{
(void)typeClass;
m_errorReporter.typeError(0000_error, _typeName.location(), "Using type class type variables not yet implemented.");
}
else
m_errorReporter.typeError(0000_error, _typeName.location(), "Type name referencing a variable declaration.");
}
else
m_errorReporter.typeError(0000_error, _typeName.location(), "Unsupported user defined type name.");
}
else else
m_errorReporter.typeError(0000_error, _typeName.location(), "Only elementary types are supported."); m_errorReporter.typeError(0000_error, _typeName.location(), "Unsupported type name.");
return m_typeSystem.freshTypeVariable(false); return m_typeSystem.freshTypeVariable(false);
} }

View File

@ -57,6 +57,8 @@ private:
bool visit(Return const&) override { return true; } bool visit(Return const&) override { return true; }
void endVisit(Return const& _return) override; void endVisit(Return const& _return) override;
bool visit(TypeClassDefinition const&) override { return true; }
bool visitNode(ASTNode const& _node) override; bool visitNode(ASTNode const& _node) override;
Type fromTypeName(TypeName const& _typeName); Type fromTypeName(TypeName const& _typeName);
@ -65,6 +67,7 @@ private:
TypeSystem m_typeSystem; TypeSystem m_typeSystem;
Type m_voidType; Type m_voidType;
Type m_wordType; Type m_wordType;
Type m_integerType;
std::optional<Type> m_currentFunctionType; std::optional<Type> m_currentFunctionType;
struct TypeAnnotation struct TypeAnnotation

View File

@ -1058,3 +1058,11 @@ TryCatchClause const* TryStatement::errorClause() const {
TryCatchClause const* TryStatement::fallbackClause() const { TryCatchClause const* TryStatement::fallbackClause() const {
return findClause(m_clauses); return findClause(m_clauses);
} }
/// Experimental Solidity nodes
/// @{
TypeClassDefinitionAnnotation& TypeClassDefinition::annotation() const
{
return initAnnotation<TypeClassDefinitionAnnotation>();
}
/// @}

View File

@ -121,6 +121,8 @@ public:
bool operator!=(ASTNode const& _other) const { return !operator==(_other); } bool operator!=(ASTNode const& _other) const { return !operator==(_other); }
///@} ///@}
virtual bool experimentalSolidityOnly() const { return false; }
protected: protected:
size_t const m_id = 0; size_t const m_id = 0;
@ -2447,4 +2449,43 @@ private:
/// @} /// @}
/// Experimental Solidity nodes
/// @{
class TypeClassDefinition: public Declaration, public StructurallyDocumented, public ScopeOpener
{
public:
TypeClassDefinition(
int64_t _id,
SourceLocation const& _location,
ASTPointer<VariableDeclaration> _typeVariable,
ASTPointer<ASTString> const& _name,
SourceLocation _nameLocation,
ASTPointer<StructuredDocumentation> const& _documentation,
std::vector<ASTPointer<ASTNode>> _subNodes
):
Declaration(_id, _location, _name, std::move(_nameLocation)),
StructurallyDocumented(_documentation),
m_typeVariable(std::move(_typeVariable)),
m_subNodes(std::move(_subNodes))
{}
void accept(ASTVisitor& _visitor) override;
void accept(ASTConstVisitor& _visitor) const override;
VariableDeclaration const& typeVariable() const { return *m_typeVariable; }
std::vector<ASTPointer<ASTNode>> const& subNodes() const { return m_subNodes; }
TypeClassDefinitionAnnotation& annotation() const override;
Type const* type() const override { solAssert(false, "Requested type of experimental solidity node."); }
bool experimentalSolidityOnly() const override { return true; }
private:
ASTPointer<VariableDeclaration> m_typeVariable;
std::vector<ASTPointer<ASTNode>> m_subNodes;
};
/// @}
} }

View File

@ -341,4 +341,12 @@ struct FunctionCallAnnotation: ExpressionAnnotation
bool tryCall = false; bool tryCall = false;
}; };
/// Experimental Solidity annotations.
/// Used to intergrate with name and type resolution.
/// @{
struct TypeClassDefinitionAnnotation: TypeDeclarationAnnotation, StructurallyDocumentedAnnotation
{
};
/// @}
} }

View File

@ -1033,6 +1033,15 @@ void ASTJsonExporter::endVisit(EventDefinition const&)
m_inEvent = false; m_inEvent = false;
} }
bool ASTJsonExporter::visitNode(ASTNode const& _node)
{
solAssert(false, _node.experimentalSolidityOnly() ?
"Attempt to export an AST of experimental solidity." :
"Attempt to export an AST that contains unexpected nodes."
);
return false;
}
string ASTJsonExporter::location(VariableDeclaration::Location _location) string ASTJsonExporter::location(VariableDeclaration::Location _location)
{ {
switch (_location) switch (_location)

View File

@ -130,6 +130,7 @@ public:
void endVisit(EventDefinition const&) override; void endVisit(EventDefinition const&) override;
bool visitNode(ASTNode const& _node) override;
private: private:
void setJsonNode( void setJsonNode(
ASTNode const& _node, ASTNode const& _node,

View File

@ -109,6 +109,10 @@ public:
virtual bool visit(ElementaryTypeNameExpression& _node) { return visitNode(_node); } virtual bool visit(ElementaryTypeNameExpression& _node) { return visitNode(_node); }
virtual bool visit(Literal& _node) { return visitNode(_node); } virtual bool visit(Literal& _node) { return visitNode(_node); }
virtual bool visit(StructuredDocumentation& _node) { return visitNode(_node); } virtual bool visit(StructuredDocumentation& _node) { return visitNode(_node); }
/// Experimental Solidity nodes
/// @{
virtual bool visit(TypeClassDefinition& _node) { return visitNode(_node); }
/// @}
virtual void endVisit(SourceUnit& _node) { endVisitNode(_node); } virtual void endVisit(SourceUnit& _node) { endVisitNode(_node); }
virtual void endVisit(PragmaDirective& _node) { endVisitNode(_node); } virtual void endVisit(PragmaDirective& _node) { endVisitNode(_node); }
@ -165,6 +169,10 @@ public:
virtual void endVisit(ElementaryTypeNameExpression& _node) { endVisitNode(_node); } virtual void endVisit(ElementaryTypeNameExpression& _node) { endVisitNode(_node); }
virtual void endVisit(Literal& _node) { endVisitNode(_node); } virtual void endVisit(Literal& _node) { endVisitNode(_node); }
virtual void endVisit(StructuredDocumentation& _node) { endVisitNode(_node); } virtual void endVisit(StructuredDocumentation& _node) { endVisitNode(_node); }
/// Experimental Solidity nodes
/// @{
virtual void endVisit(TypeClassDefinition& _node) { endVisitNode(_node); }
/// @}
protected: protected:
/// Generic function called by default for each node, to be overridden by derived classes /// Generic function called by default for each node, to be overridden by derived classes
@ -243,6 +251,10 @@ public:
virtual bool visit(ElementaryTypeNameExpression const& _node) { return visitNode(_node); } virtual bool visit(ElementaryTypeNameExpression const& _node) { return visitNode(_node); }
virtual bool visit(Literal const& _node) { return visitNode(_node); } virtual bool visit(Literal const& _node) { return visitNode(_node); }
virtual bool visit(StructuredDocumentation const& _node) { return visitNode(_node); } virtual bool visit(StructuredDocumentation const& _node) { return visitNode(_node); }
/// Experimental Solidity nodes
/// @{
virtual bool visit(TypeClassDefinition const& _node) { return visitNode(_node); }
/// @}
virtual void endVisit(SourceUnit const& _node) { endVisitNode(_node); } virtual void endVisit(SourceUnit const& _node) { endVisitNode(_node); }
virtual void endVisit(PragmaDirective const& _node) { endVisitNode(_node); } virtual void endVisit(PragmaDirective const& _node) { endVisitNode(_node); }
@ -299,6 +311,10 @@ public:
virtual void endVisit(ElementaryTypeNameExpression const& _node) { endVisitNode(_node); } virtual void endVisit(ElementaryTypeNameExpression const& _node) { endVisitNode(_node); }
virtual void endVisit(Literal const& _node) { endVisitNode(_node); } virtual void endVisit(Literal const& _node) { endVisitNode(_node); }
virtual void endVisit(StructuredDocumentation const& _node) { endVisitNode(_node); } virtual void endVisit(StructuredDocumentation const& _node) { endVisitNode(_node); }
/// Experimental Solidity nodes
/// @{
virtual void endVisit(TypeClassDefinition const& _node) { endVisitNode(_node); }
/// @}
protected: protected:
/// Generic function called by default for each node, to be overridden by derived classes /// Generic function called by default for each node, to be overridden by derived classes

View File

@ -1024,4 +1024,31 @@ void Literal::accept(ASTConstVisitor& _visitor) const
_visitor.endVisit(*this); _visitor.endVisit(*this);
} }
/// Experimental Solidity nodes
/// @{
void TypeClassDefinition::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
{
m_typeVariable->accept(_visitor);
if (m_documentation)
m_documentation->accept(_visitor);
listAccept(m_subNodes, _visitor);
}
_visitor.endVisit(*this);
}
void TypeClassDefinition::accept(ASTConstVisitor& _visitor) const
{
if (_visitor.visit(*this))
{
m_typeVariable->accept(_visitor);
if (m_documentation)
m_documentation->accept(_visitor);
listAccept(m_subNodes, _visitor);
}
_visitor.endVisit(*this);
}
/// @}
} }

View File

@ -40,26 +40,52 @@ std::string TypeSystem::typeToString(Type const& _type) const
return std::visit(util::GenericVisitor{ return std::visit(util::GenericVisitor{
[&](TypeExpression const& _type) { [&](TypeExpression const& _type) {
std::stringstream stream; std::stringstream stream;
if (!_type.arguments.empty()) auto printTypeArguments = [&]() {
{ if (!_type.arguments.empty())
stream << "("; {
for (auto type: _type.arguments | ranges::views::drop_last(1)) stream << "(";
stream << typeToString(type) << ", "; for (auto type: _type.arguments | ranges::views::drop_last(1))
stream << typeToString(_type.arguments.back()); stream << typeToString(type) << ", ";
stream << ") "; stream << typeToString(_type.arguments.back());
} stream << ") ";
stream << std::visit(util::GenericVisitor{ }
};
std::visit(util::GenericVisitor{
[&](Declaration const* _declaration) { [&](Declaration const* _declaration) {
return _declaration->name(); printTypeArguments();
stream << _declaration->name();
}, },
[&](BuiltinType _builtinType) -> string { [&](BuiltinType _builtinType) {
return builtinTypeName(_builtinType); switch (_builtinType)
{
case BuiltinType::Function:
solAssert(_type.arguments.size() == 2);
stream << fmt::format("{} -> {}", typeToString(_type.arguments.front()), typeToString(_type.arguments.back()));
break;
case BuiltinType::Unit:
solAssert(_type.arguments.empty());
stream << "()";
break;
case BuiltinType::Pair:
{
auto tupleTypes = TypeSystemHelpers{*this}.destTupleType(_type);
stream << "(";
for (auto type: tupleTypes | ranges::view::drop_last(1))
stream << typeToString(type) << ", ";
stream << typeToString(tupleTypes.back()) << ")";
break;
}
default:
printTypeArguments();
stream << builtinTypeName(_builtinType);
break;
}
} }
}, _type.constructor); }, _type.constructor);
return stream.str(); return stream.str();
}, },
[](TypeVariable const& _type) { [](TypeVariable const& _type) {
return fmt::format("var[{}]", _type.index()); return fmt::format("{}var{}", _type.generic() ? '?' : '\'', _type.index());
}, },
}, resolve(_type)); }, resolve(_type));
} }
@ -180,6 +206,41 @@ experimental::Type TypeSystemHelpers::tupleType(vector<Type> _elements) const
return result; return result;
} }
vector<experimental::Type> TypeSystemHelpers::destTupleType(Type _tupleType) const
{
auto [constructor, arguments] = destTypeExpression(_tupleType);
if (auto const* builtinType = get_if<BuiltinType>(&constructor))
{
if (*builtinType == BuiltinType::Unit)
return {};
else if (*builtinType != BuiltinType::Pair)
return {_tupleType};
}
else
return {_tupleType};
solAssert(arguments.size() == 2);
vector<Type> result;
result.emplace_back(arguments.front());
Type tail = arguments.back();
while(true)
{
auto const* tailTypeExpression = get_if<TypeExpression>(&tail);
if (!tailTypeExpression)
break;
auto [tailConstructor, tailArguments] = destTypeExpression(tail);
auto const* builtinType = get_if<BuiltinType>(&tailConstructor);
if(!builtinType || *builtinType != BuiltinType::Pair)
break;
solAssert(tailArguments.size() == 2);
result.emplace_back(tailArguments.front());
tail = tailArguments.back();
}
result.emplace_back(tail);
return result;
}
experimental::Type TypeSystemHelpers::functionType(experimental::Type _argType, experimental::Type _resultType) const experimental::Type TypeSystemHelpers::functionType(experimental::Type _argType, experimental::Type _resultType) const
{ {
return typeSystem.builtinType(BuiltinType::Function, {_argType, _resultType}); return typeSystem.builtinType(BuiltinType::Function, {_argType, _resultType});
@ -198,7 +259,6 @@ tuple<TypeExpression::Constructor, vector<experimental::Type>> TypeSystemHelpers
}, _functionType); }, _functionType);
} }
tuple<experimental::Type, experimental::Type> TypeSystemHelpers::destFunctionType(Type _functionType) const tuple<experimental::Type, experimental::Type> TypeSystemHelpers::destFunctionType(Type _functionType) const
{ {
auto [constructor, arguments] = destTypeExpression(_functionType); auto [constructor, arguments] = destTypeExpression(_functionType);

View File

@ -46,7 +46,8 @@ enum class BuiltinType
Function, Function,
Unit, Unit,
Pair, Pair,
Word Word,
Integer
}; };
struct TypeExpression struct TypeExpression
@ -104,10 +105,11 @@ private:
struct TypeSystemHelpers struct TypeSystemHelpers
{ {
TypeSystem& typeSystem; TypeSystem const& typeSystem;
Type tupleType(std::vector<Type> _elements) const;
Type functionType(Type _argType, Type _resultType) const;
std::tuple<TypeExpression::Constructor, std::vector<Type>> destTypeExpression(Type _functionType) const; std::tuple<TypeExpression::Constructor, std::vector<Type>> destTypeExpression(Type _functionType) const;
Type tupleType(std::vector<Type> _elements) const;
std::vector<Type> destTupleType(Type _tupleType) const;
Type functionType(Type _argType, Type _resultType) const;
std::tuple<Type, Type> destFunctionType(Type _functionType) const; std::tuple<Type, Type> destFunctionType(Type _functionType) const;
}; };

View File

@ -134,6 +134,10 @@ ASTPointer<SourceUnit> Parser::parse(CharStream& _charStream)
case Token::Function: case Token::Function:
nodes.push_back(parseFunctionDefinition(true)); nodes.push_back(parseFunctionDefinition(true));
break; break;
case Token::Class:
solAssert(m_experimentalSolidityEnabledInCurrentSourceUnit);
nodes.push_back(parseTypeClassDefinition());
break;
default: default:
if ( if (
// Workaround because `error` is not a keyword. // Workaround because `error` is not a keyword.
@ -623,7 +627,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari
return result; return result;
} }
ASTPointer<ASTNode> Parser::parseFunctionDefinition(bool _freeFunction) ASTPointer<ASTNode> Parser::parseFunctionDefinition(bool _freeFunction, bool _allowBody)
{ {
RecursionGuard recursionGuard(*this); RecursionGuard recursionGuard(*this);
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
@ -673,7 +677,9 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinition(bool _freeFunction)
ASTPointer<Block> block; ASTPointer<Block> block;
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
if (m_scanner->currentToken() == Token::Semicolon) if (!_allowBody)
expectToken(Token::Semicolon);
else if (m_scanner->currentToken() == Token::Semicolon)
advance(); advance();
else else
{ {
@ -1270,6 +1276,13 @@ ASTPointer<ParameterList> Parser::parseParameterList(
vector<ASTPointer<VariableDeclaration>> parameters; vector<ASTPointer<VariableDeclaration>> parameters;
VarDeclParserOptions options(_options); VarDeclParserOptions options(_options);
options.allowEmptyName = true; options.allowEmptyName = true;
if (m_experimentalSolidityEnabledInCurrentSourceUnit && m_scanner->currentToken() == Token::Identifier)
{
// Parses unary parameter lists without parentheses. TODO: is this a good idea in all cases? Including arguments?
parameters = {parsePostfixVariableDeclaration()};
nodeFactory.setEndPositionFromNode(parameters.front());
return nodeFactory.createNode<ParameterList>(parameters);
}
expectToken(Token::LParen); expectToken(Token::LParen);
auto parseSingleVariableDeclaration = [&]() { auto parseSingleVariableDeclaration = [&]() {
if (m_experimentalSolidityEnabledInCurrentSourceUnit) if (m_experimentalSolidityEnabledInCurrentSourceUnit)
@ -1717,6 +1730,54 @@ ASTPointer<VariableDeclaration> Parser::parsePostfixVariableDeclaration()
); );
} }
ASTPointer<TypeClassDefinition> Parser::parseTypeClassDefinition()
{
RecursionGuard recursionGuard(*this);
ASTNodeFactory nodeFactory(*this);
vector<ASTPointer<ASTNode>> subNodes;
ASTPointer<StructuredDocumentation> const documentation = parseStructuredDocumentation();
expectToken(Token::Class);
// TODO: parseTypeVariable()? parseTypeVariableDeclaration()?
ASTPointer<VariableDeclaration> typeVariable;
{
ASTNodeFactory nodeFactory(*this);
nodeFactory.markEndPosition();
auto [identifier, nameLocation] = expectIdentifierWithLocation();
typeVariable = nodeFactory.createNode<VariableDeclaration>(
nullptr,
identifier,
nameLocation,
nullptr,
Visibility::Default,
nullptr
);
}
expectToken(Token::Colon);
auto [name, nameLocation] = expectIdentifierWithLocation();
expectToken(Token::LBrace);
while (true)
{
Token currentTokenValue = m_scanner->currentToken();
if (currentTokenValue == Token::RBrace)
break;
expectToken(Token::Function, false);
subNodes.push_back(parseFunctionDefinition(false, false));
}
nodeFactory.markEndPosition();
expectToken(Token::RBrace);
return nodeFactory.createNode<TypeClassDefinition>(
typeVariable,
name,
nameLocation,
documentation,
subNodes
);
}
ASTPointer<Statement> Parser::parseSimpleStatement(ASTPointer<ASTString> const& _docString) ASTPointer<Statement> Parser::parseSimpleStatement(ASTPointer<ASTString> const& _docString)
{ {
RecursionGuard recursionGuard(*this); RecursionGuard recursionGuard(*this);

View File

@ -102,7 +102,7 @@ private:
ASTPointer<OverrideSpecifier> parseOverrideSpecifier(); ASTPointer<OverrideSpecifier> parseOverrideSpecifier();
StateMutability parseStateMutability(); StateMutability parseStateMutability();
FunctionHeaderParserResult parseFunctionHeader(bool _isStateVariable); FunctionHeaderParserResult parseFunctionHeader(bool _isStateVariable);
ASTPointer<ASTNode> parseFunctionDefinition(bool _freeFunction = false); ASTPointer<ASTNode> parseFunctionDefinition(bool _freeFunction = false, bool _allowBody = true);
ASTPointer<StructDefinition> parseStructDefinition(); ASTPointer<StructDefinition> parseStructDefinition();
ASTPointer<EnumDefinition> parseEnumDefinition(); ASTPointer<EnumDefinition> parseEnumDefinition();
ASTPointer<UserDefinedValueTypeDefinition> parseUserDefinedValueTypeDefinition(); ASTPointer<UserDefinedValueTypeDefinition> parseUserDefinedValueTypeDefinition();
@ -176,6 +176,7 @@ private:
ASTPointer<ASTString> const& _docString ASTPointer<ASTString> const& _docString
); );
ASTPointer<VariableDeclaration> parsePostfixVariableDeclaration(); ASTPointer<VariableDeclaration> parsePostfixVariableDeclaration();
ASTPointer<TypeClassDefinition> parseTypeClassDefinition();
///@} ///@}
///@{ ///@{

View File

@ -1,10 +1,10 @@
pragma experimental solidity; pragma experimental solidity;
/*
class a:StackType {
function stackSize() -> (integer);
}
class a:StackType {
function stackSize() -> x:integer;
}
/*
instantiate uint256 : StackType { instantiate uint256 : StackType {
function stackSize() -> (integer) { function stackSize() -> (integer) {
return 1; return 1;
@ -12,7 +12,7 @@ instantiate uint256 : StackType {
} }
*/ */
function f(a) -> (b) { function f(a) -> b {
return a; return a;
} }