diff --git a/alib2cli/src/ast/command/WhileCommand.h b/alib2cli/src/ast/command/WhileCommand.h new file mode 100644 index 0000000000000000000000000000000000000000..0d77e62b625a361df97e80a09d2d6870ec17f939 --- /dev/null +++ b/alib2cli/src/ast/command/WhileCommand.h @@ -0,0 +1,38 @@ +#ifndef _CLI_WHILE_COMMAND_H_ +#define _CLI_WHILE_COMMAND_H_ + +#include <ast/Command.h> +#include <environment/Environment.h> +#include <ast/Statement.h> +#include <common/CastHelper.h> + +namespace cli { + +class WhileCommand : public Command { + std::unique_ptr < Expression > m_condition; + std::unique_ptr < Command > m_body; + +public: + WhileCommand ( std::unique_ptr < Expression > condition, std::unique_ptr < Command > body ) : m_condition ( std::move ( condition ) ), m_body ( std::move ( body ) ) { + } + + CommandResult run ( Environment & environment ) const override { + CommandResult res = cli::CommandResult::OK; + while ( res == cli::CommandResult::OK ) { + std::shared_ptr < abstraction::Value > conditionResult = m_condition->translateAndEval ( environment ); + + std::shared_ptr < abstraction::Value > castedResult = abstraction::CastHelper::eval ( environment, conditionResult, "bool" ); + + if ( ! std::static_pointer_cast < abstraction::ValueHolderInterface < bool > > ( castedResult )->getValue ( ) ) + break; + + res = m_body->run ( environment ); + } + + return res; + } +}; + +} /* namespace cli */ + +#endif /* _CLI_WHILE_COMMAND_H_ */ diff --git a/alib2cli/src/parser/Parser.cpp b/alib2cli/src/parser/Parser.cpp index 39ac763c9fb59bd73bfa13f46ecd05d0591c8cd5..4082f807cede0af8c0ef2eeed4ac27d4bd88ca20 100644 --- a/alib2cli/src/parser/Parser.cpp +++ b/alib2cli/src/parser/Parser.cpp @@ -34,6 +34,7 @@ #include <ast/command/EvalCommand.h> #include <ast/command/InterpretCommand.h> #include <ast/command/IfCommand.h> +#include <ast/command/WhileCommand.h> #include <ast/command/ReturnCommand.h> #include <ast/expression/BatchExpression.h> @@ -369,7 +370,7 @@ std::unique_ptr < CommandList > Parser::block ( ) { } std::unique_ptr < Command > Parser::semicolon_command ( ) { - bool semicolonFreeCommand = check_nonreserved_kw ( "begin", "if" ); + bool semicolonFreeCommand = check_nonreserved_kw ( "begin", "if", "while" ); std::unique_ptr < Command > res = command ( ); if ( ! semicolonFreeCommand ) match ( cli::Lexer::TokenType::SEMICOLON_SIGN ); @@ -510,6 +511,18 @@ std::unique_ptr < Command > Parser::command ( ) { } return std::make_unique < IfCommand > ( std::move ( condition ), std::move ( thenBranch ), std::move ( elseBranch ) ); + } else if ( check_nonreserved_kw ( "while" ) ) { + if ( globalScope ( ) ) + throw exception::CommonException ( "Statement not available in global scope." ); + match_nonreserved_kw ( "while" ); + match ( cli::Lexer::TokenType::LEFT_PAREN ); + std::unique_ptr < Expression > condition = expression_or_batch ( ); + match ( cli::Lexer::TokenType::RIGHT_PAREN ); + + match_nonreserved_kw ( "do" ); + std::unique_ptr < Command > body = semicolon_command ( ); + + return std::make_unique < WhileCommand > ( std::move ( condition ), std::move ( body ) ); } else { throw exception::CommonException ( "Mismatched set " + ext::to_string ( getCheckOptions ( ) ) + " while expanding parse rule. Token is " + ( ( std::string ) m_current ) + "." ); }