Browse Source

Initial implementation of Solidity parser finished, not yet tested much.

cl-refactor
Christian 10 years ago
parent
commit
f070d3bdea
  1. 110
      libsolidity/AST.h
  2. 233
      libsolidity/Parser.cpp
  3. 10
      libsolidity/Parser.h
  4. 13
      libsolidity/grammar.txt
  5. 78
      test/solidityParser.cpp

110
libsolidity/AST.h

@ -54,6 +54,8 @@ public:
: m_location(_location)
{}
virtual ~ASTNode() {}
Location getLocation() const { return m_location; }
private:
Location m_location;
@ -146,9 +148,7 @@ private:
class TypeName : public ASTNode
{
public:
explicit TypeName(Location const& _location)
: ASTNode(_location)
{}
explicit TypeName(Location const& _location) : ASTNode(_location) {}
};
/// any pre-defined type that is not a mapping
@ -192,15 +192,13 @@ private:
class Statement : public ASTNode
{
public:
explicit Statement(Location const& _location)
: ASTNode(_location)
{}
explicit Statement(Location const& _location) : ASTNode(_location) {}
};
class Block : public Statement
{
public:
explicit Block(Location const& _location, vecptr<Statement> const& _statements)
Block(Location const& _location, vecptr<Statement> const& _statements)
: Statement(_location), m_statements(_statements)
{}
private:
@ -209,7 +207,12 @@ private:
class IfStatement : public Statement
{
public:
IfStatement(Location const& _location, ptr<Expression> const& _condition,
ptr<Statement> const& _trueBody, ptr<Statement> const& _falseBody)
: Statement(_location), m_condition(_condition),
m_trueBody(_trueBody), m_falseBody(_falseBody)
{}
private:
ptr<Expression> m_condition;
ptr<Statement> m_trueBody;
@ -218,11 +221,17 @@ private:
class BreakableStatement : public Statement
{
public:
BreakableStatement(Location const& _location) : Statement(_location) {}
};
class WhileStatement : public BreakableStatement
{
public:
WhileStatement(Location const& _location, ptr<Expression> const& _condition,
ptr<Statement> const& _body)
: BreakableStatement(_location), m_condition(_condition), m_body(_body)
{}
private:
ptr<Expression> m_condition;
ptr<Statement> m_body;
@ -230,31 +239,42 @@ private:
class Continue : public Statement
{
public:
Continue(Location const& _location) : Statement(_location) {}
};
class Break : public Statement
{
public:
Break(Location const& _location) : Statement(_location) {}
};
class Return : public Statement
{
public:
Return(Location const& _location, ptr<Expression> _expression)
: Statement(_location), m_expression(_expression)
{}
private:
ptr<Expression> m_expression;
};
class VariableAssignment : public Statement
class VariableDefinition : public Statement
{
public:
VariableDefinition(Location const& _location, ptr<VariableDeclaration> _variable,
ptr<Expression> _value)
: Statement(_location), m_variable(_variable), m_value(_value)
{}
private:
ptr<VariableDeclaration> m_variable;
Token::Value m_assigmentOperator;
ptr<Expression> m_rightHandSide; ///< can be missing
ptr<Expression> m_value; ///< can be missing
};
class Expression : public Statement
{
private:
public:
Expression(Location const& _location) : Statement(_location) {}
};
/// @}
@ -264,6 +284,12 @@ private:
class Assignment : public Expression
{
public:
Assignment(Location const& _location, ptr<Expression> const& _leftHandSide,
Token::Value _assignmentOperator, ptr<Expression> const& _rightHandSide)
: Expression(_location), m_leftHandSide(_leftHandSide),
m_assigmentOperator(_assignmentOperator), m_rightHandSide(_rightHandSide)
{}
private:
ptr<Expression> m_leftHandSide;
Token::Value m_assigmentOperator;
@ -272,31 +298,52 @@ private:
class UnaryOperation : public Expression
{
public:
UnaryOperation(Location const& _location, Token::Value _operator,
ptr<Expression> const& _subExpression, bool _isPrefix)
: Expression(_location), m_operator(_operator),
m_subExpression(_subExpression), m_isPrefix(_isPrefix)
{}
private:
Token::Value m_operator;
ptr<Expression> m_subExpression;
bool isPrefix;
bool m_isPrefix;
};
class BinaryOperation : public Expression
{
public:
BinaryOperation(Location const& _location, ptr<Expression> const& _left,
Token::Value _operator, ptr<Expression> const& _right)
: Expression(_location), m_left(_left), m_operator(_operator), m_right(_right)
{}
private:
ptr<Expression> m_left;
ptr<Expression> m_right;
Token::Value m_operator;
ptr<Expression> m_right;
};
/// Can be ordinary function call, type cast or struct construction.
class FunctionCall : public Expression
{
public:
FunctionCall(Location const& _location, ptr<Expression> const& _expression,
vecptr<Expression> const& _arguments)
: Expression(_location), m_expression(_expression), m_arguments(_arguments)
{}
private:
// 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
ptr<Expression> m_expression;
vecptr<Expression> m_arguments;
};
class MemberAccess : public Expression
{
public:
MemberAccess(Location const& _location, ptr<Expression> _expression,
std::string const& _memberName)
: Expression(_location), m_expression(_expression), m_memberName(_memberName)
{}
private:
ptr<Expression> m_expression;
std::string m_memberName;
@ -304,23 +351,48 @@ private:
class IndexAccess : public Expression
{
public:
IndexAccess(Location const& _location, ptr<Expression> const& _base,
ptr<Expression> const& _index)
: Expression(_location), m_base(_base), m_index(_index)
{}
private:
ptr<Expression> m_base;
ptr<Expression> m_index;
};
class PrimaryExpression : public Expression
{
public:
PrimaryExpression(Location const& _location) : Expression(_location) {}
};
class Identifier : public PrimaryExpression
{
public:
Identifier(Location const& _location, std::string const& _name)
: PrimaryExpression(_location), m_name(_name) {}
private:
std::string m_name;
};
class ElementaryTypeNameExpression : public PrimaryExpression
{
public:
ElementaryTypeNameExpression(Location const& _location, Token::Value _type)
: PrimaryExpression(_location), m_type(_type) {}
private:
Token::Value m_type;
};
class Literal : public PrimaryExpression
{
public:
Literal(Location const& _location, Token::Value _token, std::string const& _value)
: PrimaryExpression(_location), m_token(_token), m_value(_value)
{}
private:
Token::Value m_token;
std::string m_value;
};

233
libsolidity/Parser.cpp

@ -231,12 +231,10 @@ ptr<ParameterList> Parser::parseParameterList()
ptr<Block> Parser::parseBlock()
{
ASTNodeFactory nodeFactory(*this);
expectToken(Token::LBRACE);
vecptr<Statement> statements;
while (m_scanner->getCurrentToken() != Token::RBRACE) {
m_scanner->next();
statements.push_back(parseStatement());
}
nodeFactory.markEndPosition();
@ -246,6 +244,7 @@ ptr<Block> Parser::parseBlock()
ptr<Statement> Parser::parseStatement()
{
ptr<Statement> statement;
switch (m_scanner->getCurrentToken()) {
case Token::IF:
@ -254,10 +253,227 @@ ptr<Statement> Parser::parseStatement()
return parseWhileStatement();
case Token::LBRACE:
return parseBlock();
// starting from here, all statements must be terminated by a semicolon
case Token::CONTINUE: // all following
return
case Token::CONTINUE:
statement = ASTNodeFactory(*this).createNode<Continue>();
break;
case Token::BREAK:
statement = ASTNodeFactory(*this).createNode<Break>();
break;
case Token::RETURN:
{
ASTNodeFactory nodeFactory(*this);
ptr<Expression> expression;
if (m_scanner->next() != Token::SEMICOLON) {
expression = parseExpression();
nodeFactory.setEndPositionFromNode(expression);
}
statement = nodeFactory.createNode<Return>(expression);
}
break;
default:
// distinguish between variable definition (and potentially assignment) and expressions
// (which include assignments to other expressions and pre-declared variables)
// We have a variable definition if we ge a keyword that specifies a type name, or
// in the case of a user-defined type, we have two identifiers following each other.
if (m_scanner->getCurrentToken() == Token::MAPPING ||
m_scanner->getCurrentToken() == Token::VAR ||
Token::IsElementaryTypeName(m_scanner->getCurrentToken()) ||
(m_scanner->getCurrentToken() == Token::IDENTIFIER &&
m_scanner->peek() == Token::IDENTIFIER)) {
statement = parseVariableDefinition();
} else {
// "ordinary" expression
statement = parseExpression();
}
}
expectToken(Token::SEMICOLON);
return statement;
}
ptr<IfStatement> Parser::parseIfStatement()
{
ASTNodeFactory nodeFactory(*this);
expectToken(Token::IF);
expectToken(Token::LPAREN);
ptr<Expression> condition = parseExpression();
expectToken(Token::RPAREN);
ptr<Statement> trueBody = parseStatement();
ptr<Statement> falseBody;
if (m_scanner->getCurrentToken() == Token::ELSE) {
m_scanner->next();
falseBody = parseStatement();
nodeFactory.setEndPositionFromNode(falseBody);
} else {
nodeFactory.setEndPositionFromNode(trueBody);
}
return nodeFactory.createNode<IfStatement>(condition, trueBody, falseBody);
}
ptr<WhileStatement> Parser::parseWhileStatement()
{
ASTNodeFactory nodeFactory(*this);
expectToken(Token::WHILE);
expectToken(Token::LPAREN);
ptr<Expression> condition = parseExpression();
expectToken(Token::RPAREN);
ptr<Statement> body = parseStatement();
nodeFactory.setEndPositionFromNode(body);
return nodeFactory.createNode<WhileStatement>(condition, body);
}
ptr<VariableDefinition> Parser::parseVariableDefinition()
{
ASTNodeFactory nodeFactory(*this);
ptr<VariableDeclaration> variable = parseVariableDeclaration();
ptr<Expression> value;
if (m_scanner->getCurrentToken() == Token::ASSIGN) {
m_scanner->next();
value = parseExpression();
nodeFactory.setEndPositionFromNode(value);
} else {
nodeFactory.setEndPositionFromNode(variable);
}
return nodeFactory.createNode<VariableDefinition>(variable, value);
}
ptr<Expression> Parser::parseExpression()
{
ASTNodeFactory nodeFactory(*this);
ptr<Expression> expression = parseBinaryExpression();
if (!Token::IsAssignmentOp(m_scanner->getCurrentToken()))
return expression;
Token::Value assignmentOperator = expectAssignmentOperator();
ptr<Expression> rightHandSide = parseExpression();
nodeFactory.setEndPositionFromNode(rightHandSide);
return nodeFactory.createNode<Assignment>(expression, assignmentOperator, rightHandSide);
}
ptr<Expression> Parser::parseBinaryExpression(int _minPrecedence)
{
ASTNodeFactory nodeFactory(*this);
ptr<Expression> expression = parseUnaryExpression();
int precedence = Token::Precedence(m_scanner->getCurrentToken());
for (; precedence >= _minPrecedence; --precedence) {
while (Token::Precedence(m_scanner->getCurrentToken()) == precedence) {
Token::Value op = m_scanner->getCurrentToken();
m_scanner->next();
ptr<Expression> right = parseBinaryExpression(precedence + 1);
nodeFactory.setEndPositionFromNode(right);
expression = nodeFactory.createNode<BinaryOperation>(expression, op, right);
}
}
return expression;
}
ptr<Expression> Parser::parseUnaryExpression()
{
ASTNodeFactory nodeFactory(*this);
Token::Value token = m_scanner->getCurrentToken();
if (Token::IsUnaryOp(token) || Token::IsCountOp(token)) {
// prefix expression
m_scanner->next();
ptr<Expression> subExpression = parseUnaryExpression();
nodeFactory.setEndPositionFromNode(subExpression);
return nodeFactory.createNode<UnaryOperation>(token, subExpression, true);
} else {
// potential postfix expression
ptr<Expression> subExpression = parseLeftHandSideExpression();
token = m_scanner->getCurrentToken();
if (!Token::IsCountOp(token))
return subExpression;
nodeFactory.markEndPosition();
m_scanner->next();
return nodeFactory.createNode<UnaryOperation>(token, subExpression, false);
}
}
ptr<Expression> Parser::parseLeftHandSideExpression()
{
ASTNodeFactory nodeFactory(*this);
ptr<Expression> expression = parsePrimaryExpression();
while (true) {
switch (m_scanner->getCurrentToken()) {
case Token::LBRACK:
{
m_scanner->next();
ptr<Expression> index = parseExpression();
nodeFactory.markEndPosition();
expectToken(Token::RBRACK);
expression = nodeFactory.createNode<IndexAccess>(expression, index);
}
break;
case Token::PERIOD:
{
m_scanner->next();
nodeFactory.markEndPosition();
std::string memberName = expectIdentifier();
expression = nodeFactory.createNode<MemberAccess>(expression, memberName);
}
break;
case Token::LPAREN:
{
m_scanner->next();
vecptr<Expression> arguments = parseFunctionCallArguments();
nodeFactory.markEndPosition();
expectToken(Token::RPAREN);
expression = nodeFactory.createNode<FunctionCall>(expression, arguments);
}
break;
default:
return expression;
}
}
}
ptr<Expression> Parser::parsePrimaryExpression()
{
Token::Value token = m_scanner->getCurrentToken();
switch (token) {
case Token::TRUE_LITERAL:
case Token::FALSE_LITERAL:
m_scanner->next();
return ASTNodeFactory(*this).createNode<Literal>(token, std::string());
case Token::NUMBER:
case Token::STRING_LITERAL:
m_scanner->next();
return ASTNodeFactory(*this).createNode<Literal>(token, m_scanner->getCurrentLiteral());
case Token::IDENTIFIER:
m_scanner->next();
return ASTNodeFactory(*this).createNode<Identifier>(m_scanner->getCurrentLiteral());
case Token::LPAREN:
{
m_scanner->next();
ptr<Expression> expression = parseExpression();
expectToken(Token::RPAREN);
return expression;
}
default:
if (Token::IsElementaryTypeName(token)) {
// used for casts
m_scanner->next();
return ASTNodeFactory(*this).createNode<ElementaryTypeNameExpression>(token);
} else {
throwExpectationError("Expected primary expression.");
return ptr<Expression>(); // this is not reached
}
}
}
vecptr<Expression> Parser::parseFunctionCallArguments()
{
vecptr<Expression> arguments;
if (m_scanner->getCurrentToken() != Token::RPAREN) {
arguments.push_back(parseExpression());
while (m_scanner->getCurrentToken() != Token::RPAREN) {
expectToken(Token::COMMA);
arguments.push_back(parseExpression());
}
}
return arguments;
}
void Parser::expectToken(Token::Value _value)
@ -267,6 +483,15 @@ void Parser::expectToken(Token::Value _value)
m_scanner->next();
}
Token::Value Parser::expectAssignmentOperator()
{
Token::Value op = m_scanner->getCurrentToken();
if (!Token::IsAssignmentOp(op))
throwExpectationError(std::string("Expected assignment operator"));
m_scanner->next();
return op;
}
std::string Parser::expectIdentifier()
{
if (m_scanner->getCurrentToken() != Token::IDENTIFIER)

10
libsolidity/Parser.h

@ -53,12 +53,22 @@ private:
ptr<ParameterList> parseParameterList();
ptr<Block> parseBlock();
ptr<Statement> parseStatement();
ptr<IfStatement> parseIfStatement();
ptr<WhileStatement> parseWhileStatement();
ptr<VariableDefinition> parseVariableDefinition();
ptr<Expression> parseExpression();
ptr<Expression> parseBinaryExpression(int _minPrecedence = 4);
ptr<Expression> parseUnaryExpression();
ptr<Expression> parseLeftHandSideExpression();
ptr<Expression> parsePrimaryExpression();
vecptr<Expression> parseFunctionCallArguments();
/// @}
/// Helper functions
/// @{
/// If current token value is not _value, throw exception otherwise advance token.
void expectToken(Token::Value _value);
Token::Value expectAssignmentOperator();
std::string expectIdentifier();
void throwExpectationError(const std::string& _description);
/// @}

13
libsolidity/grammar.txt

@ -15,18 +15,21 @@ TypeName = ElementaryTypeName | Identifier | Mapping
Mapping = 'mapping' '(' ElementaryTypeName '=>' TypeName ')'
Block = '{' Statement* '}'
Statement = IfStatement | WhileStatement | Continue | Break | Return | VariableAssignment | Expression ';' | Block
Statement = IfStatement | WhileStatement | Block |
( Continue | Break | Return | VariableDefinition | Expression ) ';'
IfStatement = 'if' '(' Expression ')' Statement ( 'else' Statement )?
WhileStatement = 'while' '(' Expression ')' Statement
Continue = 'continue' ';'
Break = 'break' ';'
Return = 'return' Expression? ';'
VariableAssignment = VariableDeclaration ( AssignmentOp Expression )? ';'
VariableDefinition = VariableDeclaration ( = Expression )? ';'
Expression = Assignment | UnaryOperation | BinaryOperation | FunctionCall | IndexAccess | MemberAccess | PrimaryExpression
Expression = Assignment | UnaryOperation | BinaryOperation | FunctionCall | IndexAccess |
MemberAccess | PrimaryExpression
// The expression syntax is actually much more complicated
Assignment = Expression (AssignmentOp Expression)
FunctionCall = Identifier '(' ( Expression ( ',' Expression )* ) ')'
FunctionCall = Expression '(' ( Expression ( ',' Expression )* ) ')'
MemberAccess = Expression '.' Identifier
IndexAccess = Expression '[' Expresison ']'
PrimaryExpression = Identifier | NumberLiteral | StringLiteral | '(' Expression ')'
PrimaryExpression = Identifier | NumberLiteral | StringLiteral | ElementaryTypeName | '(' Expression ')'

78
test/solidityParser.cpp

@ -130,6 +130,84 @@ BOOST_AUTO_TEST_CASE(mapping_to_mapping_in_struct)
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(variable_definition)
{
char const* text = "contract test {\n"
" function fun(uint256 a) {\n"
" var b;\n"
" uint256 c;\n"
" mapping(address=>hash) d;\n"
" customtype varname;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(variable_definition_with_initialization)
{
char const* text = "contract test {\n"
" function fun(uint256 a) {\n"
" var b = 2;\n"
" uint256 c = 0x87;\n"
" mapping(address=>hash) d;\n"
" string name = \"Solidity\";"
" customtype varname;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(operator_expression)
{
char const* text = "contract test {\n"
" function fun(uint256 a) {\n"
" uint256 x = (1 + 4) || false && (1 - 12) + -9;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(complex_expression)
{
char const* text = "contract test {\n"
" function fun(uint256 a) {\n"
" uint256 x = (1 + 4).member(++67)[a/=9] || true;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(while_loop)
{
char const* text = "contract test {\n"
" function fun(uint256 a) {\n"
" uint256 x = (1 + 4).member(++67) || true;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(if_statement)
{
char const* text = "contract test {\n"
" function fun(uint256 a) {\n"
" if (a >= 8) return 2; else { var b = 7; }\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(else_if_statement)
{
char const* text = "contract test {\n"
" function fun(uint256 a) returns (address b) {\n"
" if (a < 0) b = 0x67; else if (a == 0) b = 0x12; else b = 0x78;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_SUITE_END()

Loading…
Cancel
Save