Remove interpreter
This commit is contained in:
@@ -13,7 +13,6 @@ set(LIB_SOURCES
|
||||
src/lexer.cpp
|
||||
src/parser.cpp
|
||||
src/value.cpp
|
||||
src/interpreter.cpp
|
||||
src/state.cpp
|
||||
src/chunk.cpp
|
||||
src/compiler.cpp
|
||||
@@ -27,7 +26,6 @@ set(LIB_HEADERS
|
||||
src/parser.h
|
||||
src/ast.h
|
||||
src/value.h
|
||||
src/interpreter.h
|
||||
src/state.h
|
||||
src/chunk.h
|
||||
src/compiler.h
|
||||
|
||||
@@ -4,11 +4,8 @@
|
||||
|
||||
namespace camellya {
|
||||
|
||||
State::State(ExecutionMode mode)
|
||||
: execution_mode_(mode),
|
||||
interpreter_(std::make_unique<Interpreter>()),
|
||||
vm_(std::make_unique<VM>()),
|
||||
compiler_(std::make_unique<Compiler>()) {}
|
||||
State::State()
|
||||
: vm_(std::make_unique<VM>()), compiler_(std::make_unique<Compiler>()) {}
|
||||
|
||||
bool State::do_string(const std::string &script) {
|
||||
try {
|
||||
@@ -43,29 +40,16 @@ bool State::do_file(const std::string& filename) {
|
||||
|
||||
void State::register_function(const std::string &name, NativeFunction func) {
|
||||
auto func_value = std::make_shared<FunctionValue>(name, func);
|
||||
|
||||
if (execution_mode_ == ExecutionMode::INTERPRETER) {
|
||||
interpreter_->global_environment->define(name, func_value);
|
||||
} else {
|
||||
vm_->register_native_function(name, func);
|
||||
}
|
||||
}
|
||||
|
||||
ValuePtr State::get_global(const std::string &name) {
|
||||
if (execution_mode_ == ExecutionMode::INTERPRETER) {
|
||||
return interpreter_->global_environment->get(name);
|
||||
} else {
|
||||
return vm_->get_global(name);
|
||||
}
|
||||
}
|
||||
|
||||
void State::set_global(const std::string &name, ValuePtr value) {
|
||||
if (execution_mode_ == ExecutionMode::INTERPRETER) {
|
||||
interpreter_->global_environment->define(name, value);
|
||||
} else {
|
||||
vm_->set_global(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
void State::push_number(double value) {
|
||||
stack_.push_back(std::make_shared<NumberValue>(value));
|
||||
@@ -79,13 +63,9 @@ void State::push_bool(bool value) {
|
||||
stack_.push_back(std::make_shared<BoolValue>(value));
|
||||
}
|
||||
|
||||
void State::push_nil() {
|
||||
stack_.push_back(std::make_shared<NilValue>());
|
||||
}
|
||||
void State::push_nil() { stack_.push_back(std::make_shared<NilValue>()); }
|
||||
|
||||
void State::push_value(ValuePtr value) {
|
||||
stack_.push_back(std::move(value));
|
||||
}
|
||||
void State::push_value(ValuePtr value) { stack_.push_back(std::move(value)); }
|
||||
|
||||
double State::to_number(int index) {
|
||||
ValuePtr val = get_stack_value(index);
|
||||
@@ -108,9 +88,7 @@ bool State::to_bool(int index) {
|
||||
return is_truthy(val);
|
||||
}
|
||||
|
||||
ValuePtr State::to_value(int index) {
|
||||
return get_stack_value(index);
|
||||
}
|
||||
ValuePtr State::to_value(int index) { return get_stack_value(index); }
|
||||
|
||||
void State::set_top(int index) {
|
||||
if (index < 0) {
|
||||
@@ -151,11 +129,6 @@ ValuePtr State::get_stack_value(int index) {
|
||||
}
|
||||
|
||||
bool State::execute_program(const Program &program) {
|
||||
if (execution_mode_ == ExecutionMode::INTERPRETER) {
|
||||
// Use tree-walking interpreter
|
||||
interpreter_->execute(program);
|
||||
return true;
|
||||
} else {
|
||||
// Use VM
|
||||
auto chunk = compiler_->compile(program);
|
||||
if (!chunk) {
|
||||
@@ -169,6 +142,5 @@ bool State::execute_program(const Program& program) {
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace camellya
|
||||
|
||||
21
src/state.h
21
src/state.h
@@ -1,33 +1,22 @@
|
||||
#ifndef CAMELLYA_STATE_H
|
||||
#define CAMELLYA_STATE_H
|
||||
|
||||
#include "compiler.h"
|
||||
#include "lexer.h"
|
||||
#include "parser.h"
|
||||
#include "interpreter.h"
|
||||
#include "vm.h"
|
||||
#include "compiler.h"
|
||||
#include "value.h"
|
||||
#include <string>
|
||||
#include "vm.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace camellya {
|
||||
|
||||
// Execution mode
|
||||
enum class ExecutionMode {
|
||||
INTERPRETER, // Tree-walking interpreter
|
||||
VM // Bytecode VM
|
||||
};
|
||||
|
||||
// Main state class - similar to lua_State
|
||||
class State {
|
||||
public:
|
||||
State(ExecutionMode mode = ExecutionMode::VM);
|
||||
State();
|
||||
~State() = default;
|
||||
|
||||
// Set execution mode
|
||||
void set_execution_mode(ExecutionMode mode) { execution_mode_ = mode; }
|
||||
ExecutionMode get_execution_mode() const { return execution_mode_; }
|
||||
|
||||
// Execute script from string
|
||||
bool do_string(const std::string &script);
|
||||
|
||||
@@ -63,8 +52,6 @@ public:
|
||||
const std::string &get_error() const { return last_error_; }
|
||||
|
||||
private:
|
||||
ExecutionMode execution_mode_;
|
||||
std::unique_ptr<Interpreter> interpreter_;
|
||||
std::unique_ptr<VM> vm_;
|
||||
std::unique_ptr<Compiler> compiler_;
|
||||
std::vector<ValuePtr> stack_;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
#include "camellya.h"
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -125,7 +125,6 @@ TEST_CASE("class init is called on declaration", "[class][init]") {
|
||||
|
||||
TEST_CASE("interpreter performance: simple loop", "[perf][script]") {
|
||||
State state;
|
||||
State state_vm(ExecutionMode::VM);
|
||||
const char *script = R"(
|
||||
func sum_to(number n) -> number {
|
||||
var s = 0;
|
||||
@@ -149,18 +148,6 @@ TEST_CASE("interpreter performance: simple loop", "[perf][script]") {
|
||||
auto r_num = std::dynamic_pointer_cast<NumberValue>(r_val);
|
||||
REQUIRE(r_num->value == 499500.0);
|
||||
};
|
||||
|
||||
BENCHMARK("state_vm sum_to(1000)") {
|
||||
if (!state_vm.do_string(script)) {
|
||||
auto last_error = state_vm.get_error();
|
||||
REQUIRE(last_error.empty());
|
||||
}
|
||||
auto r_val = state_vm.get_global("r");
|
||||
REQUIRE(r_val);
|
||||
REQUIRE(r_val->type() == Type::NUMBER);
|
||||
auto r_num = std::dynamic_pointer_cast<NumberValue>(r_val);
|
||||
REQUIRE(r_num->value == 499500.0);
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("loop break", "[script][loop]") {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "src/camellya.h"
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
using namespace camellya;
|
||||
|
||||
TEST_CASE("VM - Basic arithmetic", "[vm]") {
|
||||
State state(ExecutionMode::VM);
|
||||
State state;
|
||||
|
||||
SECTION("Addition") {
|
||||
REQUIRE(state.do_string("var x = 10 + 20;"));
|
||||
@@ -37,7 +37,7 @@ TEST_CASE("VM - Basic arithmetic", "[vm]") {
|
||||
}
|
||||
|
||||
TEST_CASE("VM - Variables and assignment", "[vm]") {
|
||||
State state(ExecutionMode::VM);
|
||||
State state;
|
||||
|
||||
SECTION("Variable declaration and initialization") {
|
||||
REQUIRE(state.do_string("var a = 42;"));
|
||||
@@ -57,19 +57,20 @@ TEST_CASE("VM - Variables and assignment", "[vm]") {
|
||||
}
|
||||
|
||||
TEST_CASE("VM - String operations", "[vm]") {
|
||||
State state(ExecutionMode::VM);
|
||||
State state;
|
||||
|
||||
SECTION("String concatenation") {
|
||||
REQUIRE(state.do_string(R"(var greeting = "Hello" + " " + "World";)"));
|
||||
auto greeting = state.get_global("greeting");
|
||||
REQUIRE(greeting != nullptr);
|
||||
REQUIRE(greeting->type() == Type::STRING);
|
||||
REQUIRE(std::dynamic_pointer_cast<StringValue>(greeting)->value == "Hello World");
|
||||
REQUIRE(std::dynamic_pointer_cast<StringValue>(greeting)->value ==
|
||||
"Hello World");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("VM - Comparison operators", "[vm]") {
|
||||
State state(ExecutionMode::VM);
|
||||
State state;
|
||||
|
||||
SECTION("Equality") {
|
||||
REQUIRE(state.do_string("var eq = 10 == 10;"));
|
||||
@@ -91,7 +92,7 @@ TEST_CASE("VM - Comparison operators", "[vm]") {
|
||||
}
|
||||
|
||||
TEST_CASE("VM - Lists", "[vm]") {
|
||||
State state(ExecutionMode::VM);
|
||||
State state;
|
||||
|
||||
SECTION("Create list") {
|
||||
REQUIRE(state.do_string("var numbers = [1, 2, 3, 4, 5];"));
|
||||
@@ -113,7 +114,7 @@ TEST_CASE("VM - Lists", "[vm]") {
|
||||
}
|
||||
|
||||
TEST_CASE("VM - Maps", "[vm]") {
|
||||
State state(ExecutionMode::VM);
|
||||
State state;
|
||||
|
||||
SECTION("Create map") {
|
||||
REQUIRE(state.do_string(R"(var person = {"name": "Alice", "age": "30"};)"));
|
||||
@@ -134,7 +135,7 @@ TEST_CASE("VM - Maps", "[vm]") {
|
||||
}
|
||||
|
||||
TEST_CASE("VM - If statements", "[vm]") {
|
||||
State state(ExecutionMode::VM);
|
||||
State state;
|
||||
|
||||
SECTION("If branch taken") {
|
||||
REQUIRE(state.do_string(R"(
|
||||
@@ -162,7 +163,7 @@ TEST_CASE("VM - If statements", "[vm]") {
|
||||
}
|
||||
|
||||
TEST_CASE("VM - While loops", "[vm]") {
|
||||
State state(ExecutionMode::VM);
|
||||
State state;
|
||||
|
||||
SECTION("While loop") {
|
||||
REQUIRE(state.do_string(R"(
|
||||
@@ -179,7 +180,7 @@ TEST_CASE("VM - While loops", "[vm]") {
|
||||
}
|
||||
|
||||
TEST_CASE("VM - Native functions", "[vm]") {
|
||||
State state(ExecutionMode::VM);
|
||||
State state;
|
||||
|
||||
SECTION("len function") {
|
||||
REQUIRE(state.do_string(R"(
|
||||
@@ -190,80 +191,3 @@ TEST_CASE("VM - Native functions", "[vm]") {
|
||||
REQUIRE(std::dynamic_pointer_cast<NumberValue>(size)->value == 4.0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("VM vs Interpreter - Same results", "[vm][interpreter]") {
|
||||
const char* script = R"(
|
||||
var x = 10;
|
||||
var y = 20;
|
||||
var sum = x + y;
|
||||
var product = x * y;
|
||||
)";
|
||||
|
||||
State vm_state(ExecutionMode::VM);
|
||||
State interp_state(ExecutionMode::INTERPRETER);
|
||||
|
||||
REQUIRE(vm_state.do_string(script));
|
||||
REQUIRE(interp_state.do_string(script));
|
||||
|
||||
auto vm_sum = vm_state.get_global("sum");
|
||||
auto interp_sum = interp_state.get_global("sum");
|
||||
REQUIRE(std::dynamic_pointer_cast<NumberValue>(vm_sum)->value ==
|
||||
std::dynamic_pointer_cast<NumberValue>(interp_sum)->value);
|
||||
|
||||
auto vm_product = vm_state.get_global("product");
|
||||
auto interp_product = interp_state.get_global("product");
|
||||
REQUIRE(std::dynamic_pointer_cast<NumberValue>(vm_product)->value ==
|
||||
std::dynamic_pointer_cast<NumberValue>(interp_product)->value);
|
||||
}
|
||||
|
||||
TEST_CASE("class init is called on declaration", "[vm][class][init]") {
|
||||
State state(ExecutionMode::VM);
|
||||
const char* script = R"(
|
||||
class Person {
|
||||
var age : number;
|
||||
var name : string;
|
||||
|
||||
func init() -> nil {
|
||||
age = 18;
|
||||
name = "Default";
|
||||
}
|
||||
|
||||
func getAge() -> number {
|
||||
return this.age;
|
||||
}
|
||||
}
|
||||
|
||||
var p : Person;
|
||||
var a = p.getAge();
|
||||
)";
|
||||
|
||||
auto ret = state.do_string(script);
|
||||
if(!ret) {
|
||||
REQUIRE(state.get_error() == "");
|
||||
}
|
||||
|
||||
auto p_val = state.get_global("p");
|
||||
REQUIRE(p_val);
|
||||
REQUIRE(p_val->type() == Type::INSTANCE);
|
||||
|
||||
auto instance = std::dynamic_pointer_cast<InstanceValue>(p_val);
|
||||
REQUIRE(instance);
|
||||
|
||||
auto age_val = instance->get("age");
|
||||
auto name_val = instance->get("name");
|
||||
|
||||
REQUIRE(age_val->type() == Type::NUMBER);
|
||||
REQUIRE(name_val->type() == Type::STRING);
|
||||
|
||||
auto age_num = std::dynamic_pointer_cast<NumberValue>(age_val);
|
||||
auto name_str = std::dynamic_pointer_cast<StringValue>(name_val);
|
||||
|
||||
REQUIRE(age_num->value == 18.0);
|
||||
REQUIRE(name_str->value == "Default");
|
||||
|
||||
auto a_val = state.get_global("a");
|
||||
REQUIRE(a_val);
|
||||
REQUIRE(a_val->type() == Type::NUMBER);
|
||||
auto a_num = std::dynamic_pointer_cast<NumberValue>(a_val);
|
||||
REQUIRE(a_num->value == 18.0);
|
||||
}
|
||||
Reference in New Issue
Block a user