.
This commit is contained in:
83
src/vm.cpp
83
src/vm.cpp
@@ -1,5 +1,4 @@
|
||||
#include "vm.h"
|
||||
#include "interpreter.h"
|
||||
#include <iostream>
|
||||
#include <format>
|
||||
#include <cmath>
|
||||
@@ -212,6 +211,9 @@ bool VM::run() {
|
||||
if (func->is_native) {
|
||||
// Native function call
|
||||
std::vector<ValuePtr> args;
|
||||
if (func->bound_instance) {
|
||||
args.push_back(func->bound_instance);
|
||||
}
|
||||
for (int i = arg_count - 1; i >= 0; i--) {
|
||||
args.push_back(peek(i));
|
||||
}
|
||||
@@ -424,7 +426,18 @@ bool VM::run() {
|
||||
auto instance = std::dynamic_pointer_cast<InstanceValue>(object);
|
||||
push(instance->get(name));
|
||||
} else {
|
||||
runtime_error("Only instances have properties.");
|
||||
auto it = builtin_classes.find(object->type_name());
|
||||
if (it != builtin_classes.end()) {
|
||||
auto klass = it->second;
|
||||
auto method_it = klass->methods.find(name);
|
||||
if (method_it != klass->methods.end()) {
|
||||
auto bound = std::make_shared<FunctionValue>(*method_it->second);
|
||||
bound->bound_instance = object;
|
||||
push(bound);
|
||||
break;
|
||||
}
|
||||
}
|
||||
runtime_error("Only instances and types with registered built-in classes have properties/methods.");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -613,6 +626,67 @@ void VM::register_builtin_functions() {
|
||||
throw RuntimeError("len() expects list, string, or map.");
|
||||
});
|
||||
globals["len"] = len_func;
|
||||
|
||||
// Define list class
|
||||
auto list_klass = std::make_shared<ClassValue>("list");
|
||||
list_klass->add_method("push", std::make_shared<FunctionValue>("push",
|
||||
[](const std::vector<ValuePtr>& args) -> ValuePtr {
|
||||
if (args.size() != 2) throw RuntimeError("list.push() expects 1 argument.");
|
||||
auto list = std::dynamic_pointer_cast<ListValue>(args[0]);
|
||||
list->push(args[1]);
|
||||
return args[1];
|
||||
}));
|
||||
list_klass->add_method("pop", std::make_shared<FunctionValue>("pop",
|
||||
[](const std::vector<ValuePtr>& args) -> ValuePtr {
|
||||
if (args.size() != 1) throw RuntimeError("list.pop() expects 0 arguments.");
|
||||
auto list = std::dynamic_pointer_cast<ListValue>(args[0]);
|
||||
if (list->elements.empty()) return std::make_shared<NilValue>();
|
||||
ValuePtr val = list->elements.back();
|
||||
list->elements.pop_back();
|
||||
return val;
|
||||
}));
|
||||
list_klass->add_method("len", std::make_shared<FunctionValue>("len",
|
||||
[](const std::vector<ValuePtr>& args) -> ValuePtr {
|
||||
if (args.size() != 1) throw RuntimeError("list.len() expects 0 arguments.");
|
||||
auto list = std::dynamic_pointer_cast<ListValue>(args[0]);
|
||||
return std::make_shared<NumberValue>(static_cast<double>(list->size()));
|
||||
}));
|
||||
register_builtin_class("list", list_klass);
|
||||
|
||||
// Define map class
|
||||
auto map_klass = std::make_shared<ClassValue>("map");
|
||||
map_klass->add_method("set", std::make_shared<FunctionValue>("set",
|
||||
[](const std::vector<ValuePtr>& args) -> ValuePtr {
|
||||
if (args.size() != 3) throw RuntimeError("map.set() expects 2 arguments.");
|
||||
auto map = std::dynamic_pointer_cast<MapValue>(args[0]);
|
||||
if (args[1]->type() != Type::STRING) throw RuntimeError("Map key must be a string.");
|
||||
std::string key = std::dynamic_pointer_cast<StringValue>(args[1])->value;
|
||||
map->set(key, args[2]);
|
||||
return args[2];
|
||||
}));
|
||||
map_klass->add_method("get", std::make_shared<FunctionValue>("get",
|
||||
[](const std::vector<ValuePtr>& args) -> ValuePtr {
|
||||
if (args.size() != 2) throw RuntimeError("map.get() expects 1 argument.");
|
||||
auto map = std::dynamic_pointer_cast<MapValue>(args[0]);
|
||||
if (args[1]->type() != Type::STRING) throw RuntimeError("Map key must be a string.");
|
||||
std::string key = std::dynamic_pointer_cast<StringValue>(args[1])->value;
|
||||
return map->get(key);
|
||||
}));
|
||||
map_klass->add_method("has", std::make_shared<FunctionValue>("has",
|
||||
[](const std::vector<ValuePtr>& args) -> ValuePtr {
|
||||
if (args.size() != 2) throw RuntimeError("map.has() expects 1 argument.");
|
||||
auto map = std::dynamic_pointer_cast<MapValue>(args[0]);
|
||||
if (args[1]->type() != Type::STRING) throw RuntimeError("Map key must be a string.");
|
||||
std::string key = std::dynamic_pointer_cast<StringValue>(args[1])->value;
|
||||
return std::make_shared<BoolValue>(map->has(key));
|
||||
}));
|
||||
map_klass->add_method("len", std::make_shared<FunctionValue>("len",
|
||||
[](const std::vector<ValuePtr>& args) -> ValuePtr {
|
||||
if (args.size() != 1) throw RuntimeError("map.len() expects 0 arguments.");
|
||||
auto map = std::dynamic_pointer_cast<MapValue>(args[0]);
|
||||
return std::make_shared<NumberValue>(static_cast<double>(map->pairs.size()));
|
||||
}));
|
||||
register_builtin_class("map", map_klass);
|
||||
}
|
||||
|
||||
void VM::register_native_function(const std::string& name, NativeFunction func) {
|
||||
@@ -620,6 +694,11 @@ void VM::register_native_function(const std::string& name, NativeFunction func)
|
||||
globals[name] = func_value;
|
||||
}
|
||||
|
||||
void VM::register_builtin_class(const std::string& type_name, std::shared_ptr<ClassValue> klass) {
|
||||
builtin_classes[type_name] = klass;
|
||||
globals[klass->name] = klass;
|
||||
}
|
||||
|
||||
void VM::set_global(const std::string& name, ValuePtr value) {
|
||||
globals[name] = value;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user