Skip to content

Commit

Permalink
add builtin function : context_stack() -> list(string)
Browse files Browse the repository at this point in the history
  • Loading branch information
chloro-pn committed Jun 6, 2024
1 parent 884f3fb commit db5a019
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 28 deletions.
4 changes: 3 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@
* 支持新的数据类型 Map
* 支持函数重载
* 支持注册函数的包管理
* Output to json format
* [done] Output to json format
* for语句支持变量定义

6 changes: 4 additions & 2 deletions example/register_cpp_function.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ auto my_cpp_func_check(const std::vector<std::unique_ptr<wamon::Type>>& params_t
return wamon::TypeFactory<int>::Get();
}

auto my_cpp_func(std::vector<std::shared_ptr<wamon::Variable>>&& params) -> std::shared_ptr<wamon::Variable> {
auto my_cpp_func(wamon::Interpreter&, std::vector<std::shared_ptr<wamon::Variable>>&& params)
-> std::shared_ptr<wamon::Variable> {
auto len = wamon::AsStringVariable(params[0])->GetValue().size();
return std::make_shared<wamon::IntVariable>(static_cast<int>(len), wamon::Variable::ValueCategory::RValue, "");
}

auto my_type_cpp_func(std::vector<std::shared_ptr<wamon::Variable>>&& params) -> std::shared_ptr<wamon::Variable> {
auto my_type_cpp_func(wamon::Interpreter&, std::vector<std::shared_ptr<wamon::Variable>>&& params)
-> std::shared_ptr<wamon::Variable> {
return std::make_shared<wamon::IntVariable>(12138, wamon::Variable::ValueCategory::RValue, "");
}

Expand Down
3 changes: 2 additions & 1 deletion include/wamon/builtin_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ namespace wamon {
class Type;
class FuncCallExpr;
class TypeChecker;
class Interpreter;

class BuiltinFunctions {
public:
using HandleType = std::function<std::shared_ptr<Variable>(std::vector<std::shared_ptr<Variable>>&&)>;
using HandleType = std::function<std::shared_ptr<Variable>(Interpreter&, std::vector<std::shared_ptr<Variable>>&&)>;
using CheckType = std::function<std::unique_ptr<Type>(const std::vector<std::unique_ptr<Type>>& params_type)>;

BuiltinFunctions();
Expand Down
33 changes: 25 additions & 8 deletions include/wamon/interpreter.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <functional>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
Expand All @@ -18,7 +19,6 @@ namespace wamon {
enum class RuntimeContextType {
Global,
Function,
Callable,
Method,
FOR,
IF,
Expand Down Expand Up @@ -75,15 +75,18 @@ struct RuntimeContext {
RuntimeContext() = default;

RuntimeContext(const RuntimeContext&) = delete;
RuntimeContext(RuntimeContext&& other) : type_(other.type_), symbol_table_(std::move(other.symbol_table_)) {}
RuntimeContext(RuntimeContext&& other)
: type_(other.type_), desc_(std::move(other.desc_)), symbol_table_(std::move(other.symbol_table_)) {}
RuntimeContext& operator=(const RuntimeContext& other) = delete;
RuntimeContext& operator=(RuntimeContext&& other) {
type_ = other.type_;
desc_ = other.desc_;
symbol_table_ = std::move(other.symbol_table_);
return *this;
}

RuntimeContextType type_;
std::string desc_;
std::unordered_map<std::string, std::shared_ptr<Variable>> symbol_table_;
};

Expand All @@ -101,14 +104,17 @@ class Interpreter {

private:
template <RuntimeContextType type>
void EnterContext() {
void EnterContext(const std::string& desc) {
auto rs = std::make_unique<RuntimeContext>();
rs->type_ = type;
rs->desc_ = desc;
runtime_stack_.push_back(std::move(rs));
}

void LeaveContext() {
assert(runtime_stack_.empty() == false);
if (runtime_stack_.empty()) {
throw WamonException("Interpreter.LeaveContext error, empty");
}
runtime_stack_.pop_back();
}

Expand All @@ -120,6 +126,17 @@ class Interpreter {
return runtime_stack_.back().get();
}

std::vector<std::string> GetContextStack() const {
std::vector<std::string> ret;
for (auto it = runtime_stack_.rbegin(); it != runtime_stack_.rend(); ++it) {
if ((*it)->type_ == RuntimeContextType::Function || (*it)->type_ == RuntimeContextType::Method) {
ret.push_back((*it)->desc_);
}
}
ret.push_back(package_context_.desc_);
return ret;
}

std::shared_ptr<Variable> Alloc(const std::unique_ptr<Type>& type, std::vector<std::shared_ptr<Variable>>&& params);

void Dealloc(std::shared_ptr<Variable> v);
Expand All @@ -134,7 +151,7 @@ class Interpreter {
auto override_name = OperatorDef::CreateName(op, {operand...});
auto func_def = GetPackageUnit().FindFunction(override_name);
if (func_def != nullptr) {
EnterContext<RuntimeContextType::Function>();
EnterContext<RuntimeContextType::Function>(func_def->GetFunctionName());
ret = CallFunction(func_def, {operand...});
LeaveContext();
return ret;
Expand Down Expand Up @@ -179,8 +196,8 @@ class Interpreter {
if (func == nullptr) {
throw WamonException("CallFunction error, {} not exist", builtin_name);
}
EnterContext<RuntimeContextType::Function>();
auto ret = (*func)(std::move(params));
EnterContext<RuntimeContextType::Function>(builtin_name);
auto ret = (*func)(*this, std::move(params));
LeaveContext();
return ret->IsRValue() ? std::move(ret) : ret->Clone();
}
Expand All @@ -207,7 +224,7 @@ class Interpreter {
std::shared_ptr<Variable> CallMethod(std::shared_ptr<Variable> obj, const std::string& method_name,
std::vector<std::shared_ptr<Variable>>&& params) {
auto method = InnerTypeMethod::Instance().Get(obj, method_name);
EnterContext<RuntimeContextType::Method>();
EnterContext<RuntimeContextType::Method>(obj->GetTypeInfo() + "::" + method_name);
auto ret = method(obj, std::move(params), pu_);
LeaveContext();
return ret->IsRValue() ? std::move(ret) : ret->Clone();
Expand Down
1 change: 1 addition & 0 deletions include/wamon/variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,7 @@ requires WAMON_SUPPORT_TOVAR<std::remove_cvref_t<T>> std::shared_ptr<Variable> T

inline std::shared_ptr<Variable> ToVar(std::shared_ptr<Variable> v) { return v; }

// todo : 万能引用 + type trait
template <typename EleType>
std::shared_ptr<Variable> ToVar(std::vector<EleType>&& v) {
auto ret = VariableFactoryShared(TypeFactory<std::vector<EleType>>::Get(), Variable::ValueCategory::LValue, "");
Expand Down
12 changes: 6 additions & 6 deletions src/ast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ std::shared_ptr<Variable> DeallocExpr::Calculate(Interpreter& interpreter) {
}

ExecuteResult BlockStmt::Execute(Interpreter& interpreter) {
interpreter.EnterContext<RuntimeContextType::Block>();
interpreter.EnterContext<RuntimeContextType::Block>("block");
for (auto& each : block_) {
ExecuteResult step = each->Execute(interpreter);
if (step.state_ != ExecuteState::Next) {
Expand All @@ -198,7 +198,7 @@ ExecuteResult BlockStmt::Execute(Interpreter& interpreter) {
}

ExecuteResult ForStmt::Execute(Interpreter& interpreter) {
interpreter.EnterContext<RuntimeContextType::FOR>();
interpreter.EnterContext<RuntimeContextType::FOR>("for");
init_->Calculate(interpreter);
while (true) {
auto v = check_->Calculate(interpreter);
Expand Down Expand Up @@ -228,7 +228,7 @@ ExecuteResult IfStmt::Execute(Interpreter& interpreter) {
ExecuteResult er = ExecuteResult::Next();
bool executed = false;
if (check == true) {
interpreter.EnterContext<RuntimeContextType::IF>();
interpreter.EnterContext<RuntimeContextType::IF>("if");
executed = true;
er = if_block_->Execute(interpreter);
}
Expand All @@ -237,15 +237,15 @@ ExecuteResult IfStmt::Execute(Interpreter& interpreter) {
v = each.elif_check->Calculate(interpreter);
check = AsBoolVariable(v)->GetValue();
if (check == true) {
interpreter.EnterContext<RuntimeContextType::ELSE>();
interpreter.EnterContext<RuntimeContextType::ELSE>("elif");
executed = true;
er = each.elif_block->Execute(interpreter);
break;
}
}
}
if (executed == false && else_block_ != nullptr) {
interpreter.EnterContext<RuntimeContextType::ELSE>();
interpreter.EnterContext<RuntimeContextType::ELSE>("else");
executed = true;
er = else_block_->Execute(interpreter);
}
Expand All @@ -260,7 +260,7 @@ ExecuteResult IfStmt::Execute(Interpreter& interpreter) {
}

ExecuteResult WhileStmt::Execute(Interpreter& interpreter) {
interpreter.EnterContext<RuntimeContextType::WHILE>();
interpreter.EnterContext<RuntimeContextType::WHILE>("while");
while (true) {
auto v = check_->Calculate(interpreter);
bool check = AsBoolVariable(v)->GetValue();
Expand Down
26 changes: 24 additions & 2 deletions src/builtin_functions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
#include "nlohmann/json.hpp"
#include "wamon/ast.h"
#include "wamon/exception.h"
#include "wamon/interpreter.h"
#include "wamon/type_checker.h"
#include "wamon/variable.h"

namespace wamon {

static auto _print(std::vector<std::shared_ptr<Variable>>&& params) -> std::shared_ptr<Variable> {
static auto _print(Interpreter& ip, std::vector<std::shared_ptr<Variable>>&& params) -> std::shared_ptr<Variable> {
nlohmann::json j;
for (auto& each : params) {
j.push_back(each->Print());
Expand All @@ -19,7 +21,18 @@ static auto _print(std::vector<std::shared_ptr<Variable>>&& params) -> std::shar
return std::make_shared<VoidVariable>();
}

static auto _to_string(std::vector<std::shared_ptr<Variable>>&& params) -> std::shared_ptr<Variable> {
static auto _context_stack(Interpreter& ip, std::vector<std::shared_ptr<Variable>>&& params)
-> std::shared_ptr<Variable> {
assert(params.empty());
auto descs = ip.GetContextStack();
// global and context_stack self at least
assert(descs.size() >= 2);
auto it = descs.begin();
descs.erase(it);
return ToVar(std::move(descs));
}

static auto _to_string(Interpreter& ip, std::vector<std::shared_ptr<Variable>>&& params) -> std::shared_ptr<Variable> {
assert(params.size() == 1);
auto& v = params[0];
std::string result;
Expand All @@ -38,12 +51,20 @@ static auto _to_string(std::vector<std::shared_ptr<Variable>>&& params) -> std::
static void register_builtin_handles(std::unordered_map<std::string, BuiltinFunctions::HandleType>& handles) {
handles["print"] = _print;
handles["to_string"] = _to_string;
handles["context_stack"] = _context_stack;
}

static auto _print_check(const std::vector<std::unique_ptr<Type>>& params_type) -> std::unique_ptr<Type> {
return TypeFactory<void>::Get();
}

static auto _context_stack_check(const std::vector<std::unique_ptr<Type>>& params_type) -> std::unique_ptr<Type> {
if (params_type.size() != 0) {
throw WamonException("context_stack type_check error, params_type.size() == {}", params_type.size());
}
return TypeFactory<std::vector<std::string>>::Get();
}

static auto _to_string_check(const std::vector<std::unique_ptr<Type>>& params_type) -> std::unique_ptr<Type> {
if (params_type.size() != 1) {
throw WamonException("to_string type_check error ,params_type.size() == {}", params_type.size());
Expand All @@ -58,6 +79,7 @@ static auto _to_string_check(const std::vector<std::unique_ptr<Type>>& params_ty
static void register_builtin_checks(std::unordered_map<std::string, BuiltinFunctions::CheckType>& checks) {
checks["print"] = _print_check;
checks["to_string"] = _to_string_check;
checks["context_stack"] = _context_stack_check;
}

BuiltinFunctions::BuiltinFunctions() {
Expand Down
5 changes: 3 additions & 2 deletions src/interpreter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace wamon {

Interpreter::Interpreter(PackageUnit& pu) : pu_(pu) {
package_context_.type_ = RuntimeContextType::Global;
package_context_.desc_ = "global";
// 将packge unit中的包变量进行求解并插入包符号表中
const auto& vars = pu_.GetGlobalVariDefStmt();
for (const auto& each : vars) {
Expand Down Expand Up @@ -47,7 +48,7 @@ void Interpreter::Dealloc(std::shared_ptr<Variable> v) {
std::shared_ptr<Variable> Interpreter::CallFunction(const FunctionDef* function_def,
std::vector<std::shared_ptr<Variable>>&& params) {
assert(function_def != nullptr);
EnterContext<RuntimeContextType::Function>();
EnterContext<RuntimeContextType::Function>(function_def->GetFunctionName());
auto param_name = function_def->GetParamList().begin();
auto capture_name = function_def->GetCaptureIds().begin();
for (auto param : params) {
Expand Down Expand Up @@ -105,7 +106,7 @@ std::shared_ptr<Variable> Interpreter::CallMethod(std::shared_ptr<Variable> obj,
if (method_def->IsDeclaration()) {
throw WamonException("Interpreter.CallMethod error, method {} is declaration", method_def->GetMethodName());
}
EnterContext<RuntimeContextType::Method>();
EnterContext<RuntimeContextType::Method>(obj->GetTypeInfo() + "::" + method_def->GetMethodName());
auto param_name = method_def->GetParamList().begin();
for (auto param : params) {
assert(param_name != method_def->GetParamList().end());
Expand Down
9 changes: 4 additions & 5 deletions src/package_unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ namespace wamon {
PackageUnit PackageUnit::_MergePackageUnits(std::vector<PackageUnit>&& packages) {
PackageUnit result; // name == ""; import_package == empty; lambda_count == 0;
for (auto it = packages.begin(); it != packages.end(); ++it) {
auto package_name = it->package_name_;
result.AddPackageImports(package_name, it->import_packages_);
result.AddPackageImports(it->GetName(), it->GetImportPackage());
for (auto var_define = it->var_define_.begin(); var_define != it->var_define_.end(); ++var_define) {
auto var_name = (*var_define)->GetVarName();
(*var_define)->SetVarName(package_name + "$" + var_name);
(*var_define)->SetVarName(it->GetName() + "$" + var_name);
result.AddVarDef(std::move(*var_define));
}

Expand All @@ -22,14 +21,14 @@ PackageUnit PackageUnit::_MergePackageUnits(std::vector<PackageUnit>&& packages)
// 运算符重载不能添加前缀,因为相同类型的重载即便在不同包,也不应该重复定义。
// lambda函数不添加前缀,因为构造lambda名字的时候已经添加了包名作为后缀
// todo:支持一个包可以由多个PackageUnit合并得到的情况下,lambda的名字可能会冲突
func_define->second->SetFunctionName(package_name + "$" + func_name);
func_define->second->SetFunctionName(it->GetName() + "$" + func_name);
}
result.AddFuncDef(std::move(func_define->second));
}

for (auto struct_define = it->structs_.begin(); struct_define != it->structs_.end(); ++struct_define) {
auto struct_name = struct_define->first;
struct_define->second->SetStructName(package_name + "$" + struct_name);
struct_define->second->SetStructName(it->GetName() + "$" + struct_name);
result.AddStructDef(std::move(struct_define->second));
}
}
Expand Down
62 changes: 62 additions & 0 deletions test/builtin_function_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "gtest/gtest.h"
#include "wamon/builtin_functions.h"
#include "wamon/interpreter.h"
#include "wamon/parser.h"
#include "wamon/scanner.h"
#include "wamon/static_analyzer.h"
#include "wamon/type_checker.h"
#include "wamon/variable.h"

TEST(builtin_function, context_stack) {
using namespace wamon;
std::string script = R"(
package main;
let cs : list(string) = ();
struct ms {
int a;
}
method ms {
func func_method() -> void {
call func2:();
return;
}
}
func func1() -> void {
let tmp : ms = (2);
call tmp:func_method();
return;
}
func func2() -> void {
call func3:();
return;
}
func func3() -> void {
{
let lmd: f(()->void) = lambda [] () -> void { cs = call context_stack:(); return; };
call lmd:();
}
return;
}
)";
Scanner scan;
auto tokens = scan.Scan(script);
auto pu = Parse(tokens);
pu = MergePackageUnits(std::move(pu));

TypeChecker tc(pu);
std::string reason;
EXPECT_EQ(tc.CheckAll(reason), true);

Interpreter ip(pu);
ip.CallFunctionByName("main$func1", {});
auto v = ip.FindVariableById("main$cs");
std::string dump_info =
R"_(["__lambda_0main","main$func3","main$func2","main$ms::func_method","main$func1","global"])_";
EXPECT_EQ(v->Print().dump(), dump_info);
}
3 changes: 2 additions & 1 deletion test/interpreter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,8 @@ TEST(interpreter, register_cpp_function) {
}
return wamon::TypeFactory<int>::Get();
},
[](std::vector<std::shared_ptr<wamon::Variable>>&& params) -> std::shared_ptr<wamon::Variable> {
[](wamon::Interpreter&,
std::vector<std::shared_ptr<wamon::Variable>>&& params) -> std::shared_ptr<wamon::Variable> {
auto len = wamon::AsStringVariable(params[0])->GetValue().size();
return std::make_shared<wamon::IntVariable>(static_cast<int>(len), wamon::Variable::ValueCategory::RValue, "");
});
Expand Down

0 comments on commit db5a019

Please sign in to comment.