From a23dc75ec4c5a99efe026551bfa31a061a506bfc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= <tseeker@nocternity.net>
Date: Mon, 6 Nov 2017 17:09:05 +0100
Subject: [PATCH] Parser - Conditionals

Structure for conditionals + support for the if instruction
---
 opast.cc | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 opast.hh | 71 ++++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 131 insertions(+), 16 deletions(-)

diff --git a/opast.cc b/opast.cc
index 720b3fe..92a388a 100644
--- a/opast.cc
+++ b/opast.cc
@@ -366,13 +366,22 @@ struct T_ParserImpl_
 	void parseFunctionArguments(
 			T_FuncNode& function ,
 			T_SRDToken const& argsToken ) noexcept;
+
+	// ---------------------------------------------------------------------
+
 	void parseInstructions(
 			T_InstrListNode& instructions ,
 			T_SRDList const& input ,
 			uint32_t start ) noexcept;
+	P_InstrListNode parseBlock(
+			A_Node& parent ,
+			T_SRDToken const& block ) noexcept;
 
 	// ---------------------------------------------------------------------
 
+	void parseIfInstruction(
+			T_InstrListNode& instructions ,
+			T_SRDList const& input ) noexcept;
 	void parsePipelineInstruction(
 			T_InstrListNode& instructions ,
 			T_SRDList const& input ) noexcept;
@@ -388,17 +397,17 @@ struct T_ParserImpl_
 
 	// ---------------------------------------------------------------------
 
-	T_OwnPtr< A_ExpressionNode > parseExpression(
+	P_ExpressionNode parseExpression(
 			A_Node& parent ,
 			T_SRDToken const& token ) noexcept;
-	T_OwnPtr< A_ExpressionNode > parseOperation(
+	P_ExpressionNode parseOperation(
 			A_Node& parent ,
 			T_SRDList const& opList ) noexcept;
-	T_OwnPtr< A_ExpressionNode > parseBinOp(
+	P_ExpressionNode parseBinOp(
 			A_Node& parent ,
 			T_SRDList const& opList ,
 			T_BinaryOperatorNode::E_Operator op ) noexcept;
-	T_OwnPtr< A_ExpressionNode > parseUnaryOp(
+	P_ExpressionNode parseUnaryOp(
 			A_Node& parent ,
 			T_SRDList const& opList ,
 			T_UnaryOperatorNode::E_Operator op ) noexcept;
@@ -490,6 +499,8 @@ void T_ParserImpl_::parseFunctionArguments(
 	}
 }
 
+/*----------------------------------------------------------------------------*/
+
 void T_ParserImpl_::parseInstructions(
 		T_InstrListNode& instructions ,
 		T_SRDList const& input ,
@@ -521,6 +532,9 @@ void T_ParserImpl_::parseInstructions(
 		}
 
 		switch ( *instrMap.get( iword ) ) {
+			case E_InstrType::IF:
+				parseIfInstruction( instructions , ilist );
+				break;
 			case E_InstrType::PIPELINE:
 				parsePipelineInstruction( instructions , ilist );
 				break;
@@ -537,6 +551,52 @@ void T_ParserImpl_::parseInstructions(
 	}
 }
 
+P_InstrListNode T_ParserImpl_::parseBlock(
+		A_Node& parent ,
+		T_SRDToken const& block ) noexcept
+{
+	if ( block.type( ) != E_SRDTokenType::LIST ) {
+		errors.addNew( "block expected" , block.location( ) );
+		return {};
+	}
+
+	P_InstrListNode rv{ NewOwned< T_InstrListNode >( parent ) };
+	rv->location( ) = block.location( );
+	parseInstructions( *rv , block.list( ) , 0 );
+	return rv;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void T_ParserImpl_::parseIfInstruction(
+		T_InstrListNode& instructions ,
+		T_SRDList const& input ) noexcept
+{
+	if ( input.size( ) == 1 ) {
+		errors.addNew( "expression and 'then' block expected" ,
+				input[ 0 ].location( ) );
+		return;
+	}
+
+	T_CondInstrNode& cond{ instructions.add< T_CondInstrNode >( ) };
+	cond.location( ) = input[ 0 ].location( );
+	cond.setExpression( parseExpression( cond , input[ 1 ] ) );
+
+	if ( input.size( ) == 2 ) {
+		errors.addNew( "'then' block expected" ,
+				input[ 0 ].location( ) );
+		return;
+	}
+
+	cond.setCase( 1 , parseBlock( cond , input[ 2 ] ) );
+	if ( input.size( ) > 3 ) {
+		cond.setDefaultCase( parseBlock( cond , input[ 3 ] ) );
+		if ( input.size( ) > 4 ) {
+			errors.addNew( "too many arguments" , input[ 4 ].location( ) );
+		}
+	}
+}
+
 /*----------------------------------------------------------------------------*/
 
 void T_ParserImpl_::parsePipelineInstruction(
@@ -681,7 +741,7 @@ void T_ParserImpl_::parseSetInstruction(
 
 /*----------------------------------------------------------------------------*/
 
-T_OwnPtr< A_ExpressionNode > T_ParserImpl_::parseExpression(
+P_ExpressionNode T_ParserImpl_::parseExpression(
 		A_Node& parent ,
 		T_SRDToken const& token ) noexcept
 {
@@ -700,7 +760,7 @@ T_OwnPtr< A_ExpressionNode > T_ParserImpl_::parseExpression(
 	return {};
 }
 
-T_OwnPtr< A_ExpressionNode > T_ParserImpl_::parseOperation(
+P_ExpressionNode T_ParserImpl_::parseOperation(
 		A_Node& parent ,
 		T_SRDList const& opList ) noexcept
 {
@@ -723,7 +783,7 @@ T_OwnPtr< A_ExpressionNode > T_ParserImpl_::parseOperation(
 	return {};
 }
 
-T_OwnPtr< A_ExpressionNode > T_ParserImpl_::parseBinOp(
+P_ExpressionNode T_ParserImpl_::parseBinOp(
 		A_Node& parent ,
 		T_SRDList const& opList ,
 		T_BinaryOperatorNode::E_Operator op ) noexcept
@@ -754,7 +814,7 @@ T_OwnPtr< A_ExpressionNode > T_ParserImpl_::parseBinOp(
 	return opNode;
 }
 
-T_OwnPtr< A_ExpressionNode > T_ParserImpl_::parseUnaryOp(
+P_ExpressionNode T_ParserImpl_::parseUnaryOp(
 		A_Node& parent ,
 		T_SRDList const& opList ,
 		T_UnaryOperatorNode::E_Operator op ) noexcept
diff --git a/opast.hh b/opast.hh
index f84a43d..59002a3 100644
--- a/opast.hh
+++ b/opast.hh
@@ -23,6 +23,7 @@ class A_Node
 		DECL_FRAME ,	// Frame block
 		DECL_FN ,	// Function
 		//
+		OP_COND ,	// Conditional instruction
 		OP_PIPELINE ,	// Shader pipeline declaration
 		OP_PROFILE ,	// Profiling block
 		OP_PROGRAM ,	// Shader program declaration
@@ -137,6 +138,7 @@ class A_FuncNode : public A_Node
 	T_InstrListNode const& instructions( ) const noexcept
 		{ return instructions_; }
 };
+using P_InstrListNode = T_OwnPtr< T_InstrListNode >;
 
 // Root node, keeps track of the whole tree and related data (function table,
 // assets...)
@@ -225,9 +227,62 @@ class A_ExpressionNode : public A_Node
 		: A_Node( type , &parent )
 	{ }
 };
+using P_ExpressionNode = T_OwnPtr< A_ExpressionNode >;
 
 /*============================================================================*/
 
+// Conditional instruction
+class T_CondInstrNode : public A_InstructionNode
+{
+    private:
+	P_ExpressionNode expression_;
+	T_KeyValueTable< int64_t , P_InstrListNode > cases_;
+	P_InstrListNode defaultCase_;
+
+    public:
+	explicit T_CondInstrNode( T_InstrListNode& parent ) noexcept
+		: A_InstructionNode( OP_COND , parent )
+	{ }
+
+	void setExpression( P_ExpressionNode expression ) noexcept
+		{ expression_ = std::move( expression ); }
+	bool hasExpression( ) const noexcept
+		{ return bool( expression_ ); }
+	A_ExpressionNode& expression( ) noexcept
+		{ return *expression_; }
+	A_ExpressionNode const& expression( ) const noexcept
+		{ return *expression_; }
+
+	void setCase( const int64_t value ,
+			P_InstrListNode instrList ) noexcept
+	{
+		if ( instrList ) {
+			cases_.set( value , std::move( instrList ) );
+		}
+	}
+
+	void rmCase( const int64_t value ) noexcept
+		{ cases_.remove( value ); }
+
+	T_Array< int64_t > const& cases( ) const noexcept
+		{ return cases_.keys( ); }
+	bool hasCase( const int64_t value ) const noexcept
+		{ return cases_.contains( value ); }
+	T_InstrListNode& getCase( const int64_t value ) noexcept
+		{ return **cases_.get( value ); }
+	T_InstrListNode const& getCase( const int64_t value ) const noexcept
+		{ return **cases_.get( value ); }
+
+	void setDefaultCase( P_InstrListNode defaultCase ) noexcept
+		{ defaultCase_ = std::move( defaultCase ); }
+	bool hasDefaultCase( ) const noexcept
+		{ return bool( defaultCase_ ); }
+	T_InstrListNode& defaultCase( ) noexcept
+		{ return *defaultCase_; }
+	T_InstrListNode const& defaultCase( ) const noexcept
+		{ return *defaultCase_; }
+};
+
 // Pipeline declaration instruction
 class T_PipelineInstrNode : public A_InstructionNode
 {
@@ -303,7 +358,7 @@ class T_SetInstrNode : public A_InstructionNode
     private:
 	T_String id_;
 	T_SRDLocation idLocation_;
-	T_OwnPtr< A_ExpressionNode > expression_;
+	P_ExpressionNode expression_;
 
     public:
 	T_SetInstrNode( T_InstrListNode& parent ,
@@ -314,7 +369,7 @@ class T_SetInstrNode : public A_InstructionNode
 	T_SRDLocation const& idLocation( ) const noexcept
 		{ return idLocation_; }
 
-	void setExpression( T_OwnPtr< A_ExpressionNode > expression ) noexcept
+	void setExpression( P_ExpressionNode expression ) noexcept
 		{ expression_ = std::move( expression ); }
 
 	bool hasExpression( ) const noexcept
@@ -380,7 +435,7 @@ class T_UnaryOperatorNode : public A_ExpressionNode
 
     private:
 	E_Operator op_;
-	T_OwnPtr< A_ExpressionNode > argument_;
+	P_ExpressionNode argument_;
 
     public:
 	T_UnaryOperatorNode(
@@ -390,7 +445,7 @@ class T_UnaryOperatorNode : public A_ExpressionNode
 	E_Operator op( ) const noexcept
 		{ return op_; }
 
-	void setArgument( T_OwnPtr< A_ExpressionNode > argument ) noexcept
+	void setArgument( P_ExpressionNode argument ) noexcept
 		{ argument_ = std::move( argument ); }
 
 	bool hasArgument( ) const noexcept
@@ -418,8 +473,8 @@ class T_BinaryOperatorNode : public A_ExpressionNode
 
     private:
 	E_Operator op_;
-	T_OwnPtr< A_ExpressionNode > left_;
-	T_OwnPtr< A_ExpressionNode > right_;
+	P_ExpressionNode left_;
+	P_ExpressionNode right_;
 
     public:
 	T_BinaryOperatorNode(
@@ -429,9 +484,9 @@ class T_BinaryOperatorNode : public A_ExpressionNode
 	E_Operator op( ) const noexcept
 		{ return op_; }
 
-	void setLeft( T_OwnPtr< A_ExpressionNode > left ) noexcept
+	void setLeft( P_ExpressionNode left ) noexcept
 		{ left_ = std::move( left ); }
-	void setRight( T_OwnPtr< A_ExpressionNode > right ) noexcept
+	void setRight( P_ExpressionNode right ) noexcept
 		{ right_ = std::move( right ); }
 
 	bool hasLeft( ) const noexcept