From 31f307cc6ba42d16a1d4c137a1db4f849f113759 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Tue, 5 Sep 2017 15:28:05 +0200
Subject: [PATCH] cli syntax for set construction

---
 alib2cli/src/ast/Option.h                     |  2 +
 alib2cli/src/ast/options/CategoryOption.h     |  4 ++
 alib2cli/src/ast/options/HL3Option.h          |  4 ++
 alib2cli/src/ast/options/TypeOption.h         | 27 +++++++++
 .../src/ast/statements/ContainerStatement.cpp | 57 +++++++++++++++++++
 .../src/ast/statements/ContainerStatement.h   | 28 +++++++++
 alib2cli/src/lexer/Lexer.cpp                  | 20 +++++++
 alib2cli/src/lexer/Lexer.h                    | 12 ++++
 alib2cli/src/parser/Parser.cpp                | 34 +++++++++++
 alib2cli/src/parser/Parser.h                  |  1 +
 alib2cli/test-src/cli/CliTest.cpp             | 22 +++++++
 alib2cli/test-src/cli/CliTest.h               |  2 +
 12 files changed, 213 insertions(+)
 create mode 100644 alib2cli/src/ast/options/TypeOption.h
 create mode 100644 alib2cli/src/ast/statements/ContainerStatement.cpp
 create mode 100644 alib2cli/src/ast/statements/ContainerStatement.h

diff --git a/alib2cli/src/ast/Option.h b/alib2cli/src/ast/Option.h
index 2c9c896b2a..d36660d3fc 100644
--- a/alib2cli/src/ast/Option.h
+++ b/alib2cli/src/ast/Option.h
@@ -3,6 +3,7 @@
 
 #include <ast/Ast.h>
 #include <ast/statements/SingleStatement.h>
+#include <ast/statements/ContainerStatement.h>
 
 namespace cli {
 
@@ -12,6 +13,7 @@ public:
 	}
 
 	virtual void eval ( SingleStatement & statement ) const = 0;
+	virtual void eval ( ContainerStatement & statement ) const = 0;
 };
 
 } /* namespace cli */
diff --git a/alib2cli/src/ast/options/CategoryOption.h b/alib2cli/src/ast/options/CategoryOption.h
index 594a587d6f..ed34c1752e 100644
--- a/alib2cli/src/ast/options/CategoryOption.h
+++ b/alib2cli/src/ast/options/CategoryOption.h
@@ -17,6 +17,10 @@ public:
 	virtual void eval ( SingleStatement & statement ) const override {
 		statement.setCategory ( abstraction::AlgorithmCategories::algorithmCategory ( m_key ) );
 	}
+
+	virtual void eval ( ContainerStatement & ) const override {
+		throw exception::CommonException ( "ContainerStatement cannot be categorized." );
+	}
 };
 
 } /* namespace cli */
diff --git a/alib2cli/src/ast/options/HL3Option.h b/alib2cli/src/ast/options/HL3Option.h
index 1a362e520f..8cb9935995 100644
--- a/alib2cli/src/ast/options/HL3Option.h
+++ b/alib2cli/src/ast/options/HL3Option.h
@@ -10,6 +10,10 @@ public:
 	virtual void eval ( SingleStatement & ) const override {
 		std::cout << "The cake is a lie, as well as the release date of HL3. GLaDOS told me." << std::endl;
 	}
+
+	virtual void eval ( ContainerStatement & ) const override {
+		std::cout << "The cake is a lie, as well as the release date of HL3. GLaDOS told me." << std::endl;
+	}
 };
 
 } /* namespace cli */
diff --git a/alib2cli/src/ast/options/TypeOption.h b/alib2cli/src/ast/options/TypeOption.h
new file mode 100644
index 0000000000..6b0835528d
--- /dev/null
+++ b/alib2cli/src/ast/options/TypeOption.h
@@ -0,0 +1,27 @@
+#ifndef _CLI_VALUE_OPTION_H_
+#define _CLI_VALUE_OPTION_H_
+
+#include <ast/Option.h>
+#include <exception/CommonException.h>
+
+namespace cli {
+
+class TypeOption final : public Option {
+	std::string m_type;
+
+public:
+	TypeOption ( std::string type ) : m_type ( std::move ( type ) ) {
+	}
+
+	virtual void eval ( SingleStatement & ) const override {
+		throw exception::CommonException ( "Single statement cannot be parametrized with type." );
+	}
+
+	virtual void eval ( ContainerStatement & statement ) const override {
+		statement.setType ( m_type );
+	}
+};
+
+} /* namespace cli */
+
+#endif /* _CLI_VALUE_OPTION_H_ */
diff --git a/alib2cli/src/ast/statements/ContainerStatement.cpp b/alib2cli/src/ast/statements/ContainerStatement.cpp
new file mode 100644
index 0000000000..4b14caf0d0
--- /dev/null
+++ b/alib2cli/src/ast/statements/ContainerStatement.cpp
@@ -0,0 +1,57 @@
+#include <ast/statements/ContainerStatement.h>
+#include <ast/Option.h>
+#include <ast/Param.h>
+#include <ast/Arg.h>
+#include <abstraction/common/CastHelper.h>
+
+namespace cli {
+
+ContainerStatement::ContainerStatement ( std::string container, ext::vector < std::unique_ptr < Param > > params, ext::vector < std::unique_ptr < Option > > options ) : m_container ( std::move ( container ) ), m_params ( std::move ( params ) ), m_options ( std::move ( options ) ) {
+	for ( const std::unique_ptr < Option > & option : m_options ) {
+		option->eval ( * this );
+	}
+}
+
+std::shared_ptr < abstraction::OperationAbstraction > ContainerStatement::translateAndEval ( const std::shared_ptr < abstraction::OperationAbstraction > & prev, Environment & environment ) const {
+	ext::vector < std::shared_ptr < abstraction::OperationAbstraction > > params;
+	for ( const std::unique_ptr < Param > & param : m_params ) {
+		params.push_back ( param->translateAndEval ( prev, environment ) );
+	}
+
+	std::vector < bool > moves;
+	for ( const std::unique_ptr < Param > & param : m_params ) {
+		moves.push_back ( param->getMove ( ) );
+	}
+
+	std::shared_ptr < abstraction::OperationAbstraction > algo = abstraction::Registry::getContainerAbstraction ( m_container, m_type );
+
+	unsigned i = 0;
+	ext::vector < std::shared_ptr < abstraction::OperationAbstraction > > casted_params;
+	for ( const std::shared_ptr < abstraction::OperationAbstraction > & param : params ) {
+		if ( abstraction::Registry::isCastNoOp ( algo->getParamType ( i ), param->getReturnType ( ) ) ) {
+			casted_params.push_back ( param );
+		} else {
+			casted_params.push_back ( abstraction::CastHelper::eval ( param, algo->getParamType ( i ), moves [ i ] ) );
+			moves [ i ] = true;
+		}
+		++ i;
+	}
+
+	i = 0;
+	for ( const std::shared_ptr < abstraction::OperationAbstraction > & param : casted_params ) {
+		if ( ! algo->attachInput ( param, i, moves [ i ] ) )
+			throw exception::CommonException ( "Can't connect param at " + ext::to_string ( i ) + " of algorithm " + m_container + " with result of type " + param->getReturnType ( ) + "." );
+		++ i;
+	}
+
+	if ( ! algo->eval ( ) )
+		throw exception::CommonException ( "Eval of algorithm " + m_container + " failed." );
+
+	return algo;
+}
+
+void ContainerStatement::setType ( std::string type ) {
+	m_type = std::move ( type );
+}
+
+} /* namespace cli */
diff --git a/alib2cli/src/ast/statements/ContainerStatement.h b/alib2cli/src/ast/statements/ContainerStatement.h
new file mode 100644
index 0000000000..83930e6aff
--- /dev/null
+++ b/alib2cli/src/ast/statements/ContainerStatement.h
@@ -0,0 +1,28 @@
+#ifndef _CLI_CONTAINER_STATEMENT_H_
+#define _CLI_CONTAINER_STATEMENT_H_
+
+#include <ast/Statement.h>
+#include <abstraction/Registry.h>
+#include <exception/CommonException.h>
+#include <iostream>
+
+namespace cli {
+
+class ContainerStatement final : public Statement {
+	std::string m_container;
+	ext::vector < std::unique_ptr < Param > > m_params;
+	ext::vector < std::unique_ptr < Option > > m_options;
+
+	std::string m_type;
+
+public:
+	ContainerStatement ( std::string container, ext::vector < std::unique_ptr < Param > > params, ext::vector < std::unique_ptr < Option > > options );
+
+	virtual std::shared_ptr < abstraction::OperationAbstraction > translateAndEval ( const std::shared_ptr < abstraction::OperationAbstraction > & prev, Environment & environment ) const override;
+
+	void setType ( std::string type );
+};
+
+} /* namespace cli */
+
+#endif /* _CLI_CONTAINER_STATEMENT_H_ */
diff --git a/alib2cli/src/lexer/Lexer.cpp b/alib2cli/src/lexer/Lexer.cpp
index 2041b330c2..ad591d4d06 100644
--- a/alib2cli/src/lexer/Lexer.cpp
+++ b/alib2cli/src/lexer/Lexer.cpp
@@ -35,6 +35,26 @@ q0:	if ( m_index >= m_line.size ( ) ) {
 		res.m_type = TokenType::RIGHT_PAREN;
 		return res;
 	}
+	if ( m_line [ m_index ] == '{' ) {
+		m_index ++;
+		res.m_type = TokenType::LEFT_BRACE;
+		return res;
+	}
+	if ( m_line [ m_index ] == '}' ) {
+		m_index ++;
+		res.m_type = TokenType::RIGHT_BRACE;
+		return res;
+	}
+	if ( m_line [ m_index ] == '[' ) {
+		m_index ++;
+		res.m_type = TokenType::LEFT_BRACKET;
+		return res;
+	}
+	if ( m_line [ m_index ] == ']' ) {
+		m_index ++;
+		res.m_type = TokenType::RIGHT_BRACKET;
+		return res;
+	}
 	if ( m_line [ m_index ] == '$' ) {
 		m_index ++;
 		res.m_type = TokenType::DOLAR_SIGN;
diff --git a/alib2cli/src/lexer/Lexer.h b/alib2cli/src/lexer/Lexer.h
index 7ed1d1676f..8e56b887ac 100644
--- a/alib2cli/src/lexer/Lexer.h
+++ b/alib2cli/src/lexer/Lexer.h
@@ -19,6 +19,10 @@ public:
 		OUT_REDIRECT,
 		LEFT_PAREN,
 		RIGHT_PAREN,
+		LEFT_BRACE,
+		RIGHT_BRACE,
+		LEFT_BRACKET,
+		RIGHT_BRACKET,
 		DOLAR_SIGN,
 		AMPERSAND_SIGN,
 		PIPE_SIGN,
@@ -55,6 +59,14 @@ public:
 				return out << "left_paren";
 			case TokenType::RIGHT_PAREN :
 				return out << "right_paren";
+			case TokenType::LEFT_BRACE :
+				return out << "left_brace";
+			case TokenType::RIGHT_BRACE :
+				return out << "right_brace";
+			case TokenType::LEFT_BRACKET :
+				return out << "left_bracket";
+			case TokenType::RIGHT_BRACKET :
+				return out << "right_bracket";
 			case TokenType::DOLAR_SIGN :
 				return out << "dolar_sign";
 			case TokenType::AMPERSAND_SIGN :
diff --git a/alib2cli/src/parser/Parser.cpp b/alib2cli/src/parser/Parser.cpp
index bdce7cfa47..a750241de9 100644
--- a/alib2cli/src/parser/Parser.cpp
+++ b/alib2cli/src/parser/Parser.cpp
@@ -2,6 +2,7 @@
 
 #include <ast/statements/CastStatement.h>
 #include <ast/statements/SingleStatement.h>
+#include <ast/statements/ContainerStatement.h>
 #include <ast/statements/ResultFileStatement.h>
 #include <ast/statements/ResultVariableStatement.h>
 #include <ast/statements/ResultPrintStatement.h>
@@ -31,6 +32,7 @@
 #include <command/SetCommand.h>
 
 #include <ast/options/HL3Option.h>
+#include <ast/options/TypeOption.h>
 #include <ast/options/CategoryOption.h>
 
 #include <primitive/Integer.h>
@@ -48,6 +50,17 @@ std::unique_ptr < Option > Parser::category_option ( ) {
 	}
 }
 
+std::unique_ptr < Option > Parser::type_option ( ) {
+	if ( check_nonreserved_kw ( "type" ) ) {
+		match_nonreserved_kw ( "type" );
+		std::string value = getTokenValue ( );
+		match ( cli::Lexer::TokenType::INTEGER, cli::Lexer::TokenType::IDENTIFIER );
+		return std::make_unique < TypeOption > ( std::move ( value ) );
+	} else {
+		return nullptr;
+	}
+}
+
 std::unique_ptr < Option > Parser::option ( ) {
 	match ( cli::Lexer::TokenType::COLON_SIGN );
 	if ( check_nonreserved_kw ( "hl3" ) ) {
@@ -203,6 +216,27 @@ std::shared_ptr < Statement > Parser::single_statement ( ) {
 		}
 
 		return std::make_shared < SingleStatement > ( std::move ( name ), std::move ( params ), std::move ( options ) );
+	} else if ( check ( cli::Lexer::TokenType::LEFT_BRACE ) ) {
+		match ( cli::Lexer::TokenType::LEFT_BRACE );
+		ext::vector < std::unique_ptr < Option > > options;
+		while ( check ( cli::Lexer::TokenType::COLON_SIGN ) ) {
+			match ( cli::Lexer::TokenType::COLON_SIGN );
+			std::unique_ptr < Option > res = type_option ( );
+			if ( ! res )
+				res = option ( );
+			if ( ! res )
+				throw exception::CommonException ( "Option not recognised" );
+			options.emplace_back ( std::move ( res ) );
+		}
+
+		ext::vector < std::unique_ptr < Param > > params;
+		while ( ! check ( cli::Lexer::TokenType::RIGHT_BRACE ) ) {
+			params.emplace_back ( param ( ) );
+		}
+
+		std::shared_ptr < Statement > res = std::make_shared < ContainerStatement > ( "Set", std::move ( params ), std::move ( options ) );
+		match ( cli::Lexer::TokenType::RIGHT_BRACE );
+		return res;
 	} else if ( check ( cli::Lexer::TokenType::HASH_SIGN ) ) {
 		match ( cli::Lexer::TokenType::HASH_SIGN );
 		std::string value = getTokenValue ( );
diff --git a/alib2cli/src/parser/Parser.h b/alib2cli/src/parser/Parser.h
index 8d6a709b6d..124c88a858 100644
--- a/alib2cli/src/parser/Parser.h
+++ b/alib2cli/src/parser/Parser.h
@@ -81,6 +81,7 @@ public:
 	}
 
 	std::unique_ptr < Option > category_option ( );
+	std::unique_ptr < Option > type_option ( );
 	std::unique_ptr < Option > option ( );
 
 	std::unique_ptr < Arg > arg ( );
diff --git a/alib2cli/test-src/cli/CliTest.cpp b/alib2cli/test-src/cli/CliTest.cpp
index e86f8daf2d..6b49045781 100644
--- a/alib2cli/test-src/cli/CliTest.cpp
+++ b/alib2cli/test-src/cli/CliTest.cpp
@@ -11,6 +11,7 @@
 #include <abstraction/AlgorithmRegistry.hpp>
 #include <abstraction/XmlFileWriterRegistry.hpp>
 #include <abstraction/XmlParserRegistry.hpp>
+#include <abstraction/ContainerRegistry.hpp>
 
 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION ( CliTest, "common" );
 CPPUNIT_TEST_SUITE_REGISTRATION ( CliTest );
@@ -237,3 +238,24 @@ void CliTest::testConstRvalueReferencePassing ( ) {
 	cli::Parser parser ( cli::Lexer ( "execute ConstRvalueReferenceProvider | ConstRvalueReferenceAcceptor ^ - >" ) );
 	parser.parse ( )->run ( environment );
 }
+
+class Print {
+public:
+	static void print ( ext::set < int > theSet ) {
+		for ( int value : theSet )
+			std::cout << value << ", ";
+		std::cout << std::endl;
+	}
+};
+
+void CliTest::testSetConstruction ( ) {
+	abstraction::ContainerRegistry::registerSet < int > ( );
+	abstraction::AlgorithmRegistry::registerAlgorithm < Print > ( Print::print, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, false, false, std::array < std::string, 1 > ( ) );
+
+	cli::Environment environment;
+	cli::Parser parser ( cli::Lexer ( "execute { :type int 1 2 3 } > $set" ) );
+	parser.parse ( )->run ( environment );
+	std::cout << environment.getVariable ( "set" )->getReturnType ( ) << std::endl;
+	parser = cli::Parser ( cli::Lexer ( "execute $set | Print -" ) );
+	parser.parse ( )->run ( environment );
+}
diff --git a/alib2cli/test-src/cli/CliTest.h b/alib2cli/test-src/cli/CliTest.h
index 4f0f82bb32..d9f5c7af68 100644
--- a/alib2cli/test-src/cli/CliTest.h
+++ b/alib2cli/test-src/cli/CliTest.h
@@ -11,6 +11,7 @@ class CliTest : public CppUnit::TestFixture {
 	CPPUNIT_TEST ( testConstReferencePassing );
 	CPPUNIT_TEST ( testReferencePassing );
 	CPPUNIT_TEST ( testConstRvalueReferencePassing );
+	CPPUNIT_TEST ( testSetConstruction );
 	CPPUNIT_TEST_SUITE_END ( );
 
 public:
@@ -23,6 +24,7 @@ public:
 	void testConstReferencePassing ( );
 	void testReferencePassing ( );
 	void testConstRvalueReferencePassing ( );
+	void testSetConstruction ( );
 };
 
 #endif // CLI_TEST_H_
-- 
GitLab