From fd93cba85c8cde67d85b8ff123aa63c3b2a8547f Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Fri, 30 Aug 2019 11:50:06 +0200
Subject: [PATCH] implement semicolon separation of commands

---
 alib2cli/src/command/CommandList.h | 34 ++++++++++++++++++++++++++++++
 alib2cli/src/lexer/Lexer.cpp       |  6 ++++++
 alib2cli/src/lexer/Lexer.h         |  3 +++
 alib2cli/src/parser/Parser.cpp     | 33 ++++++++++++++++-------------
 alib2cli/src/parser/Parser.h       |  6 ++++--
 5 files changed, 65 insertions(+), 17 deletions(-)
 create mode 100644 alib2cli/src/command/CommandList.h

diff --git a/alib2cli/src/command/CommandList.h b/alib2cli/src/command/CommandList.h
new file mode 100644
index 0000000000..ecfb42f0f8
--- /dev/null
+++ b/alib2cli/src/command/CommandList.h
@@ -0,0 +1,34 @@
+#ifndef _CLI_COMMAND_LIST_H_
+#define _CLI_COMMAND_LIST_H_
+
+#include <command/Command.h>
+
+namespace cli {
+
+class CommandList final : public Command {
+	ext::vector < std::unique_ptr < Command > > m_commands;
+
+public:
+	CommandList ( ext::vector < std::unique_ptr < Command > > commands ) : m_commands ( std::move ( commands ) ) {
+	}
+
+	Command::Result run ( Environment & environment ) const override {
+		if ( m_commands.empty ( ) )
+			throw std::invalid_argument ( "Command list can't be empty" );
+
+		Command::Result res = Command::Result::OK;
+		for ( size_t i = 0; i < m_commands.size ( ) && res == Command::Result::OK; ++ i )
+			res = m_commands [ i ]->run ( environment );
+
+		return res;
+	}
+
+	void append ( std::unique_ptr < Command > command ) {
+		m_commands.emplace_back ( std::move ( command ) );
+	}
+
+};
+
+} /* namespace cli */
+
+#endif /* _CLI_COMMAND_LIST_H_ */
diff --git a/alib2cli/src/lexer/Lexer.cpp b/alib2cli/src/lexer/Lexer.cpp
index 48e23090c6..2c44d09b3c 100644
--- a/alib2cli/src/lexer/Lexer.cpp
+++ b/alib2cli/src/lexer/Lexer.cpp
@@ -113,6 +113,12 @@ q0:	if ( m_source->isEndOfTransmition ( ) ) {
 		res.m_type = TokenType::COLON_SIGN;
 		return res;
 	}
+	if ( m_source->getCharacter ( ) == ';' ) {
+		res.m_raw += m_source->getCharacter ( );
+		m_source->advance ( readNextLine );
+		res.m_type = TokenType::SEMICOLON_SIGN;
+		return res;
+	}
 	if ( m_source->getCharacter ( ) == '=' ) {
 		res.m_raw += m_source->getCharacter ( );
 		m_source->advance ( readNextLine );
diff --git a/alib2cli/src/lexer/Lexer.h b/alib2cli/src/lexer/Lexer.h
index ff23c37e27..9a6c9baf9f 100644
--- a/alib2cli/src/lexer/Lexer.h
+++ b/alib2cli/src/lexer/Lexer.h
@@ -44,6 +44,7 @@ public:
 		PIPE_SIGN,
 		CARET_SIGN,
 		COLON_SIGN,
+		SEMICOLON_SIGN,
 		DASH_SIGN,
 		EQUAL_SIGN,
 		HASH_SIGN,
@@ -90,6 +91,8 @@ public:
 			return "caret_sign";
 		case TokenType::COLON_SIGN :
 			return "colon_sign";
+		case TokenType::SEMICOLON_SIGN :
+			return "semicolon_sign";
 		case TokenType::DASH_SIGN :
 			return "dash_sign";
 		case TokenType::EQUAL_SIGN :
diff --git a/alib2cli/src/parser/Parser.cpp b/alib2cli/src/parser/Parser.cpp
index ca72b598bd..48e51675b2 100644
--- a/alib2cli/src/parser/Parser.cpp
+++ b/alib2cli/src/parser/Parser.cpp
@@ -240,7 +240,7 @@ std::shared_ptr < Statement > Parser::statement ( ) {
 		std::unique_ptr < CategoryOption > category = category_option ( );
 		ext::vector < std::shared_ptr < Statement > > params;
 		ext::vector < bool > moves;
-		while ( ! check ( cli::Lexer::TokenType::OUT_REDIRECT ) && ! check ( cli::Lexer::TokenType::PIPE_SIGN ) && ! check ( cli::Lexer::TokenType::EOS ) && ! check ( cli::Lexer::TokenType::RIGHT_PAREN ) ) {
+		while ( ! check ( cli::Lexer::TokenType::OUT_REDIRECT ) && ! check ( cli::Lexer::TokenType::PIPE_SIGN ) && ! check ( cli::Lexer::TokenType::EOS ) && ! check ( cli::Lexer::TokenType::RIGHT_PAREN ) && ! check ( cli::Lexer::TokenType::SEMICOLON_SIGN ) ) {
 			moves.push_back ( move_arg ( ) );
 			params.emplace_back ( param ( ) );
 		}
@@ -266,7 +266,7 @@ std::shared_ptr < StatementList > Parser::statement_list ( ) {
 		match ( cli::Lexer::TokenType::PIPE_SIGN );
 		list.emplace_back ( statement ( ) );
 	}
-	return std::make_shared < StatementList > ( list );
+	return std::make_shared < StatementList > ( std::move ( list ) );
 }
 
 void Parser::out_redirect_file ( std::shared_ptr < StatementList > & list ) {
@@ -286,7 +286,7 @@ void Parser::out_redirect ( std::shared_ptr < StatementList > & list ) {
 		match ( cli::Lexer::TokenType::DOLAR_SIGN );
 		std::unique_ptr < Arg > name = arg ( );
 		list->append ( std::make_unique < ResultVariableStatement > ( std::move ( name ) ) );
-	} else if ( check ( cli::Lexer::TokenType::EOS ) ) {
+	} else if ( check ( cli::Lexer::TokenType::EOS, cli::Lexer::TokenType::SEMICOLON_SIGN ) ) {
 		return;
 	} else {
 		out_redirect_file ( list );
@@ -297,7 +297,7 @@ void Parser::result ( std::shared_ptr < StatementList > & list ) {
 	if ( check ( cli::Lexer::TokenType::OUT_REDIRECT ) ) {
 		match ( cli::Lexer::TokenType::OUT_REDIRECT );
 		out_redirect ( list );
-	} else if ( check ( cli::Lexer::TokenType::EOS ) ) {
+	} else if ( check ( cli::Lexer::TokenType::EOS, cli::Lexer::TokenType::SEMICOLON_SIGN ) ) {
 		list->append ( std::make_unique < ResultPrintStatement > ( ) );
 	} else {
 		return;
@@ -359,40 +359,46 @@ std::unique_ptr < Command > Parser::introspect_command ( ) {
 	}
 }
 
-std::unique_ptr < Command > Parser::parse ( ) {
+std::unique_ptr < CommandList > Parser::parse ( ) {
+	ext::vector < std::unique_ptr < Command > > list;
+	list.emplace_back ( command ( ) );
+	while ( check ( cli::Lexer::TokenType::SEMICOLON_SIGN ) ) {
+		match ( cli::Lexer::TokenType::SEMICOLON_SIGN );
+		list.emplace_back ( command ( ) );
+	}
+	match ( cli::Lexer::TokenType::EOS );
+	return std::make_unique < CommandList > ( std::move ( list ) );
+}
+
+std::unique_ptr < Command > Parser::command ( ) {
 	if ( check_nonreserved_kw ( "execute" ) ) {
 		match_nonreserved_kw ( "execute" );
 		std::shared_ptr < StatementList > res = statement_list ( );
 		result ( res );
-		match ( cli::Lexer::TokenType::EOS );
 		return std::make_unique < ExecuteCommand > ( res );
 	} else if ( check_nonreserved_kw ( "quit" ) ) {
 		match_nonreserved_kw ( "quit" );
 
 		std::shared_ptr < StatementList > res;
-		if ( ! check ( cli::Lexer::TokenType::EOS ) )
+		if ( ! check ( cli::Lexer::TokenType::EOS, cli::Lexer::TokenType::SEMICOLON_SIGN ) )
 			res = statement_list ( );
 
-		match ( cli::Lexer::TokenType::EOS );
 		return std::make_unique < QuitCommand > ( res );
 	} else if ( check_nonreserved_kw ( "exit" ) ) {
 		match_nonreserved_kw ( "exit" );
 
 		std::shared_ptr < StatementList > res;
-		if ( ! check ( cli::Lexer::TokenType::EOS ) )
+		if ( ! check ( cli::Lexer::TokenType::EOS, cli::Lexer::TokenType::SEMICOLON_SIGN ) )
 			res = statement_list ( );
 
-		match ( cli::Lexer::TokenType::EOS );
 		return std::make_unique < QuitCommand > ( res );
 	} else if ( check_nonreserved_kw ( "help" ) ) {
 		match_nonreserved_kw ( "help" );
 		std::unique_ptr < cli::Arg > command = optional_arg ( );
-		match ( cli::Lexer::TokenType::EOS );
 		return std::make_unique < HelpCommand > ( std::move ( command ) );
 	} else if ( check_nonreserved_kw ( "introspect" ) ) {
 		match_nonreserved_kw ( "introspect" );
 		std::unique_ptr < Command > command = introspect_command ( );
-		match ( cli::Lexer::TokenType::EOS );
 		return command;
 	} else if ( check_nonreserved_kw ( "set" ) ) {
 		match_nonreserved_kw ( "set" );
@@ -400,19 +406,16 @@ std::unique_ptr < Command > Parser::parse ( ) {
 		match ( cli::Lexer::TokenType::INTEGER, cli::Lexer::TokenType::IDENTIFIER );
 		std::string value = getTokenValue ( );
 		match ( cli::Lexer::TokenType::INTEGER, cli::Lexer::TokenType::IDENTIFIER, cli::Lexer::TokenType::STRING );
-		match ( cli::Lexer::TokenType::EOS );
 		return std::make_unique < SetCommand > ( std::move ( param ), std::move ( value ) );
 	} else if ( check_nonreserved_kw ( "load" ) ) {
 		match_nonreserved_kw ( "load" );
 		std::string libraryName = getTokenValue ( );
 		match ( cli::Lexer::TokenType::INTEGER, cli::Lexer::TokenType::IDENTIFIER, cli::Lexer::TokenType::STRING );
-		match ( cli::Lexer::TokenType::EOS );
 		return std::make_unique < LoadCommand > ( std::move ( libraryName ) );
 	} else if ( check_nonreserved_kw ( "unload" ) ) {
 		match_nonreserved_kw ( "unload" );
 		std::string libraryName = getTokenValue ( );
 		match ( cli::Lexer::TokenType::INTEGER, cli::Lexer::TokenType::IDENTIFIER, cli::Lexer::TokenType::STRING );
-		match ( cli::Lexer::TokenType::EOS );
 		return std::make_unique < UnloadCommand > ( std::move ( libraryName ) );
 	} else if ( check ( cli::Lexer::TokenType::EOT ) ) {
 		return std::make_unique < QuitCommand > ( nullptr );
diff --git a/alib2cli/src/parser/Parser.h b/alib2cli/src/parser/Parser.h
index 3e5695c4b1..d0f63a0cb7 100644
--- a/alib2cli/src/parser/Parser.h
+++ b/alib2cli/src/parser/Parser.h
@@ -8,7 +8,7 @@
 #include <ast/options/TypeOption.h>
 #include <ast/options/CategoryOption.h>
 
-#include <command/Command.h>
+#include <command/CommandList.h>
 
 #include <ast/statements/StatementList.h>
 
@@ -152,7 +152,9 @@ public:
 
 	std::unique_ptr < Command > introspect_command ( );
 
-	std::unique_ptr < Command > parse ( );
+	std::unique_ptr < Command > command ( );
+
+	std::unique_ptr < CommandList > parse ( );
 
 };
 
-- 
GitLab