From 53eb8442f8599a0bc106d0919545ef80779b0918 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Fri, 11 Aug 2017 19:46:37 +0200
Subject: [PATCH] change cli syntax, pass options to singleStatement

---
 alib2cli/src/ast/Ast.h                        | 12 ++++
 alib2cli/src/ast/Option.h                     | 19 ++++++
 alib2cli/src/ast/Param.h                      |  1 +
 alib2cli/src/ast/Statement.h                  |  3 +-
 alib2cli/src/ast/options/HL3Option.h          | 17 ++++++
 .../src/ast/statements/SingleStatement.cpp    | 58 +++++++++++++++++++
 alib2cli/src/ast/statements/SingleStatement.h | 51 ++--------------
 alib2cli/src/command/HelpCommand.h            | 10 ++--
 alib2cli/src/lexer/Lexer.cpp                  |  5 ++
 alib2cli/src/lexer/Lexer.h                    |  3 +
 alib2cli/src/parser/Parser.cpp                | 44 +++++++++-----
 alib2cli/src/parser/Parser.h                  |  7 ++-
 alib2cli/test-src/cli/CliTest.cpp             |  4 +-
 13 files changed, 165 insertions(+), 69 deletions(-)
 create mode 100644 alib2cli/src/ast/Ast.h
 create mode 100644 alib2cli/src/ast/Option.h
 create mode 100644 alib2cli/src/ast/options/HL3Option.h
 create mode 100644 alib2cli/src/ast/statements/SingleStatement.cpp

diff --git a/alib2cli/src/ast/Ast.h b/alib2cli/src/ast/Ast.h
new file mode 100644
index 0000000000..b79fc96bf4
--- /dev/null
+++ b/alib2cli/src/ast/Ast.h
@@ -0,0 +1,12 @@
+#ifndef _CLI_AST_H_
+#define _CLI_AST_H_
+
+namespace cli {
+
+class Option;
+class Statement;
+class Param;
+
+} /* namespace cli */
+
+#endif /* _CLI_AST_H_ */
diff --git a/alib2cli/src/ast/Option.h b/alib2cli/src/ast/Option.h
new file mode 100644
index 0000000000..2c9c896b2a
--- /dev/null
+++ b/alib2cli/src/ast/Option.h
@@ -0,0 +1,19 @@
+#ifndef _CLI_OPTION_H_
+#define _CLI_OPTION_H_
+
+#include <ast/Ast.h>
+#include <ast/statements/SingleStatement.h>
+
+namespace cli {
+
+class Option {
+public:
+	virtual ~Option ( ) noexcept {
+	}
+
+	virtual void eval ( SingleStatement & statement ) const = 0;
+};
+
+} /* namespace cli */
+
+#endif /* _CLI_OPTION_H_ */
diff --git a/alib2cli/src/ast/Param.h b/alib2cli/src/ast/Param.h
index 82bf87a669..4e2ef4a463 100644
--- a/alib2cli/src/ast/Param.h
+++ b/alib2cli/src/ast/Param.h
@@ -1,6 +1,7 @@
 #ifndef _CLI_PARAM_H_
 #define _CLI_PARAM_H_
 
+#include <ast/Ast.h>
 #include <abstraction/OperationAbstraction.hpp>
 #include <environment/Environment.h>
 
diff --git a/alib2cli/src/ast/Statement.h b/alib2cli/src/ast/Statement.h
index 2a23c5496f..5e026e7a0b 100644
--- a/alib2cli/src/ast/Statement.h
+++ b/alib2cli/src/ast/Statement.h
@@ -1,12 +1,13 @@
 #ifndef _CLI_STATEMENT_H_
 #define _CLI_STATEMENT_H_
 
+#include <ast/Ast.h>
 #include <abstraction/OperationAbstraction.hpp>
 #include <environment/Environment.h>
 
 namespace cli {
 
-class Statement {
+class Statement : public std::enable_shared_from_this < Statement > {
 public:
 	virtual ~Statement ( ) noexcept {
 	}
diff --git a/alib2cli/src/ast/options/HL3Option.h b/alib2cli/src/ast/options/HL3Option.h
new file mode 100644
index 0000000000..90b3bea7de
--- /dev/null
+++ b/alib2cli/src/ast/options/HL3Option.h
@@ -0,0 +1,17 @@
+#ifndef _CLI_HL3_OPTION_H_
+#define _CLI_HL3_OPTION_H_
+
+#include <ast/Option.h>
+
+namespace cli {
+
+class HL3Option final : public Option {
+public:
+	virtual void eval ( SingleStatement & statement ) const override {
+		statement.setHL3 ( );
+	}
+};
+
+} /* namespace cli */
+
+#endif /* _CLI_HL3_OPTION_H_ */
diff --git a/alib2cli/src/ast/statements/SingleStatement.cpp b/alib2cli/src/ast/statements/SingleStatement.cpp
new file mode 100644
index 0000000000..4804e8791e
--- /dev/null
+++ b/alib2cli/src/ast/statements/SingleStatement.cpp
@@ -0,0 +1,58 @@
+#include <ast/statements/SingleStatement.h>
+#include <ast/Option.h>
+#include <ast/Param.h>
+
+namespace cli {
+
+SingleStatement::SingleStatement ( std::string name, ext::vector < std::unique_ptr < Param > > params, ext::vector < std::unique_ptr < Option > > options ) : m_name ( name ), 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 > SingleStatement::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 ) );
+	}
+
+	ext::vector < ext::type_index > paramTypes;
+	for ( const  std::shared_ptr < abstraction::OperationAbstraction > & param : params ) {
+		paramTypes.push_back ( param->type ( ) );
+	}
+
+	bool downcast = false;
+	bool normalize = false;
+
+	std::shared_ptr < abstraction::OperationAbstraction > algo = abstraction::Registry::getAlgorithmAbstraction ( m_name, paramTypes, downcast, normalize );
+
+	unsigned i = 0;
+	for ( const std::shared_ptr < abstraction::OperationAbstraction > & param : params ) {
+		if ( ! algo->attachInput ( param, i ) )
+			throw exception::CommonException ( "Can't connect param at " + ext::to_string ( i ) + " of algorithm " + m_name + " with result of type " + ext::to_string ( param->type ( ) ) + "." );
+		i++;
+	}
+
+	if ( ! algo->eval ( ) )
+		throw exception::CommonException ( "Eval of algorithm " + m_name + " failed." );
+
+	if ( downcast ) {
+		std::shared_ptr < abstraction::OperationAbstraction > downcaster = algo->getDowncastResult ( );
+		downcaster->attachInput ( algo, 0 );
+		downcaster->eval ( );
+
+		algo = downcaster;
+	}
+
+	if ( normalize ) {
+		std::shared_ptr < abstraction::OperationAbstraction > normalized = algo->getNormalizeResult ( );
+		normalized->attachInput ( algo, 0 );
+		normalized->eval ( );
+
+		algo = normalized;
+	}
+
+	return algo;
+}
+
+} /* namespace cli */
diff --git a/alib2cli/src/ast/statements/SingleStatement.h b/alib2cli/src/ast/statements/SingleStatement.h
index ef7d6b518c..f68f7aa484 100644
--- a/alib2cli/src/ast/statements/SingleStatement.h
+++ b/alib2cli/src/ast/statements/SingleStatement.h
@@ -4,62 +4,23 @@
 #include <ast/Statement.h>
 #include <abstraction/Registry.h>
 #include <exception/CommonException.h>
+#include <iostream>
 
 namespace cli {
 
 class SingleStatement final : public Statement {
 	std::string m_name;
 	ext::vector < std::unique_ptr < Param > > m_params;
+	ext::vector < std::unique_ptr < Option > > m_options;
 
 public:
-	SingleStatement ( std::string name, ext::vector < std::unique_ptr < Param > > params ) : m_name ( name ), m_params ( std::move ( params ) ) {
-	}
-
-	virtual std::shared_ptr < abstraction::OperationAbstraction > translateAndEval ( const std::shared_ptr < abstraction::OperationAbstraction > & prev, Environment & environment ) const override {
-		ext::vector < std::shared_ptr < abstraction::OperationAbstraction > > params;
-		for ( const std::unique_ptr < Param > & param : m_params ) {
-			params.push_back ( param->translateAndEval ( prev, environment ) );
-		}
-
-		ext::vector < ext::type_index > paramTypes;
-		for ( const  std::shared_ptr < abstraction::OperationAbstraction > & param : params ) {
-			paramTypes.push_back ( param->type ( ) );
-		}
-
-		bool downcast = false;
-		bool normalize = false;
-
-		std::shared_ptr < abstraction::OperationAbstraction > algo = abstraction::Registry::getAlgorithmAbstraction ( m_name, paramTypes, downcast, normalize );
-
-		unsigned i = 0;
-		for ( const std::shared_ptr < abstraction::OperationAbstraction > & param : params ) {
-			if ( ! algo->attachInput ( param, i ) )
-				throw exception::CommonException ( "Can't connect param at " + ext::to_string ( i ) + " of algorithm " + m_name + " with result of type " + ext::to_string ( param->type ( ) ) + "." );
-			i++;
-		}
+	SingleStatement ( std::string name, ext::vector < std::unique_ptr < Param > > params, ext::vector < std::unique_ptr < Option > > options );
 
-		if ( ! algo->eval ( ) )
-			throw exception::CommonException ( "Eval of algorithm " + m_name + " failed." );
+	virtual std::shared_ptr < abstraction::OperationAbstraction > translateAndEval ( const std::shared_ptr < abstraction::OperationAbstraction > & prev, Environment & environment ) const override;
 
-		if ( downcast ) {
-			std::shared_ptr < abstraction::OperationAbstraction > downcaster = algo->getDowncastResult ( );
-			downcaster->attachInput ( algo, 0 );
-			downcaster->eval ( );
-
-			algo = downcaster;
-		}
-
-		if ( normalize ) {
-			std::shared_ptr < abstraction::OperationAbstraction > normalized = algo->getNormalizeResult ( );
-			normalized->attachInput ( algo, 0 );
-			normalized->eval ( );
-
-			algo = normalized;
-		}
-
-		return algo;
+	void setHL3 ( ) {
+		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/command/HelpCommand.h b/alib2cli/src/command/HelpCommand.h
index 222fb8f065..a78a6a46c1 100644
--- a/alib2cli/src/command/HelpCommand.h
+++ b/alib2cli/src/command/HelpCommand.h
@@ -26,25 +26,25 @@ public:
 			std::cout << "" << std::endl;
 			std::cout << "identifier   - an immediate string param - the value is a std::string (ImmediateValueParam)" << std::endl;
 			std::cout << "number       - an immediate number param - the value is an int (ImmediateValueParam)" << std::endl;
-			std::cout << ":identifier  - an immediate value from an environment - the value is a std::string (BindedValueParam)" << std::endl;
+			std::cout << "#identifier  - an immediate value from an environment - the value is a std::string (BindedValueParam)" << std::endl;
 			std::cout << "$identifier  - a value from a variable (VariableValueParam)" << std::endl;
 			std::cout << "" << std::endl;
 			std::cout << "<identifier  - a value from a xml file named (ImmediateFileParam)" << std::endl;
-			std::cout << "<:identifier - a value from a xml file with a name from an environment (BindedFileParam)" << std::endl;
+			std::cout << "<#identifier - a value from a xml file with a name from an environment (BindedFileParam)" << std::endl;
 			std::cout << "" << std::endl;
 			std::cout << "statement:" << std::endl;
 			std::cout << "name ( param )* output_spec - a statement with params (SingleStatement)" << std::endl;
 			std::cout << "( type ) statement          - the result of a statement is casted (CastedStatement)" << std::endl;
 			std::cout << "" << std::endl;
-			std::cout << ":identifier  - an immediate value from an environment (BindedValueStatement)" << std::endl;
+			std::cout << "#identifier  - an immediate value from an environment (BindedValueStatement)" << std::endl;
 			std::cout << "$identifier  - a value from a variable (VariableValueStatement)" << std::endl;
 			std::cout << "" << std::endl;
 			std::cout << "<identifier  - a value from a xml file (ImmediateFileStatement)" << std::endl;
-			std::cout << "<:identifier - a value from a xml file with a name from an environment (BindedFileStatement)" << std::endl;
+			std::cout << "<#identifier - a value from a xml file with a name from an environment (BindedFileStatement)" << std::endl;
 			std::cout << "" << std::endl;
 			std::cout << "output_spec:" << std::endl;
 			std::cout << ">identifier  - a value to a xml file (ResultImmediateFileStatement)" << std::endl;
-			std::cout << ">:identifier - a value to a xml file with name from environment (ResultBindedFileStatement)" << std::endl;
+			std::cout << ">#identifier - a value to a xml file with name from environment (ResultBindedFileStatement)" << std::endl;
 			std::cout << ">$identifier - a value to a variable (ResultVariableStatement)" << std::endl;
 			std::cout << ">            - a value is discarded" << std::endl;
 			std::cout << "             - an empty output specifier prints the result to the stdout (ResultPrintStatement)" << std::endl;
diff --git a/alib2cli/src/lexer/Lexer.cpp b/alib2cli/src/lexer/Lexer.cpp
index f6aba8a339..d70f22cc9d 100644
--- a/alib2cli/src/lexer/Lexer.cpp
+++ b/alib2cli/src/lexer/Lexer.cpp
@@ -60,6 +60,11 @@ q0:		if ( m_index >= m_line.size ( ) ) {
 		res.m_type = TokenType::EQUAL_SIGN;
 		return res;
 	}
+	if ( m_line [ m_index ] == '#' ) {
+		m_index ++;
+		res.m_type = TokenType::HASH_SIGN;
+		return res;
+	}
 	if ( m_line [ m_index ] == '-' ) {
 		res.m_value += m_line [ m_index ];
 		m_index ++;
diff --git a/alib2cli/src/lexer/Lexer.h b/alib2cli/src/lexer/Lexer.h
index 64eb39d97c..7eb4d8a426 100644
--- a/alib2cli/src/lexer/Lexer.h
+++ b/alib2cli/src/lexer/Lexer.h
@@ -24,6 +24,7 @@ public:
 		COLON_SIGN,
 		DASH_SIGN,
 		EQUAL_SIGN,
+		HASH_SIGN,
 		ERROR,
 		END
 	};
@@ -62,6 +63,8 @@ public:
 				return out << "dash_sign";
 			case TokenType::EQUAL_SIGN :
 				return out << "equal_sign";
+			case TokenType::HASH_SIGN :
+				return out << "hash_sign";
 			case TokenType::ERROR :
 				return out << "error";
 			case TokenType::END :
diff --git a/alib2cli/src/parser/Parser.cpp b/alib2cli/src/parser/Parser.cpp
index 46b0ae6b75..06749d3d5a 100644
--- a/alib2cli/src/parser/Parser.cpp
+++ b/alib2cli/src/parser/Parser.cpp
@@ -26,19 +26,31 @@
 #include <command/IntrospectionCommand.h>
 #include <command/SetCommand.h>
 
+#include <ast/options/HL3Option.h>
+
 #include <primitive/Integer.h>
 #include <primitive/String.h>
 
 namespace cli {
 
+std::unique_ptr < Option > Parser::option ( ) {
+	match ( cli::Lexer::TokenType::COLON_SIGN );
+	if ( check_nonreserved_kw ( "hl3" ) ) {
+		match_nonreserved_kw ( "hl3" );
+		return std::make_unique < HL3Option > ( );
+	} else {
+		throw exception::CommonException ( "Mismatched set while expanding option rule." );
+	}
+}
+
 std::unique_ptr < Param > Parser::in_redirect_param ( ) {
 	if ( check ( cli::Lexer::TokenType::LEFT_PAREN ) ) {
 		match ( cli::Lexer::TokenType::LEFT_PAREN );
 		auto sub_statement = std::make_unique < StatementParam > ( statement_list ( ) );
 		match ( cli::Lexer::TokenType::RIGHT_PAREN );
 		return sub_statement;
-	} else if ( check ( cli::Lexer::TokenType::COLON_SIGN ) ) {
-		match ( cli::Lexer::TokenType::COLON_SIGN );
+	} else if ( check ( cli::Lexer::TokenType::HASH_SIGN ) ) {
+		match ( cli::Lexer::TokenType::HASH_SIGN );
 		std::string name = getTokenValue ( );
 		match ( cli::Lexer::TokenType::INTEGER, cli::Lexer::TokenType::IDENTIFIER );
 		return std::make_unique < BindedFileParam > ( std::move ( name ) );
@@ -67,8 +79,8 @@ std::unique_ptr < Param > Parser::param ( ) {
 		match ( cli::Lexer::TokenType::RIGHT_PAREN );
 		std::unique_ptr < Param > castedParam = param ( );
 		return std::make_unique < CastParam > ( std::move ( type ), std::move ( castedParam ) );
-	} else if ( check ( cli::Lexer::TokenType::COLON_SIGN ) ) {
-		match ( cli::Lexer::TokenType::COLON_SIGN );
+	} else if ( check ( cli::Lexer::TokenType::HASH_SIGN ) ) {
+		match ( cli::Lexer::TokenType::HASH_SIGN );
 		std::string name = getTokenValue ( );
 		match ( cli::Lexer::TokenType::INTEGER, cli::Lexer::TokenType::IDENTIFIER );
 		return std::make_unique < BindedValueParam > ( std::move ( name ) );
@@ -83,8 +95,8 @@ std::unique_ptr < Param > Parser::param ( ) {
 }
 
 std::shared_ptr < Statement > Parser::in_redirect_statement ( ) {
-	if ( check ( cli::Lexer::TokenType::COLON_SIGN ) ) {
-		match ( cli::Lexer::TokenType::COLON_SIGN );
+	if ( check ( cli::Lexer::TokenType::HASH_SIGN ) ) {
+		match ( cli::Lexer::TokenType::HASH_SIGN );
 		std::string name = getTokenValue ( );
 		match ( cli::Lexer::TokenType::INTEGER, cli::Lexer::TokenType::IDENTIFIER );
 		return std::make_unique < BindedFileStatement > ( std::move ( name ) );
@@ -99,8 +111,8 @@ std::shared_ptr < Statement > Parser::single_statement ( ) {
 		match ( cli::Lexer::TokenType::DOLAR_SIGN );
 		std::string name = matchIdentifier ( );
 		return std::make_shared < VariableValueStatement > ( std::move ( name ) );
-	} else if ( check ( cli::Lexer::TokenType::COLON_SIGN ) ) {
-		match ( cli::Lexer::TokenType::COLON_SIGN );
+	} else if ( check ( cli::Lexer::TokenType::HASH_SIGN ) ) {
+		match ( cli::Lexer::TokenType::HASH_SIGN );
 		std::string name = matchIdentifier ( );
 		return std::make_shared < BindedValueStatement > ( std::move ( name ) );
 	} else if ( check ( cli::Lexer::TokenType::IN_REDIRECT ) ) {
@@ -114,14 +126,18 @@ std::shared_ptr < Statement > Parser::single_statement ( ) {
 		return std::make_shared < CastStatement > ( std::move ( type ), casted_statement );
 	} else if ( check ( cli::Lexer::TokenType::IDENTIFIER ) ) {
 		std::string name = matchIdentifier ( );
+		ext::vector < std::unique_ptr < Option > > options;
+		while ( check ( cli::Lexer::TokenType::COLON_SIGN ) ) {
+			options.emplace_back ( option ( ) );
+		}
 		ext::vector < std::unique_ptr < Param > > params;
-		while ( ! check ( cli::Lexer::TokenType::OUT_REDIRECT ) && ! check ( cli::Lexer::TokenType::COLON_SIGN ) && ! check ( cli::Lexer::TokenType::PIPE_SIGN ) && ! check ( cli::Lexer::TokenType::END ) && ! check ( cli::Lexer::TokenType::RIGHT_PAREN ) ) {
+		while ( ! check ( cli::Lexer::TokenType::OUT_REDIRECT ) && ! check ( cli::Lexer::TokenType::HASH_SIGN ) && ! check ( cli::Lexer::TokenType::PIPE_SIGN ) && ! check ( cli::Lexer::TokenType::END ) && ! check ( cli::Lexer::TokenType::RIGHT_PAREN ) ) {
 			params.emplace_back ( param ( ) );
 		}
 
-		return std::make_shared < SingleStatement > ( name, std::move ( params ) );
+		return std::make_shared < SingleStatement > ( name, std::move ( params ), std::move ( options ) );
 	} else {
-		throw exception::CommonException ( "Mismatched set while expanding param rule." );
+		throw exception::CommonException ( "Mismatched set while expanding single_statement rule." );
 	}
 }
 
@@ -141,8 +157,8 @@ std::shared_ptr < StatementList > Parser::statement_list_cont ( ) {
 }
 
 void Parser::out_redirect ( std::shared_ptr < StatementList > & list ) {
-	if ( check ( cli::Lexer::TokenType::COLON_SIGN ) ) {
-		match ( cli::Lexer::TokenType::COLON_SIGN );
+	if ( check ( cli::Lexer::TokenType::HASH_SIGN ) ) {
+		match ( cli::Lexer::TokenType::HASH_SIGN );
 		std::string name = getTokenValue ( );
 		match ( cli::Lexer::TokenType::INTEGER, cli::Lexer::TokenType::IDENTIFIER );
 		list->append ( std::make_unique < ResultBindedFileStatement > ( std::move ( name ) ) );
@@ -207,7 +223,7 @@ std::unique_ptr < Command > Parser::parse ( ) {
 		match ( cli::Lexer::TokenType::END );
 		return std::make_unique < SetCommand > ( std::move ( param ), std::move ( value ) );
 	} else {
-		throw exception::CommonException ( "Mismatched set while expanding param rule." );
+		throw exception::CommonException ( "Mismatched set while expanding parse rule." );
 	}
 }
 
diff --git a/alib2cli/src/parser/Parser.h b/alib2cli/src/parser/Parser.h
index 1b50257903..063edc3b8a 100644
--- a/alib2cli/src/parser/Parser.h
+++ b/alib2cli/src/parser/Parser.h
@@ -3,10 +3,11 @@
 
 #include <ast/Param.h>
 #include <ast/Statement.h>
-#include <ast/statements/StatementList.h>
-
+#include <ast/Option.h>
 #include <command/Command.h>
 
+#include <ast/statements/StatementList.h>
+
 #include <lexer/Lexer.h>
 
 #include <exception/CommonException.h>
@@ -68,6 +69,8 @@ public:
 		return m_current.m_value;
 	}
 
+	std::unique_ptr < Option > option ( );
+
 	std::unique_ptr < Param > in_redirect_param ( );
 
 	std::unique_ptr < Param > param ( );
diff --git a/alib2cli/test-src/cli/CliTest.cpp b/alib2cli/test-src/cli/CliTest.cpp
index 8b2ce29b5a..20799db7c5 100644
--- a/alib2cli/test-src/cli/CliTest.cpp
+++ b/alib2cli/test-src/cli/CliTest.cpp
@@ -84,11 +84,11 @@ void CliTest::testCreateUnique ( ) {
 	try {
 		cli::Environment environment;
 		environment.setBinding ( "1", "1" );
-		cli::Parser parser ( cli::Lexer ( "execute One | Add <( Add (int) :1 <(One) ) - | Neg - > local/xxx.xml" ) );
+		cli::Parser parser ( cli::Lexer ( "execute One | Add <( Add (int) #1 <(One) ) - | Neg - > local/xxx.xml" ) );
 		parser.parse ( )->run ( environment );
 
 		environment.setBinding ( "2", "local/xxx.xml" );
-		parser = cli::Parser ( cli::Lexer ( "execute One | Add <( Add (int) <:2 <(One) ) - | (double) Neg - | Divide - <(One | (double) Add <(One) - )" ) );
+		parser = cli::Parser ( cli::Lexer ( "execute One | Add <( Add (int) <#2 <(One) ) - | (double) Neg - | Divide - <(One | (double) Add <(One) - )" ) );
 		parser.parse ( )->run ( environment );
 
 		parser = cli::Parser ( cli::Lexer ( "execute One > $res" ) );
-- 
GitLab