Add return statement to batch runner 02/170002/3
authorPaweł Stawicki <p.stawicki@samsung.com>
Mon, 12 Feb 2018 18:08:01 +0000 (19:08 +0100)
committerPaweł Stawicki <p.stawicki@samsung.com>
Tue, 13 Feb 2018 12:10:29 +0000 (13:10 +0100)
Change-Id: If2b055e67ffee1e286c4a18554a25222a7dd904f

src/batch/BatchRunner.cpp
src/batch/Evaluator.cpp
src/batch/Evaluator.hpp
src/batch/Lexer.cpp
src/batch/Parser.cpp
src/batch/ReturnValue.hpp [new file with mode: 0644]
tests/no-ui-scenarios/BatchExecTests.cpp

index 896be30..80baa8e 100644 (file)
@@ -28,6 +28,7 @@
 #include "../DoneCallback.hpp"
 #include "../DBus.hpp"
 #include "Dlog.hpp"
+#include "ReturnValue.hpp"
 
 #include <mutex>
 #include <chrono>
@@ -946,6 +947,8 @@ static void threadFunc(StatPtr result, std::unique_ptr<BatchExecutor> exec, std:
                try {
                        result->evaluate();
                        exec->outputStream() << "evaluation successed\n";
+               } catch (ReturnValue &r) {
+                       exec->outputStream() << "script returned: " << r.getResult();
                } catch (EvaluationFailure &e) {
                        if (e.hasLocation())
                                exec->outputStream() << e.location().toString() << ": ";
index 4fd9e4b..2c037fb 100644 (file)
@@ -18,6 +18,7 @@
 #include "EvaluationValue.hpp"
 #include "EvaluationContext.hpp"
 #include "Lexer.hpp"
+#include "ReturnValue.hpp"
 #include "../UniversalSwitchLog.hpp"
 
 #include <string>
@@ -504,7 +505,13 @@ void FunctionEvaluator::evaluateImpl() const
                        {
                                ctx.setVariable(argNames[i], args[i]);
                        }
-                       codeBlock->evaluate();
+                       try
+                       {
+                               codeBlock->evaluate();
+                       } catch (ReturnValue &r)
+                       {
+                               return r.getResult();
+                       }
                        return {};
                }});
 }
@@ -519,6 +526,21 @@ void FunctionEvaluator::printSelfInfo(std::ostringstream &os, unsigned int depth
        codeBlock->printSelfInfo(os, depth + 1);
 }
 
+ReturnEvaluator::ReturnEvaluator(TokenLocation location_, ExprPtr result):
+       StatementEvaluator(location_), result(std::move(result))  {}
+
+void ReturnEvaluator::evaluateImpl() const
+{
+       auto v = result ? result->evaluate() : EvaluationValue{};
+       throw ReturnValue{v};
+}
+
+void ReturnEvaluator::printSelfInfo(std::ostringstream &os, unsigned int depth) const
+{
+       printLocationAndIndent(os, location(), depth) << "return ";
+       result->printSelfInfo(os, depth + 1);
+}
+
 
 ExpressionAsStatementEvaluator::ExpressionAsStatementEvaluator(TokenLocation tokenLocation, ExprPtr expr) :
        StatementEvaluator(tokenLocation), expr(std::move(expr)) { }
index d42630e..2bdf098 100644 (file)
@@ -442,7 +442,7 @@ public:
 };
 
 /**
- * @brief Type representing group of statements, evaluated in order
+ * @brief Type representing execution of function definition
  */
 class FunctionEvaluator : public StatementEvaluator
 {
@@ -456,4 +456,17 @@ protected:
        void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
 };
 
+/**
+ * @brief Type representing execution of return statement
+ */
+class ReturnEvaluator : public StatementEvaluator
+{
+       ExprPtr result;
+public:
+       ReturnEvaluator(TokenLocation location_, ExprPtr result);
+protected:
+       void evaluateImpl() const override;
+       void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
+};
+
 #endif
index 8d023a4..f30c3ac 100644 (file)
@@ -78,7 +78,7 @@ std::string toString(TokenType t)
  * If found, resulting token will be KEYWORD rather than IDENTIFIER.
  */
 static std::unordered_set<std::string> keywords {
-       "true", "false", "def"
+       "true", "false", "def", "return"
 };
 
 /**
index 4fcebc7..7a28f7d 100644 (file)
@@ -164,6 +164,19 @@ class Parser
                ++index;
                return true;
        }
+
+       /**
+        * @brief Returns true, if token of type t can be successfully consumed
+        *
+        * Returns true, if current token's type matches type t.
+        * Current position is not modified.
+        */
+       bool canConsume(TokenType t)
+       {
+               if (t == TokenType::END_OF_LINE && index >= tokens.size()) return true;
+               return index < tokens.size() && tokens[index].type() == t;
+       }
+
        /**
         * @brief Returns true, if token of text t can be successfully consumed
         *
@@ -589,6 +602,23 @@ class Parser
        }
 
        /**
+        * @brief Tries to parse return statement
+        */
+       StatPtr parseReturn()
+       {
+               auto location = tokens[index].location();
+               if (!consume("return"))
+                       return {};
+               ExprPtr expression;
+               if (!canConsume(TokenType::END_OF_LINE)) {
+                       expression = parseExpr();
+                       if (!expression)
+                               return {};
+               }
+               return std::make_shared<ReturnEvaluator>(std::move(location), std::move(expression));
+       }
+
+       /**
         * @brief Tries to parse single line of code, which is suppoused to be expression
         *
         * At this point no statements are supported, but this might change
@@ -602,6 +632,8 @@ class Parser
                        line = parseBlock();
                } else if (tokens[index].text() == "def") {
                        line = parseFunction();
+               } else if (tokens[index].text() == "return") {
+                       line = parseReturn();
                } else {
                        auto expr = parseExpr();
                        if (!expr) return {};
diff --git a/src/batch/ReturnValue.hpp b/src/batch/ReturnValue.hpp
new file mode 100644 (file)
index 0000000..6d5357d
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RETURN_VALUE_HPP
+#define RETURN_VALUE_HPP
+
+#include "EvaluationValue.hpp"
+
+/**
+ * @brief Type representing returned value
+ *
+ * ReturnValue will be thrown like an exception,
+ * and should be catched in its function evaluator
+ */
+class ReturnValue
+{
+public:
+       ReturnValue(EvaluationValue result): result(result) {}
+       EvaluationValue getResult()
+       {
+               return result;
+       }
+
+private:
+       EvaluationValue result;
+};
+
+
+#endif //RETURN_VALUE_HPP
index edb5566..acd3152 100644 (file)
@@ -20,6 +20,7 @@
 #include "batch/EvaluationContext.hpp"
 #include "batch/Evaluator.hpp"
 #include "batch/BatchRunner.hpp"
+#include "batch/ReturnValue.hpp"
 #include <sstream>
 
 using VarsType = std::unordered_map<std::string, EvaluationValue>;
@@ -534,7 +535,7 @@ TEST_F(ScriptTest, Import)
                        std::get<1>(val) = a2;
                        std::get<2>(val) = a3;
                        std::get<3>(val) = a4;
-                       funcCount++;
+                       ++funcCount;
                        return {};
                }, {
                        { "a1" },
@@ -642,7 +643,7 @@ TEST_F(ScriptTest, functionDefinition)
                [&](int a1, int a2) -> EvaluationValue {
                        std::get<0>(val) = a1;
                        std::get<1>(val) = a2;
-                       funcCount++;
+                       ++funcCount;
                        return {};
                }, {
                        { "a1" },
@@ -797,11 +798,69 @@ TEST_F(ScriptTest, functionDefinition)
 
        ASSERT_THROW(
                execute("def myFunc(a) { }\n"
-                               "myFunc()", ec, true);
+                               "myFunc()", ec, true)
                , EvaluationFailure);
 
 }
 
+TEST_F(ScriptTest, functionReturn)
+{
+       TestBatchExecutor exec;
+       EvaluationContext ec{ exec };
+
+       exec.variables["sum"] = EvaluationValueFunction {
+               [&](int a1, int a2) -> EvaluationValue {
+                       return a1 + a2;
+               }, {
+                       { "a1" },
+                       { "a2" },
+               } };
+
+       ASSERT_NO_THROW(
+               executeWithInfo(
+                       "def myFunc() {\n"
+                       "  return\n"
+                       "}\n"
+                       "myFunc()\n", ec)
+       );
+
+       ASSERT_NO_THROW(
+               executeWithInfo(
+                       "def myFunc() {\n"
+                       "  return 5\n"
+                       "}\n"
+                       "w = myFunc()\n"
+                       "assert(w == 5)", ec)
+       );
+       ASSERT_NO_THROW(
+               executeWithInfo(
+                       "def myFunc() {\n"
+                       "  return sum(5,7)\n"
+                       "}\n"
+                       "w = myFunc()\n"
+                       "assert(w == 12)", ec)
+       );
+       ASSERT_NO_THROW(
+               executeWithInfo(
+                       "def myFunc(a) {\n"
+                       "  def myFunc2(a) {\n"
+                       "    return sum(a, 8)\n"
+                       "  }\n"
+                       "  b = myFunc2(a)\n"
+                       "  return sum(b, 17)\n"
+                       "}\n"
+                       "w = myFunc(3)\n"
+                       "assert(w == 28)", ec)
+       );
+
+       ASSERT_THROW(execute("return", ec, false), ReturnValue);
+       ASSERT_THROW(execute("return 12", ec, false), ReturnValue);
+       ASSERT_THROW(execute(
+                                        "{\n"
+                                        "  return 12\n"
+                                        "}\n", ec, false), ReturnValue);
+}
+
 int main(int argc, char *argv[])
 {
        try {