Parse everything up to function bodies and report parser errors with location.

This commit is contained in:
Christian 2014-10-08 20:53:50 +02:00
parent 56e9cc8db7
commit 0a1ebe4f51
8 changed files with 264 additions and 68 deletions

91
AST.h
View File

@ -32,6 +32,9 @@
namespace dev { namespace dev {
namespace solidity { namespace solidity {
// Used as pointers to AST nodes, to be replaced by more clever pointers, e.g. pointers which do
// not do reference counting but point to a special memory area that is completely released
// explicitly.
template <class T> template <class T>
using ptr = std::shared_ptr<T>; using ptr = std::shared_ptr<T>;
template <class T> template <class T>
@ -47,9 +50,11 @@ class Expression;
class ASTNode class ASTNode
{ {
public: public:
explicit ASTNode(const Location& _location) explicit ASTNode(Location const& _location)
: m_location(_location) : m_location(_location)
{} {}
Location getLocation() const { return m_location; }
private: private:
Location m_location; Location m_location;
}; };
@ -57,13 +62,12 @@ private:
class ContractDefinition : public ASTNode class ContractDefinition : public ASTNode
{ {
public: public:
ContractDefinition(const Location& _location, ContractDefinition(Location const& _location,
const std::string& _name, std::string const& _name,
const vecptr<StructDefinition>& _definedStructs, vecptr<StructDefinition> const& _definedStructs,
const vecptr<VariableDeclaration>& _stateVariables, vecptr<VariableDeclaration> const& _stateVariables,
const vecptr<FunctionDefinition>& _definedFunctions) vecptr<FunctionDefinition> const& _definedFunctions)
: ASTNode(_location), : ASTNode(_location), m_name(_name),
m_name(_name),
m_definedStructs(_definedStructs), m_definedStructs(_definedStructs),
m_stateVariables(_stateVariables), m_stateVariables(_stateVariables),
m_definedFunctions(_definedFunctions) m_definedFunctions(_definedFunctions)
@ -78,33 +82,61 @@ private:
class StructDefinition : public ASTNode class StructDefinition : public ASTNode
{ {
public:
StructDefinition(Location const& _location,
std::string const& _name,
vecptr<VariableDeclaration> const& _members)
: ASTNode(_location), m_name(_name), m_members(_members)
{}
private: private:
std::string m_name; std::string m_name;
vecptr<VariableDeclaration> m_members; vecptr<VariableDeclaration> m_members;
}; };
/// Used as function parameter list and return list
/// None of the parameters is allowed to contain mappings (not even recursively
/// inside structs)
class ParameterList : public ASTNode
{
public:
ParameterList(Location const& _location, vecptr<VariableDeclaration> const& _parameters)
: ASTNode(_location), m_parameters(_parameters)
{}
private:
vecptr<VariableDeclaration> m_parameters;
};
class FunctionDefinition : public ASTNode class FunctionDefinition : public ASTNode
{ {
public:
FunctionDefinition(Location const& _location, std::string const& _name, bool _isPublic,
ptr<ParameterList> const& _parameters,
bool _isDeclaredConst,
ptr<ParameterList> const& _returnParameters,
ptr<Block> const& _body)
: ASTNode(_location), m_name(_name), m_isPublic(_isPublic), m_parameters(_parameters),
m_isDeclaredConst(_isDeclaredConst), m_returnParameters(_returnParameters),
m_body(_body)
{}
private: private:
std::string m_name; std::string m_name;
vecptr<VariableDeclaration> m_arguments; bool m_isPublic;
ptr<ParameterList> m_parameters;
bool m_isDeclaredConst; bool m_isDeclaredConst;
vecptr<VariableDeclaration> m_returns; ptr<ParameterList> m_returnParameters;
ptr<Block> m_body; ptr<Block> m_body;
}; };
class VariableDeclaration : public ASTNode class VariableDeclaration : public ASTNode
{ {
public: public:
VariableDeclaration(const Location& _location, VariableDeclaration(Location const& _location,
const ptr<TypeName>& _type, ptr<TypeName> const& _type,
const std::string& _name) std::string const& _name)
: ASTNode(_location), : ASTNode(_location), m_type(_type), m_name(_name)
m_type(_type),
m_name(_name)
{} {}
private: private:
ptr<TypeName> m_type; ///<s can be empty ("var") ptr<TypeName> m_type; ///< can be empty ("var")
std::string m_name; std::string m_name;
}; };
@ -114,7 +146,7 @@ private:
class TypeName : public ASTNode class TypeName : public ASTNode
{ {
public: public:
explicit TypeName(const Location& _location) explicit TypeName(Location const& _location)
: ASTNode(_location) : ASTNode(_location)
{} {}
}; };
@ -123,7 +155,7 @@ public:
class ElementaryTypeName : public TypeName class ElementaryTypeName : public TypeName
{ {
public: public:
explicit ElementaryTypeName(const Location& _location, Token::Value _type) explicit ElementaryTypeName(Location const& _location, Token::Value _type)
: TypeName(_location), m_type(_type) : TypeName(_location), m_type(_type)
{} {}
private: private:
@ -133,18 +165,19 @@ private:
class UserDefinedTypeName : public TypeName class UserDefinedTypeName : public TypeName
{ {
public: public:
UserDefinedTypeName(const Location& _location, const std::string& _name) UserDefinedTypeName(Location const& _location, std::string const& _name)
: TypeName(_location), m_name(_name) : TypeName(_location), m_name(_name)
{} {}
private: private:
std::string m_name; std::string m_name;
}; };
class MappingTypeName : public TypeName class Mapping : public TypeName
{ {
public: public:
explicit MappingTypeName(const Location& _location) Mapping(Location const& _location, ptr<ElementaryTypeName> const& _keyType,
: TypeName(_location) ptr<TypeName> const& _valueType)
: TypeName(_location), m_keyType(_keyType), m_valueType(_valueType)
{} {}
private: private:
ptr<ElementaryTypeName> m_keyType; ptr<ElementaryTypeName> m_keyType;
@ -158,10 +191,18 @@ private:
class Statement : public ASTNode class Statement : public ASTNode
{ {
public:
explicit Statement(Location const& _location)
: ASTNode(_location)
{}
}; };
class Block : public Statement class Block : public Statement
{ {
public:
explicit Block(Location const& _location)
: Statement(_location)
{}
private: private:
vecptr<Statement> m_statements; vecptr<Statement> m_statements;
}; };
@ -245,10 +286,12 @@ private:
Token::Value m_operator; Token::Value m_operator;
}; };
/// Can be ordinary function call, type cast or struct construction.
class FunctionCall : public Expression class FunctionCall : public Expression
{ {
private: private:
std::string m_functionName; // TODO only calls to fixed, named functions for now // if m_functionName is the name of a type, store the token directly
std::string m_functionName; // "in place" calls of return values are not possible for now
vecptr<Expression> m_arguments; vecptr<Expression> m_arguments;
}; };

View File

@ -4,19 +4,16 @@
namespace dev { namespace dev {
namespace solidity { namespace solidity {
// Representation of an interval of source positions. /// Representation of an interval of source positions.
/// The interval includes start and excludes end.
struct Location { struct Location {
Location(int b, int e) : beg_pos(b), end_pos(e) { } Location(int _start, int _end) : start(_start), end(_end) { }
Location() : beg_pos(0), end_pos(0) { } Location() : start(-1), end(-1) { }
bool IsValid() const { bool IsValid() const { return start >= 0 && end >= start; }
return beg_pos >= 0 && end_pos >= beg_pos;
}
static Location invalid() { return Location(-1, -1); } int start;
int end;
int beg_pos;
int end_pos;
}; };
} } } }

View File

@ -20,6 +20,7 @@
* Solidity parser. * Solidity parser.
*/ */
#include "libdevcore/Log.h"
#include "libsolidity/BaseTypes.h" #include "libsolidity/BaseTypes.h"
#include "libsolidity/Parser.h" #include "libsolidity/Parser.h"
#include "libsolidity/Scanner.h" #include "libsolidity/Scanner.h"
@ -27,9 +28,9 @@
namespace dev { namespace dev {
namespace solidity { namespace solidity {
ptr<ASTNode> Parser::parse(Scanner& _scanner) ptr<ASTNode> Parser::parse(std::shared_ptr<Scanner> const& _scanner)
{ {
m_scanner = &_scanner; m_scanner = _scanner;
return parseContractDefinition(); return parseContractDefinition();
} }
@ -41,20 +42,22 @@ class Parser::ASTNodeFactory
{ {
public: public:
ASTNodeFactory(const Parser& _parser) ASTNodeFactory(const Parser& _parser)
: m_parser(_parser), : m_parser(_parser), m_location(_parser.getPosition(), -1)
m_location(_parser.getPosition(), -1)
{} {}
void markEndPosition() void markEndPosition() { m_location.end = m_parser.getEndPosition(); }
/// Set the end position to the one of the given node.
void setEndPositionFromNode(const ptr<ASTNode>& _node)
{ {
m_location.end_pos = m_parser.getEndPosition(); m_location.end = _node->getLocation().end;
} }
/// @todo: check that this actually uses perfect forwarding /// @todo: check that this actually uses perfect forwarding
template <class NodeType, typename... Args> template <class NodeType, typename... Args>
ptr<NodeType> createNode(Args&&... _args) ptr<NodeType> createNode(Args&&... _args)
{ {
if (m_location.end_pos < 0) markEndPosition(); if (m_location.end < 0) markEndPosition();
return std::make_shared<NodeType>(m_location, std::forward<Args>(_args)...); return std::make_shared<NodeType>(m_location, std::forward<Args>(_args)...);
} }
@ -65,12 +68,12 @@ private:
int Parser::getPosition() const int Parser::getPosition() const
{ {
return m_scanner->getCurrentLocation().beg_pos; return m_scanner->getCurrentLocation().start;
} }
int Parser::getEndPosition() const int Parser::getEndPosition() const
{ {
return m_scanner->getCurrentLocation().end_pos; return m_scanner->getCurrentLocation().end;
} }
@ -98,7 +101,6 @@ ptr<ContractDefinition> Parser::parseContractDefinition()
functions.push_back(parseFunctionDefinition(visibilityIsPublic)); functions.push_back(parseFunctionDefinition(visibilityIsPublic));
} else if (currentToken == Token::STRUCT) { } else if (currentToken == Token::STRUCT) {
structs.push_back(parseStructDefinition()); structs.push_back(parseStructDefinition());
expectToken(Token::SEMICOLON);
} else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING || } else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING ||
Token::IsElementaryTypeName(currentToken)) { Token::IsElementaryTypeName(currentToken)) {
stateVariables.push_back(parseVariableDeclaration()); stateVariables.push_back(parseVariableDeclaration());
@ -117,19 +119,57 @@ ptr<ContractDefinition> Parser::parseContractDefinition()
ptr<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic) ptr<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic)
{ {
(void) _isPublic; ASTNodeFactory nodeFactory(*this);
throwExpectationError("Function parsing is not yet implemented.");
expectToken(Token::FUNCTION);
std::string name(expectIdentifier());
ptr<ParameterList> parameters(parseParameterList());
bool isDeclaredConst = false;
if (m_scanner->getCurrentToken() == Token::CONST) {
isDeclaredConst = true;
m_scanner->next();
}
ptr<ParameterList> returnParameters;
if (m_scanner->getCurrentToken() == Token::RETURNS) {
m_scanner->next();
returnParameters = parseParameterList();
}
ptr<Block> block = parseBlock();
nodeFactory.setEndPositionFromNode(block);
return nodeFactory.createNode<FunctionDefinition>(name, _isPublic, parameters,
isDeclaredConst, returnParameters, block);
} }
ptr<StructDefinition> Parser::parseStructDefinition() ptr<StructDefinition> Parser::parseStructDefinition()
{ {
throwExpectationError("Struct definition parsing is not yet implemented."); ASTNodeFactory nodeFactory(*this);
expectToken(Token::STRUCT);
std::string name = expectIdentifier();
vecptr<VariableDeclaration> members;
expectToken(Token::LBRACE);
while (m_scanner->getCurrentToken() != Token::RBRACE) {
members.push_back(parseVariableDeclaration());
expectToken(Token::SEMICOLON);
}
nodeFactory.markEndPosition();
expectToken(Token::RBRACE);
return nodeFactory.createNode<StructDefinition>(name, members);
} }
ptr<VariableDeclaration> Parser::parseVariableDeclaration() ptr<VariableDeclaration> Parser::parseVariableDeclaration()
{ {
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
ptr<TypeName> type = parseTypeName();
nodeFactory.markEndPosition();
std::string name = expectIdentifier();
return nodeFactory.createNode<VariableDeclaration>(type, name);
}
ptr<TypeName> Parser::parseTypeName()
{
ptr<TypeName> type; ptr<TypeName> type;
Token::Value token = m_scanner->getCurrentToken(); Token::Value token = m_scanner->getCurrentToken();
if (Token::IsElementaryTypeName(token)) { if (Token::IsElementaryTypeName(token)) {
@ -139,17 +179,67 @@ ptr<VariableDeclaration> Parser::parseVariableDeclaration()
type = ASTNodeFactory(*this).createNode<TypeName>(); type = ASTNodeFactory(*this).createNode<TypeName>();
m_scanner->next(); m_scanner->next();
} else if (token == Token::MAPPING) { } else if (token == Token::MAPPING) {
// TODO type = parseMapping();
throwExpectationError("mappings are not yet implemented");
} else if (token == Token::IDENTIFIER) { } else if (token == Token::IDENTIFIER) {
type = ASTNodeFactory(*this).createNode<UserDefinedTypeName>(m_scanner->getCurrentLiteral()); type = ASTNodeFactory(*this).createNode<UserDefinedTypeName>(m_scanner->getCurrentLiteral());
m_scanner->next(); m_scanner->next();
} else { } else {
throwExpectationError("Expected variable declaration"); throwExpectationError("Expected type name");
}
return type;
}
ptr<Mapping> Parser::parseMapping()
{
ASTNodeFactory nodeFactory(*this);
expectToken(Token::MAPPING);
expectToken(Token::LPAREN);
if (!Token::IsElementaryTypeName(m_scanner->getCurrentToken()))
throwExpectationError("Expected elementary type name for mapping key type");
ptr<ElementaryTypeName> keyType;
keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(m_scanner->getCurrentToken());
m_scanner->next();
expectToken(Token::ARROW);
ptr<TypeName> valueType = parseTypeName();
nodeFactory.markEndPosition();
expectToken(Token::RPAREN);
return nodeFactory.createNode<Mapping>(keyType, valueType);
}
ptr<ParameterList> Parser::parseParameterList()
{
ASTNodeFactory nodeFactory(*this);
vecptr<VariableDeclaration> parameters;
expectToken(Token::LPAREN);
if (m_scanner->getCurrentToken() != Token::RPAREN) {
parameters.push_back(parseVariableDeclaration());
while (m_scanner->getCurrentToken() != Token::RPAREN) {
expectToken(Token::COMMA);
parameters.push_back(parseVariableDeclaration());
}
} }
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
std::string name = expectIdentifier(); m_scanner->next();
return nodeFactory.createNode<VariableDeclaration>(type, name); return nodeFactory.createNode<ParameterList>(parameters);
}
ptr<Block> Parser::parseBlock()
{
ASTNodeFactory nodeFactory(*this);
expectToken(Token::LBRACE);
while (m_scanner->getCurrentToken() != Token::RBRACE) {
m_scanner->next();
// @todo
}
nodeFactory.markEndPosition();
expectToken(Token::RBRACE);
return nodeFactory.createNode<Block>();
} }
void Parser::expectToken(Token::Value _value) void Parser::expectToken(Token::Value _value)
@ -171,9 +261,16 @@ std::string Parser::expectIdentifier()
void Parser::throwExpectationError(const std::string& _description) void Parser::throwExpectationError(const std::string& _description)
{ {
(void) _description; int line, column;
std::tie(line, column) = m_scanner->translatePositionToLineColumn(getPosition());
cwarn << "Solidity parser error: " << _description
<< "at line " << (line + 1)
<< ", column " << (column + 1);
cwarn << m_scanner->getLineAtPosition(getPosition());
cwarn << std::string(column, ' ') << "^";
/// @todo make a proper exception hierarchy /// @todo make a proper exception hierarchy
throw std::exception();//_description); throw std::exception();
} }

View File

@ -32,7 +32,7 @@ class Scanner;
class Parser class Parser
{ {
public: public:
ptr<ASTNode> parse(Scanner& _scanner); ptr<ASTNode> parse(std::shared_ptr<Scanner> const& _scanner);
private: private:
class ASTNodeFactory; class ASTNodeFactory;
@ -48,6 +48,10 @@ private:
ptr<FunctionDefinition> parseFunctionDefinition(bool _isPublic); ptr<FunctionDefinition> parseFunctionDefinition(bool _isPublic);
ptr<StructDefinition> parseStructDefinition(); ptr<StructDefinition> parseStructDefinition();
ptr<VariableDeclaration> parseVariableDeclaration(); ptr<VariableDeclaration> parseVariableDeclaration();
ptr<TypeName> parseTypeName();
ptr<Mapping> parseMapping();
ptr<ParameterList> parseParameterList();
ptr<Block> parseBlock();
/// @} /// @}
/// Helper functions /// Helper functions
@ -58,7 +62,7 @@ private:
void throwExpectationError(const std::string& _description); void throwExpectationError(const std::string& _description);
/// @} /// @}
Scanner* m_scanner; std::shared_ptr<Scanner> m_scanner;
}; };
} } } }

View File

@ -40,6 +40,9 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. // along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
#include <algorithm>
#include <tuple>
#include <libsolidity/Scanner.h> #include <libsolidity/Scanner.h>
namespace dev { namespace dev {
@ -121,6 +124,7 @@ Token::Value Scanner::next()
return m_current_token.token; return m_current_token.token;
} }
bool Scanner::skipWhitespace() bool Scanner::skipWhitespace()
{ {
const int start_position = getSourcePos(); const int start_position = getSourcePos();
@ -182,7 +186,7 @@ void Scanner::scanToken()
Token::Value token; Token::Value token;
do { do {
// Remember the position of the next token // Remember the position of the next token
m_next_token.location.beg_pos = getSourcePos(); m_next_token.location.start = getSourcePos();
switch (m_char) { switch (m_char) {
case '\n': case '\n':
@ -401,7 +405,7 @@ void Scanner::scanToken()
// whitespace. // whitespace.
} while (token == Token::WHITESPACE); } while (token == Token::WHITESPACE);
m_next_token.location.end_pos = getSourcePos(); m_next_token.location.end = getSourcePos();
m_next_token.token = token; m_next_token.token = token;
} }
@ -546,7 +550,7 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \ #define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
KEYWORD_GROUP('a') \ KEYWORD_GROUP('a') \
KEYWORD("address", Token::BREAK) \ KEYWORD("address", Token::ADDRESS) \
KEYWORD_GROUP('b') \ KEYWORD_GROUP('b') \
KEYWORD("break", Token::BREAK) \ KEYWORD("break", Token::BREAK) \
KEYWORD("bool", Token::BOOL) \ KEYWORD("bool", Token::BOOL) \
@ -588,8 +592,8 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \ KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD_GROUP('l') \ KEYWORD_GROUP('l') \
KEYWORD_GROUP('m') \ KEYWORD_GROUP('m') \
KEYWORD_GROUP('n') \
KEYWORD("mapping", Token::MAPPING) \ KEYWORD("mapping", Token::MAPPING) \
KEYWORD_GROUP('n') \
KEYWORD("new", Token::NEW) \ KEYWORD("new", Token::NEW) \
KEYWORD("null", Token::NULL_LITERAL) \ KEYWORD("null", Token::NULL_LITERAL) \
KEYWORD_GROUP('p') \ KEYWORD_GROUP('p') \
@ -600,8 +604,9 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
KEYWORD_GROUP('r') \ KEYWORD_GROUP('r') \
KEYWORD("real", Token::REAL) \ KEYWORD("real", Token::REAL) \
KEYWORD("return", Token::RETURN) \ KEYWORD("return", Token::RETURN) \
KEYWORD("returns", Token::RETURNS) \
KEYWORD_GROUP('s') \ KEYWORD_GROUP('s') \
KEYWORD("string", Token::STRING_TYPE) \ KEYWORD("string", Token::STRING_TYPE) \
KEYWORD("struct", Token::STRUCT) \ KEYWORD("struct", Token::STRUCT) \
KEYWORD("switch", Token::SWITCH) \ KEYWORD("switch", Token::SWITCH) \
KEYWORD_GROUP('t') \ KEYWORD_GROUP('t') \
@ -671,5 +676,38 @@ Token::Value Scanner::scanIdentifierOrKeyword()
return KeywordOrIdentifierToken(m_next_token.literal); return KeywordOrIdentifierToken(m_next_token.literal);
} }
std::string CharStream::getLineAtPosition(int _position) const
{
// if _position points to \n, it returns the line before the \n
using size_type = std::string::size_type;
size_type searchStart = std::min<size_type>(m_source.size(), _position);
if (searchStart > 0) searchStart--;
size_type lineStart = m_source.rfind('\n', searchStart);
if (lineStart == std::string::npos)
lineStart = 0;
else
lineStart++;
return m_source.substr(lineStart,
std::min(m_source.find('\n', lineStart),
m_source.size()) - lineStart);
}
std::tuple<int, int> CharStream::translatePositionToLineColumn(int _position) const
{
using size_type = std::string::size_type;
size_type searchPosition = std::min<size_type>(m_source.size(), _position);
int lineNumber = std::count(m_source.begin(), m_source.begin() + searchPosition, '\n');
size_type lineStart;
if (searchPosition == 0) {
lineStart = 0;
} else {
lineStart = m_source.rfind('\n', searchPosition - 1);
lineStart = lineStart == std::string::npos ? 0 : lineStart + 1;
}
return std::tuple<int, int>(lineNumber, searchPosition - lineStart);
}
} } } }

View File

@ -82,6 +82,12 @@ public:
return get(); return get();
} }
/// Functions that help pretty-printing parse errors
/// Do only use in error cases, they are quite expensive.
/// @{
std::string getLineAtPosition(int _position) const;
std::tuple<int, int> translatePositionToLineColumn(int _position) const;
/// @}
private: private:
std::string m_source; std::string m_source;
size_t m_pos; size_t m_pos;
@ -134,6 +140,16 @@ public:
Location peekLocation() const { return m_next_token.location; } Location peekLocation() const { return m_next_token.location; }
const std::string& peekLiteral() const { return m_next_token.literal; } const std::string& peekLiteral() const { return m_next_token.literal; }
/// Functions that help pretty-printing parse errors.
/// Do only use in error cases, they are quite expensive.
/// @{
std::string getLineAtPosition(int _position) const { return m_source.getLineAtPosition(_position); }
std::tuple<int, int> translatePositionToLineColumn(int _position) const
{
return m_source.translatePositionToLineColumn(_position);
}
/// @}
// Returns true if there was a line terminator before the peek'ed token, // Returns true if there was a line terminator before the peek'ed token,
// possibly inside a multi-line comment. // possibly inside a multi-line comment.
bool hasAnyLineTerminatorBeforeNext() const { bool hasAnyLineTerminatorBeforeNext() const {

View File

@ -169,6 +169,7 @@ namespace solidity {
K(PUBLIC, "public", 0) \ K(PUBLIC, "public", 0) \
K(PRIVATE, "private", 0) \ K(PRIVATE, "private", 0) \
K(RETURN, "return", 0) \ K(RETURN, "return", 0) \
K(RETURNS, "returns", 0) \
K(STRUCT, "struct", 0) \ K(STRUCT, "struct", 0) \
K(SWITCH, "switch", 0) \ K(SWITCH, "switch", 0) \
K(THIS, "this", 0) \ K(THIS, "this", 0) \

View File

@ -1,18 +1,18 @@
ContractDefinition = 'contract' Identifier '{' ContractPart* '}' ContractDefinition = 'contract' Identifier '{' ContractPart* '}'
ContractPart = VariableDeclaration ';' | StructDefinition ';' | ContractPart = VariableDeclaration ';' | StructDefinition |
FunctionDefinition ';' | 'public:' | 'private:' FunctionDefinition | 'public:' | 'private:'
StructDefinition = 'struct' Identifier '{' StructDefinition = 'struct' Identifier '{'
( VariableDeclaration (';' VariableDeclaration)* )? '} ( VariableDeclaration (';' VariableDeclaration)* )? '}
FunctionDefinition = 'function' Identifier ArgumentList 'const'? FunctionDefinition = 'function' Identifier ParameterList 'const'?
'returns' ArgumentList Block ( 'returns' ParameterList )? Block
ArgumentList = '(' ( VariableDeclaration (',' VariableDeclaration)* )? ')' ParameterList = '(' ( VariableDeclaration (',' VariableDeclaration)* )? ')'
// semantic restriction: mappings and structs (recursively) containing mappings // semantic restriction: mappings and structs (recursively) containing mappings
// are not allowed in argument lists // are not allowed in argument lists
VariableDeclaration = TypeName Identifier VariableDeclaration = TypeName Identifier
TypeName = PredefinedType | Identifier | MappingType TypeName = ElementaryTypeName | Identifier | Mapping
MappingType = 'mapping' '(' SimplePredefinedType '=>' TypeName ')' Mapping = 'mapping' '(' ElementaryTypeName '=>' TypeName ')'
Block = '{' Statement* '}' Block = '{' Statement* '}'
Statement = IfStatement | WhileStatement | Continue | Break | Return | VariableAssignment | Expression ';' | Block Statement = IfStatement | WhileStatement | Continue | Break | Return | VariableAssignment | Expression ';' | Block