Introduce FunctionCall and way to register native functions

This commit is contained in:
mrkubax10 2024-08-18 14:40:41 +02:00
parent 4a1deea89e
commit f975cebeb5
7 changed files with 113 additions and 2 deletions

View File

@ -103,3 +103,35 @@ Value FunctionDefinition::eval(VM& vm) {
m_body->eval(vm);
return vm.get_return_value();
}
FunctionCall::FunctionCall(VM& vm, FunctionType func_type, unsigned address, std::vector<std::unique_ptr<Expression>> arguments) :
Expression(ValueType::VALUE_TYPE_VOID),
m_func_type(func_type),
m_address(address),
m_arguments(std::move(arguments))
{
switch(func_type) {
case FunctionType::FUNCTION_NORMAL:
// TODO
break;
case FunctionType::FUNCTION_NATIVE:
m_result_type = var_type_to_value_type(vm.get_native_function_by_address(address).m_result_type);
break;
}
}
Value FunctionCall::eval(VM& vm) {
std::vector<Value> argument_values;
argument_values.reserve(m_arguments.size());
for(std::unique_ptr<Expression>& arg : m_arguments)
argument_values.push_back(arg->eval(vm));
switch(m_func_type) {
case FunctionType::FUNCTION_NORMAL:
// TODO
break;
case FunctionType::FUNCTION_NATIVE:
return vm.get_native_function_by_address(m_address).m_func(vm, argument_values);
}
return Value{};
}

View File

@ -100,6 +100,18 @@ namespace polygun::server::as {
std::vector<VarType> m_argument_types;
std::unique_ptr<StatementBlock> m_body;
};
class FunctionCall final : public Expression {
public:
FunctionCall(VM& vm, FunctionType func_type, unsigned address, std::vector<std::unique_ptr<Expression>> arguments);
virtual Value eval(VM& vm) override;
private:
FunctionType m_func_type;
unsigned m_address;
std::vector<std::unique_ptr<Expression>> m_arguments;
};
}
#endif // POLYGUN_SERVER_AS_AST_HPP

View File

@ -27,5 +27,15 @@ SOFTWARE.
#include <algorithm>
polygun::server::as::ValueType polygun::server::as::get_wider_type(polygun::server::as::ValueType first, polygun::server::as::ValueType second) {
return static_cast<ValueType>(std::max(first, second));
return static_cast<ValueType>(std::max(first, second));
}
polygun::server::as::ValueType polygun::server::as::var_type_to_value_type(polygun::server::as::VarType var_type) {
if(var_type<=VarType::VAR_TYPE_BOOL)
return static_cast<ValueType>(var_type);
if(var_type<=VarType::VAR_TYPE_UINT64)
return ValueType::VALUE_TYPE_UINT;
if(var_type<=VarType::VAR_TYPE_INT64)
return ValueType::VALUE_TYPE_INT;
return ValueType::VALUE_TYPE_DOUBLE;
}

View File

@ -44,6 +44,7 @@ namespace polygun::server::as {
};
enum VarType {
VAR_TYPE_VOID,
VAR_TYPE_BOOL,
VAR_TYPE_UINT8,
VAR_TYPE_UINT16,
@ -57,7 +58,13 @@ namespace polygun::server::as {
VAR_TYPE_DOUBLE
};
enum FunctionType {
FUNCTION_NORMAL,
FUNCTION_NATIVE
};
ValueType get_wider_type(ValueType first, ValueType second);
ValueType var_type_to_value_type(VarType var_type);
template<typename T>
T value_as(const Value& value, ValueType type) {
switch(type) {

View File

@ -30,9 +30,26 @@ VM::VM(unsigned storage_size) :
m_storage_size(storage_size),
m_stack(new uint8_t[storage_size]),
m_stack_ptr(0),
m_return_value()
m_return_value(),
m_native_functions(),
m_native_function_addresses()
{}
VM::~VM() {
delete[] m_stack;
}
void VM::register_function(const std::string& name, VarType result_type, const std::vector<VarType>& argument_types, Value(*func)(VM&, const std::vector<Value>&)) {
m_native_function_addresses[name] = m_native_functions.size();
const NativeFunction native_function {
result_type,
argument_types,
func
};
m_native_functions.push_back(native_function);
}
const VM::NativeFunction& VM::get_native_function_by_address(unsigned address) {
assert(address<m_native_functions.size());
return m_native_functions[address];
}

View File

@ -27,6 +27,9 @@ SOFTWARE.
#include <cassert>
#include <cstdint>
#include <map>
#include <string>
#include <vector>
#include "server/as/value.hpp"
@ -37,11 +40,18 @@ namespace polygun::server::as {
LOCATION_STACK,
LOCATION_STATIC
};
struct NativeFunction {
VarType m_result_type;
std::vector<VarType> m_argument_types;
Value(*m_func)(VM&, const std::vector<Value>&);
};
public:
VM(unsigned storage_size);
~VM();
void register_function(const std::string& name, VarType result_type, const std::vector<VarType>& argument_types, Value(*func)(VM&, const std::vector<Value>&));
template<typename T>
void set_value_at(Location location, unsigned addr, T value) {
assert(addr<m_storage_size);
@ -68,12 +78,16 @@ namespace polygun::server::as {
}
unsigned get_stack_ptr() const { return m_stack_ptr; }
const Value& get_return_value() const { return m_return_value; }
const NativeFunction& get_native_function_by_address(unsigned address);
private:
unsigned m_storage_size;
uint8_t* m_stack;
unsigned m_stack_ptr;
Value m_return_value;
std::vector<NativeFunction> m_native_functions;
// Maps function name to index in std::vector above
std::map<std::string, unsigned> m_native_function_addresses;
};
}

View File

@ -39,6 +39,8 @@ SOFTWARE.
#include "common/math/rect3d.hpp"
#include "common/logger.hpp"
#include "common/world/chunk.hpp"
#include "server/as/ast.hpp"
#include "server/as/vm.hpp"
using namespace polygun::server;
@ -46,6 +48,11 @@ static const float DAY_TIME_INTERVAL = 10.0f*60.0f/65536.0f;
static Server* g_current_server = nullptr;
as::Value test_native_function(as::VM& vm, const std::vector<as::Value>& args) {
LOG_INFO("%d", args[0].i);
return as::Value{};
}
Server::Server(std::atomic<bool>* running_atomic, std::optional<unsigned short> port_override) :
m_config(),
m_running(running_atomic?running_atomic:new std::atomic<bool>),
@ -78,6 +85,18 @@ Server::Server(std::atomic<bool>* running_atomic, std::optional<unsigned short>
m_player_storage.load();
m_chunk_manager.load_map_from_file(m_config.m_default_map);
m_mod_manager.enumerate_modules();
as::Value val1;
val1.i = 10;
as::Value val2;
val2.i = 5;
as::VM vm(1024);
vm.register_function("test_native_function", as::VarType::VAR_TYPE_VOID, std::vector<as::VarType>{as::VarType::VAR_TYPE_INT32}, test_native_function);
std::unique_ptr<as::StatementBlock> block = std::make_unique<as::StatementBlock>();
std::vector<std::unique_ptr<as::Expression>> arguments;
arguments.push_back(std::make_unique<as::BinaryExpression>(as::BinaryExpression::Operation::OPERATION_MUL, std::make_unique<as::NumericExpression>(val1, as::ValueType::VALUE_TYPE_INT), std::make_unique<as::NumericExpression>(val2, as::ValueType::VALUE_TYPE_INT)));
block->add_expression(std::make_unique<as::FunctionCall>(vm, as::FunctionType::FUNCTION_NATIVE, 0, std::move(arguments)));
block->eval(vm);
}
Server::~Server() {