diff options
author | chriseth <c@ethdev.com> | 2016-01-25 04:43:48 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2016-01-25 04:43:48 +0800 |
commit | 194679f77ada30b04f483e96197e890e41a0c22c (patch) | |
tree | 82ed4cec81cb9dd81cbdc3b8134b80fb7e3de780 /libsolidity | |
parent | 67c855c583042ddee6261a9921239a3afd086c14 (diff) | |
parent | 51caa04238ce78420e6efc2ce15842effddf3856 (diff) | |
download | dexon-solidity-194679f77ada30b04f483e96197e890e41a0c22c.tar.gz dexon-solidity-194679f77ada30b04f483e96197e890e41a0c22c.tar.zst dexon-solidity-194679f77ada30b04f483e96197e890e41a0c22c.zip |
Merge pull request #326 from guanqun/cond-expr
support conditional expression _ ? _ : _
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 37 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.h | 1 | ||||
-rw-r--r-- | libsolidity/ast/AST.h | 27 | ||||
-rw-r--r-- | libsolidity/ast/ASTForward.h | 1 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.cpp | 11 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.h | 2 | ||||
-rw-r--r-- | libsolidity/ast/ASTPrinter.cpp | 13 | ||||
-rw-r--r-- | libsolidity/ast/ASTPrinter.h | 2 | ||||
-rw-r--r-- | libsolidity/ast/ASTVisitor.h | 4 | ||||
-rw-r--r-- | libsolidity/ast/AST_accept.h | 22 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 16 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.h | 1 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 25 |
13 files changed, 156 insertions, 6 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 69357043..0d74ddba 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -744,6 +744,43 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement) typeError(_statement.expression().location(), "Invalid integer constant."); } +bool TypeChecker::visit(Conditional const& _conditional) +{ + expectType(_conditional.condition(), BoolType()); + + _conditional.trueExpression().accept(*this); + _conditional.falseExpression().accept(*this); + + TypePointer trueType = type(_conditional.trueExpression())->mobileType(); + TypePointer falseType = type(_conditional.falseExpression())->mobileType(); + + TypePointer commonType = Type::commonType(trueType, falseType); + if (!commonType) + { + typeError( + _conditional.location(), + "True expression's type " + + trueType->toString() + + " doesn't match false expression's type " + + falseType->toString() + + "." + ); + // even we can't find a common type, we have to set a type here, + // otherwise the upper statement will not be able to check the type. + commonType = trueType; + } + + _conditional.annotation().type = commonType; + + if (_conditional.annotation().lValueRequested) + typeError( + _conditional.location(), + "Conditional expression as left value is not supported yet." + ); + + return false; +} + bool TypeChecker::visit(Assignment const& _assignment) { requireLValue(_assignment.leftHandSide()); diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index 7829a23d..b884db49 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -90,6 +90,7 @@ private: virtual void endVisit(Return const& _return) override; virtual bool visit(VariableDeclarationStatement const& _variable) override; virtual void endVisit(ExpressionStatement const& _statement) override; + virtual bool visit(Conditional const& _conditional) override; virtual bool visit(Assignment const& _assignment) override; virtual bool visit(TupleExpression const& _tuple) override; virtual void endVisit(BinaryOperation const& _operation) override; diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 4baf95d3..e1063467 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -1119,6 +1119,33 @@ public: ExpressionAnnotation& annotation() const override; }; +class Conditional: public Expression +{ +public: + Conditional( + SourceLocation const& _location, + ASTPointer<Expression> const& _condition, + ASTPointer<Expression> const& _trueExpression, + ASTPointer<Expression> const& _falseExpression + ): + Expression(_location), + m_condition(_condition), + m_trueExpression(_trueExpression), + m_falseExpression(_falseExpression) + {} + virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; + + Expression const& condition() const { return *m_condition; } + Expression const& trueExpression() const { return *m_trueExpression; } + Expression const& falseExpression() const { return *m_falseExpression; } + +private: + ASTPointer<Expression> m_condition; + ASTPointer<Expression> m_trueExpression; + ASTPointer<Expression> m_falseExpression; +}; + /// Assignment, can also be a compound assignment. /// Examples: (a = 7 + 8) or (a *= 2) class Assignment: public Expression diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h index 6aaa77ce..dad2b2e2 100644 --- a/libsolidity/ast/ASTForward.h +++ b/libsolidity/ast/ASTForward.h @@ -69,6 +69,7 @@ class Throw; class VariableDeclarationStatement; class ExpressionStatement; class Expression; +class Conditional; class Assignment; class TupleExpression; class UnaryOperation; diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 377fa7e6..df836afe 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -217,6 +217,12 @@ bool ASTJsonConverter::visit(ExpressionStatement const&) return true; } +bool ASTJsonConverter::visit(Conditional const&) +{ + addJsonNode("Conditional", {}, true); + return true; +} + bool ASTJsonConverter::visit(Assignment const& _node) { addJsonNode("Assignment", @@ -397,6 +403,11 @@ void ASTJsonConverter::endVisit(ExpressionStatement const&) goUp(); } +void ASTJsonConverter::endVisit(Conditional const&) +{ + goUp(); +} + void ASTJsonConverter::endVisit(Assignment const&) { goUp(); diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index de891cc6..b7fc84e9 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -67,6 +67,7 @@ public: bool visit(Throw const& _node) override; bool visit(VariableDeclarationStatement const& _node) override; bool visit(ExpressionStatement const& _node) override; + bool visit(Conditional const& _node) override; bool visit(Assignment const& _node) override; bool visit(TupleExpression const& _node) override; bool visit(UnaryOperation const& _node) override; @@ -99,6 +100,7 @@ public: void endVisit(Throw const&) override; void endVisit(VariableDeclarationStatement const&) override; void endVisit(ExpressionStatement const&) override; + void endVisit(Conditional const&) override; void endVisit(Assignment const&) override; void endVisit(TupleExpression const&) override; void endVisit(UnaryOperation const&) override; diff --git a/libsolidity/ast/ASTPrinter.cpp b/libsolidity/ast/ASTPrinter.cpp index d4f13e47..bc981f7d 100644 --- a/libsolidity/ast/ASTPrinter.cpp +++ b/libsolidity/ast/ASTPrinter.cpp @@ -248,6 +248,14 @@ bool ASTPrinter::visit(ExpressionStatement const& _node) return goDeeper(); } +bool ASTPrinter::visit(Conditional const& _node) +{ + writeLine("Conditional"); + printType(_node); + printSourcePart(_node); + return goDeeper(); +} + bool ASTPrinter::visit(Assignment const& _node) { writeLine(string("Assignment using operator ") + Token::toString(_node.assignmentOperator())); @@ -480,6 +488,11 @@ void ASTPrinter::endVisit(ExpressionStatement const&) m_indentation--; } +void ASTPrinter::endVisit(Conditional const&) +{ + m_indentation--; +} + void ASTPrinter::endVisit(Assignment const&) { m_indentation--; diff --git a/libsolidity/ast/ASTPrinter.h b/libsolidity/ast/ASTPrinter.h index d9b5e252..334fefc7 100644 --- a/libsolidity/ast/ASTPrinter.h +++ b/libsolidity/ast/ASTPrinter.h @@ -75,6 +75,7 @@ public: bool visit(Throw const& _node) override; bool visit(VariableDeclarationStatement const& _node) override; bool visit(ExpressionStatement const& _node) override; + bool visit(Conditional const& _node) override; bool visit(Assignment const& _node) override; bool visit(TupleExpression const& _node) override; bool visit(UnaryOperation const& _node) override; @@ -115,6 +116,7 @@ public: void endVisit(Throw const&) override; void endVisit(VariableDeclarationStatement const&) override; void endVisit(ExpressionStatement const&) override; + void endVisit(Conditional const&) override; void endVisit(Assignment const&) override; void endVisit(TupleExpression const&) override; void endVisit(UnaryOperation const&) override; diff --git a/libsolidity/ast/ASTVisitor.h b/libsolidity/ast/ASTVisitor.h index f04d9682..625f395d 100644 --- a/libsolidity/ast/ASTVisitor.h +++ b/libsolidity/ast/ASTVisitor.h @@ -73,6 +73,7 @@ public: virtual bool visit(Throw& _node) { return visitNode(_node); } virtual bool visit(VariableDeclarationStatement& _node) { return visitNode(_node); } virtual bool visit(ExpressionStatement& _node) { return visitNode(_node); } + virtual bool visit(Conditional& _node) { return visitNode(_node); } virtual bool visit(Assignment& _node) { return visitNode(_node); } virtual bool visit(TupleExpression& _node) { return visitNode(_node); } virtual bool visit(UnaryOperation& _node) { return visitNode(_node); } @@ -115,6 +116,7 @@ public: virtual void endVisit(Throw& _node) { endVisitNode(_node); } virtual void endVisit(VariableDeclarationStatement& _node) { endVisitNode(_node); } virtual void endVisit(ExpressionStatement& _node) { endVisitNode(_node); } + virtual void endVisit(Conditional& _node) { endVisitNode(_node); } virtual void endVisit(Assignment& _node) { endVisitNode(_node); } virtual void endVisit(TupleExpression& _node) { endVisitNode(_node); } virtual void endVisit(UnaryOperation& _node) { endVisitNode(_node); } @@ -169,6 +171,7 @@ public: virtual bool visit(Throw const& _node) { return visitNode(_node); } virtual bool visit(VariableDeclarationStatement const& _node) { return visitNode(_node); } virtual bool visit(ExpressionStatement const& _node) { return visitNode(_node); } + virtual bool visit(Conditional const& _node) { return visitNode(_node); } virtual bool visit(Assignment const& _node) { return visitNode(_node); } virtual bool visit(TupleExpression const& _node) { return visitNode(_node); } virtual bool visit(UnaryOperation const& _node) { return visitNode(_node); } @@ -211,6 +214,7 @@ public: virtual void endVisit(Throw const& _node) { endVisitNode(_node); } virtual void endVisit(VariableDeclarationStatement const& _node) { endVisitNode(_node); } virtual void endVisit(ExpressionStatement const& _node) { endVisitNode(_node); } + virtual void endVisit(Conditional const& _node) { endVisitNode(_node); } virtual void endVisit(Assignment const& _node) { endVisitNode(_node); } virtual void endVisit(TupleExpression const& _node) { endVisitNode(_node); } virtual void endVisit(UnaryOperation const& _node) { endVisitNode(_node); } diff --git a/libsolidity/ast/AST_accept.h b/libsolidity/ast/AST_accept.h index 61370c55..dee9d5b1 100644 --- a/libsolidity/ast/AST_accept.h +++ b/libsolidity/ast/AST_accept.h @@ -551,6 +551,28 @@ void VariableDeclarationStatement::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } +void Conditional::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + m_condition->accept(_visitor); + m_trueExpression->accept(_visitor); + m_falseExpression->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void Conditional::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + m_condition->accept(_visitor); + m_trueExpression->accept(_visitor); + m_falseExpression->accept(_visitor); + } + _visitor.endVisit(*this); +} + void Assignment::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 040217da..9536c727 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -176,6 +176,22 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction); } +bool ExpressionCompiler::visit(Conditional const& _condition) +{ + CompilerContext::LocationSetter locationSetter(m_context, _condition); + _condition.condition().accept(*this); + eth::AssemblyItem trueTag = m_context.appendConditionalJump(); + _condition.falseExpression().accept(*this); + utils().convertType(*_condition.falseExpression().annotation().type, *_condition.annotation().type); + eth::AssemblyItem endTag = m_context.appendJumpToNew(); + m_context << trueTag; + m_context.adjustStackOffset(-_condition.annotation().type->sizeOnStack()); + _condition.trueExpression().accept(*this); + utils().convertType(*_condition.trueExpression().annotation().type, *_condition.annotation().type); + m_context << endTag; + return false; +} + bool ExpressionCompiler::visit(Assignment const& _assignment) { CompilerContext::LocationSetter locationSetter(m_context, _assignment); diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h index 379aa65a..f00b24e8 100644 --- a/libsolidity/codegen/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -71,6 +71,7 @@ public: void appendConstStateVariableAccessor(const VariableDeclaration& _varDecl); private: + virtual bool visit(Conditional const& _condition) override; virtual bool visit(Assignment const& _assignment) override; virtual bool visit(TupleExpression const& _tuple) override; virtual bool visit(UnaryOperation const& _unaryOperation) override; diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 4ac3381c..d9ec1a49 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -932,13 +932,26 @@ ASTPointer<Expression> Parser::parseExpression( ) { ASTPointer<Expression> expression = parseBinaryExpression(4, _lookAheadIndexAccessStructure); - if (!Token::isAssignmentOp(m_scanner->currentToken())) + if (Token::isAssignmentOp(m_scanner->currentToken())) + { + Token::Value assignmentOperator = expectAssignmentOperator(); + ASTPointer<Expression> rightHandSide = parseExpression(); + ASTNodeFactory nodeFactory(*this, expression); + nodeFactory.setEndPositionFromNode(rightHandSide); + return nodeFactory.createNode<Assignment>(expression, assignmentOperator, rightHandSide); + } + else if (m_scanner->currentToken() == Token::Value::Conditional) + { + m_scanner->next(); + ASTPointer<Expression> trueExpression = parseExpression(); + expectToken(Token::Colon); + ASTPointer<Expression> falseExpression = parseExpression(); + ASTNodeFactory nodeFactory(*this, expression); + nodeFactory.setEndPositionFromNode(falseExpression); + return nodeFactory.createNode<Conditional>(expression, trueExpression, falseExpression); + } + else return expression; - Token::Value assignmentOperator = expectAssignmentOperator(); - ASTPointer<Expression> rightHandSide = parseExpression(); - ASTNodeFactory nodeFactory(*this, expression); - nodeFactory.setEndPositionFromNode(rightHandSide); - return nodeFactory.createNode<Assignment>(expression, assignmentOperator, rightHandSide); } ASTPointer<Expression> Parser::parseBinaryExpression( |