#include "../DoneCallback.hpp"
#include "../DBus.hpp"
#include "Dlog.hpp"
+#include "ReturnValue.hpp"
#include <mutex>
#include <chrono>
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() << ": ";
#include "EvaluationValue.hpp"
#include "EvaluationContext.hpp"
#include "Lexer.hpp"
+#include "ReturnValue.hpp"
#include "../UniversalSwitchLog.hpp"
#include <string>
{
ctx.setVariable(argNames[i], args[i]);
}
- codeBlock->evaluate();
+ try
+ {
+ codeBlock->evaluate();
+ } catch (ReturnValue &r)
+ {
+ return r.getResult();
+ }
return {};
}});
}
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)) { }
};
/**
- * @brief Type representing group of statements, evaluated in order
+ * @brief Type representing execution of function definition
*/
class FunctionEvaluator : public StatementEvaluator
{
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
* 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;
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
*
}
/**
+ * @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
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 {};
--- /dev/null
+/*
+ * 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
#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>;
std::get<1>(val) = a2;
std::get<2>(val) = a3;
std::get<3>(val) = a4;
- funcCount++;
+ ++funcCount;
return {};
}, {
{ "a1" },
[&](int a1, int a2) -> EvaluationValue {
std::get<0>(val) = a1;
std::get<1>(val) = a2;
- funcCount++;
+ ++funcCount;
return {};
}, {
{ "a1" },
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 {