mirror of
https://github.com/open-goal/jak-project
synced 2026-08-30 01:20:38 -04:00
[goalc] Cleaned up speedups (#3066)
Started at 349,880,038 allocations and 42s - Switched to making `Symbol` in GOOS be a "fixed type", just a wrapper around a `const char*` pointing to the string in the symbol table. This is a step toward making a lot of things better, but by itself not a huge improvement. Some things may be worse due to more temp `std::string` allocations, but one day all these can be removed. On linux it saved allocations (347,685,429), and saved a second or two (41 s). - cache `#t` and `#f` in interpreter, better lookup for special forms/builtins (hashtable of pointers instead of strings, vector for the small special form list). Dropped time to 38s. - special-case in quasiquote when splicing is the last thing in a list. Allocation dropped to 340,603,082 - custom hash table for environment lookups (lexical vars). Dropped to 36s and 314,637,194 - less allocation in `read_list` 311,613,616. Time about the same. - `let` and `let*` in Interpreter.cpp 191,988,083, time down to 28s.
This commit is contained in:
+361
-137
@@ -12,6 +12,7 @@
|
||||
#include "common/goos/Printer.h"
|
||||
#include "common/log/log.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "common/util/crc32.h"
|
||||
#include "common/util/string_util.h"
|
||||
#include "common/util/unicode_util.h"
|
||||
|
||||
@@ -19,6 +20,10 @@
|
||||
|
||||
namespace goos {
|
||||
Interpreter::Interpreter(const std::string& username) {
|
||||
m_true_object = intern("#t");
|
||||
m_false_object = intern("#f");
|
||||
m_true_sym = m_true_object.as_symbol().name_ptr;
|
||||
m_false_sym = m_false_object.as_symbol().name_ptr;
|
||||
// Interpreter startup:
|
||||
// create the GOOS global environment
|
||||
global_environment = EnvironmentObject::make_new("global");
|
||||
@@ -33,14 +38,16 @@ Interpreter::Interpreter(const std::string& username) {
|
||||
define_var_in_env(goal_env, global_environment, "*global-env*");
|
||||
|
||||
// set user profile name
|
||||
auto user = SymbolObject::make_new(reader.symbolTable, username);
|
||||
auto user = Object::make_symbol(&reader.symbolTable, username.c_str());
|
||||
define_var_in_env(global_environment, user, "*user*");
|
||||
|
||||
// setup maps
|
||||
special_forms = {
|
||||
init_special_forms({
|
||||
{"define", &Interpreter::eval_define},
|
||||
{"quote", &Interpreter::eval_quote},
|
||||
{"set!", &Interpreter::eval_set},
|
||||
{"let", &Interpreter::eval_let},
|
||||
{"let*", &Interpreter::eval_let_star},
|
||||
{"lambda", &Interpreter::eval_lambda},
|
||||
{"cond", &Interpreter::eval_cond},
|
||||
{"or", &Interpreter::eval_or},
|
||||
@@ -48,54 +55,54 @@ Interpreter::Interpreter(const std::string& username) {
|
||||
{"macro", &Interpreter::eval_macro},
|
||||
{"quasiquote", &Interpreter::eval_quasiquote},
|
||||
{"while", &Interpreter::eval_while},
|
||||
};
|
||||
});
|
||||
|
||||
builtin_forms = {{"top-level", &Interpreter::eval_begin},
|
||||
{"begin", &Interpreter::eval_begin},
|
||||
{"exit", &Interpreter::eval_exit},
|
||||
{"read", &Interpreter::eval_read},
|
||||
{"read-data-file", &Interpreter::eval_read_data_file},
|
||||
{"read-file", &Interpreter::eval_read_file},
|
||||
{"print", &Interpreter::eval_print},
|
||||
{"inspect", &Interpreter::eval_inspect},
|
||||
{"load-file", &Interpreter::eval_load_file},
|
||||
{"try-load-file", &Interpreter::eval_try_load_file},
|
||||
{"eq?", &Interpreter::eval_equals},
|
||||
{"gensym", &Interpreter::eval_gensym},
|
||||
{"eval", &Interpreter::eval_eval},
|
||||
{"cons", &Interpreter::eval_cons},
|
||||
{"car", &Interpreter::eval_car},
|
||||
{"cdr", &Interpreter::eval_cdr},
|
||||
{"set-car!", &Interpreter::eval_set_car},
|
||||
{"set-cdr!", &Interpreter::eval_set_cdr},
|
||||
{"+", &Interpreter::eval_plus},
|
||||
{"-", &Interpreter::eval_minus},
|
||||
{"*", &Interpreter::eval_times},
|
||||
{"/", &Interpreter::eval_divide},
|
||||
{"=", &Interpreter::eval_numequals},
|
||||
{"<", &Interpreter::eval_lt},
|
||||
{">", &Interpreter::eval_gt},
|
||||
{"<=", &Interpreter::eval_leq},
|
||||
{">=", &Interpreter::eval_geq},
|
||||
{"null?", &Interpreter::eval_null},
|
||||
{"type?", &Interpreter::eval_type},
|
||||
{"fmt", &Interpreter::eval_format},
|
||||
{"error", &Interpreter::eval_error},
|
||||
{"string-ref", &Interpreter::eval_string_ref},
|
||||
{"string-length", &Interpreter::eval_string_length},
|
||||
{"string-append", &Interpreter::eval_string_append},
|
||||
{"string-starts-with?", &Interpreter::eval_string_starts_with},
|
||||
{"string-ends-with?", &Interpreter::eval_string_ends_with},
|
||||
{"string-split", &Interpreter::eval_string_split},
|
||||
{"string-substr", &Interpreter::eval_string_substr},
|
||||
{"ash", &Interpreter::eval_ash},
|
||||
{"symbol->string", &Interpreter::eval_symbol_to_string},
|
||||
{"string->symbol", &Interpreter::eval_string_to_symbol},
|
||||
{"int->string", &Interpreter::eval_int_to_string},
|
||||
{"get-environment-variable", &Interpreter::eval_get_env},
|
||||
{"make-string-hash-table", &Interpreter::eval_make_string_hash_table},
|
||||
{"hash-table-set!", &Interpreter::eval_hash_table_set},
|
||||
{"hash-table-try-ref", &Interpreter::eval_hash_table_try_ref}};
|
||||
init_builtin_forms({{"top-level", &Interpreter::eval_begin},
|
||||
{"begin", &Interpreter::eval_begin},
|
||||
{"exit", &Interpreter::eval_exit},
|
||||
{"read", &Interpreter::eval_read},
|
||||
{"read-data-file", &Interpreter::eval_read_data_file},
|
||||
{"read-file", &Interpreter::eval_read_file},
|
||||
{"print", &Interpreter::eval_print},
|
||||
{"inspect", &Interpreter::eval_inspect},
|
||||
{"load-file", &Interpreter::eval_load_file},
|
||||
{"try-load-file", &Interpreter::eval_try_load_file},
|
||||
{"eq?", &Interpreter::eval_equals},
|
||||
{"gensym", &Interpreter::eval_gensym},
|
||||
{"eval", &Interpreter::eval_eval},
|
||||
{"cons", &Interpreter::eval_cons},
|
||||
{"car", &Interpreter::eval_car},
|
||||
{"cdr", &Interpreter::eval_cdr},
|
||||
{"set-car!", &Interpreter::eval_set_car},
|
||||
{"set-cdr!", &Interpreter::eval_set_cdr},
|
||||
{"+", &Interpreter::eval_plus},
|
||||
{"-", &Interpreter::eval_minus},
|
||||
{"*", &Interpreter::eval_times},
|
||||
{"/", &Interpreter::eval_divide},
|
||||
{"=", &Interpreter::eval_numequals},
|
||||
{"<", &Interpreter::eval_lt},
|
||||
{">", &Interpreter::eval_gt},
|
||||
{"<=", &Interpreter::eval_leq},
|
||||
{">=", &Interpreter::eval_geq},
|
||||
{"null?", &Interpreter::eval_null},
|
||||
{"type?", &Interpreter::eval_type},
|
||||
{"fmt", &Interpreter::eval_format},
|
||||
{"error", &Interpreter::eval_error},
|
||||
{"string-ref", &Interpreter::eval_string_ref},
|
||||
{"string-length", &Interpreter::eval_string_length},
|
||||
{"int->string", &Interpreter::eval_int_to_string},
|
||||
{"string-append", &Interpreter::eval_string_append},
|
||||
{"string-starts-with?", &Interpreter::eval_string_starts_with},
|
||||
{"string-ends-with?", &Interpreter::eval_string_ends_with},
|
||||
{"string-split", &Interpreter::eval_string_split},
|
||||
{"string-substr", &Interpreter::eval_string_substr},
|
||||
{"ash", &Interpreter::eval_ash},
|
||||
{"symbol->string", &Interpreter::eval_symbol_to_string},
|
||||
{"string->symbol", &Interpreter::eval_string_to_symbol},
|
||||
{"get-environment-variable", &Interpreter::eval_get_env},
|
||||
{"make-string-hash-table", &Interpreter::eval_make_string_hash_table},
|
||||
{"hash-table-set!", &Interpreter::eval_hash_table_set},
|
||||
{"hash-table-try-ref", &Interpreter::eval_hash_table_try_ref}});
|
||||
|
||||
string_to_type = {{"empty-list", ObjectType::EMPTY_LIST},
|
||||
{"integer", ObjectType::INTEGER},
|
||||
@@ -113,6 +120,28 @@ Interpreter::Interpreter(const std::string& username) {
|
||||
load_goos_library();
|
||||
}
|
||||
|
||||
void Interpreter::init_builtin_forms(
|
||||
const std::unordered_map<std::string,
|
||||
Object (Interpreter::*)(const Object&,
|
||||
Arguments&,
|
||||
const std::shared_ptr<EnvironmentObject>&)>&
|
||||
forms) {
|
||||
for (const auto& [name, fn] : forms) {
|
||||
builtin_forms[(void*)intern_ptr(name).name_ptr] = fn;
|
||||
}
|
||||
}
|
||||
|
||||
void Interpreter::init_special_forms(
|
||||
const std::unordered_map<std::string,
|
||||
Object (Interpreter::*)(const Object&,
|
||||
const Object&,
|
||||
const std::shared_ptr<EnvironmentObject>&)>&
|
||||
forms) {
|
||||
for (const auto& [name, fn] : forms) {
|
||||
special_forms.push_back(std::make_pair((void*)intern_ptr(name).name_ptr, fn));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Add a user defined special form. The given function will be called with unevaluated arguments.
|
||||
* Lookup from these forms occurs after special/builtin, but before any env lookups.
|
||||
@@ -121,7 +150,7 @@ void Interpreter::register_form(
|
||||
const std::string& name,
|
||||
const std::function<
|
||||
Object(const Object&, Arguments&, const std::shared_ptr<EnvironmentObject>&)>& form) {
|
||||
m_custom_forms[name] = form;
|
||||
m_custom_forms.push_back(std::make_pair((void*)intern_ptr(name).name_ptr, form));
|
||||
}
|
||||
|
||||
Interpreter::~Interpreter() {
|
||||
@@ -149,19 +178,19 @@ void Interpreter::load_goos_library() {
|
||||
/*!
|
||||
* In env, set the variable named "name" to the value var.
|
||||
*/
|
||||
void Interpreter::define_var_in_env(Object& env, Object& var, const std::string& name) {
|
||||
env.as_env()->vars[intern_ptr(name)] = var;
|
||||
void Interpreter::define_var_in_env(Object& env, const Object& var, const std::string& name) {
|
||||
env.as_env()->vars.set(InternedSymbolPtr{intern_ptr(name)}, var);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Get a symbol with the given name, creating one if none exist.
|
||||
*/
|
||||
Object Interpreter::intern(const std::string& name) {
|
||||
return SymbolObject::make_new(reader.symbolTable, name);
|
||||
return Object::make_symbol(&reader.symbolTable, name.c_str());
|
||||
}
|
||||
|
||||
HeapObject* Interpreter::intern_ptr(const std::string& name) {
|
||||
return reader.symbolTable.intern_ptr(name);
|
||||
InternedSymbolPtr Interpreter::intern_ptr(const std::string& name) {
|
||||
return reader.symbolTable.intern(name.c_str());
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -218,10 +247,9 @@ Object Interpreter::eval_with_rewind(const Object& obj,
|
||||
* Returns if the variable was found.
|
||||
*/
|
||||
bool Interpreter::get_global_variable_by_name(const std::string& name, Object* dest) {
|
||||
auto kv = global_environment.as_env()->vars.find(
|
||||
SymbolObject::make_new(reader.symbolTable, name).as_symbol());
|
||||
if (kv != global_environment.as_env()->vars.end()) {
|
||||
*dest = kv->second;
|
||||
auto* obj = global_environment.as_env()->find(name.c_str(), &reader.symbolTable);
|
||||
if (obj) {
|
||||
*dest = *obj;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -231,12 +259,11 @@ bool Interpreter::get_global_variable_by_name(const std::string& name, Object* d
|
||||
* Sets the variable to the value. Overwrites an existing value, or creates a new global.
|
||||
*/
|
||||
void Interpreter::set_global_variable_by_name(const std::string& name, const Object& value) {
|
||||
auto sym = SymbolObject::make_new(reader.symbolTable, name).as_symbol();
|
||||
global_environment.as_env()->vars[sym] = value;
|
||||
define_var_in_env(global_environment, value, name);
|
||||
}
|
||||
|
||||
void Interpreter::set_global_variable_to_symbol(const std::string& name, const std::string& value) {
|
||||
auto sym = SymbolObject::make_new(reader.symbolTable, value);
|
||||
auto sym = Object::make_symbol(&reader.symbolTable, value.c_str());
|
||||
set_global_variable_by_name(name, sym);
|
||||
}
|
||||
|
||||
@@ -269,18 +296,18 @@ Arguments Interpreter::get_args(const Object& form, const Object& rest, const Ar
|
||||
const auto& arg = current->as_pair()->car;
|
||||
|
||||
// did we get a ":keyword"
|
||||
if (arg.is_symbol() && arg.as_symbol()->name.at(0) == ':') {
|
||||
auto key_name = arg.as_symbol()->name.substr(1);
|
||||
if (arg.is_symbol() && arg.as_symbol().name_ptr[0] == ':') {
|
||||
auto key_name = arg.as_symbol().name_ptr + 1;
|
||||
const auto& kv = spec.named.find(key_name);
|
||||
|
||||
// check for unknown key name
|
||||
if (!spec.varargs && kv == spec.named.end()) {
|
||||
throw_eval_error(form, "Key argument " + key_name + " wasn't expected");
|
||||
throw_eval_error(form, fmt::format("Key argument {} wasn't expected", key_name));
|
||||
}
|
||||
|
||||
// check for multiple definition of key
|
||||
if (args.named.find(key_name) != args.named.end()) {
|
||||
throw_eval_error(form, "Key argument " + key_name + " multiply defined");
|
||||
throw_eval_error(form, fmt::format("Key argument {} multiply defined", key_name));
|
||||
}
|
||||
|
||||
// check for well-formed :key value expression
|
||||
@@ -409,7 +436,7 @@ ArgumentSpec Interpreter::parse_arg_spec(const Object& form, Object& rest) {
|
||||
throw_eval_error(form, "args must be symbols");
|
||||
}
|
||||
|
||||
if (arg.as_symbol()->name == "&rest") {
|
||||
if (arg.as_symbol() == "&rest") {
|
||||
// special case for &rest
|
||||
current = current.as_pair()->cdr;
|
||||
if (!current.is_pair()) {
|
||||
@@ -420,20 +447,20 @@ ArgumentSpec Interpreter::parse_arg_spec(const Object& form, Object& rest) {
|
||||
throw_eval_error(form, "rest name must be a symbol");
|
||||
}
|
||||
|
||||
spec.rest = rest_name.as_symbol()->name;
|
||||
spec.rest = rest_name.as_symbol().name_ptr;
|
||||
|
||||
if (!current.as_pair()->cdr.is_empty_list()) {
|
||||
throw_eval_error(form, "rest must be the last argument");
|
||||
}
|
||||
} else if (arg.as_symbol()->name == "&key") {
|
||||
} else if (arg.as_symbol() == "&key") {
|
||||
// special case for &key
|
||||
current = current.as_pair()->cdr;
|
||||
auto key_arg = current.as_pair()->car;
|
||||
if (key_arg.is_symbol()) {
|
||||
// form is &key name
|
||||
auto key_arg_name = key_arg.as_symbol()->name;
|
||||
auto key_arg_name = key_arg.as_symbol().name_ptr;
|
||||
if (spec.named.find(key_arg_name) != spec.named.end()) {
|
||||
throw_eval_error(form, "key argument " + key_arg_name + " multiply defined");
|
||||
throw_eval_error(form, fmt::format("key argument {} multiply defined", key_arg_name));
|
||||
}
|
||||
spec.named[key_arg_name] = NamedArg();
|
||||
} else if (key_arg.is_pair()) {
|
||||
@@ -444,9 +471,9 @@ ArgumentSpec Interpreter::parse_arg_spec(const Object& form, Object& rest) {
|
||||
if (!kn.is_symbol()) {
|
||||
throw_eval_error(form, "key argument must have a symbol as a name");
|
||||
}
|
||||
auto key_arg_name = kn.as_symbol()->name;
|
||||
auto key_arg_name = kn.as_symbol().name_ptr;
|
||||
if (spec.named.find(key_arg_name) != spec.named.end()) {
|
||||
throw_eval_error(form, "key argument " + key_arg_name + " multiply defined");
|
||||
throw_eval_error(form, fmt::format("key argument {} multiply defined", key_arg_name));
|
||||
}
|
||||
NamedArg na;
|
||||
|
||||
@@ -466,7 +493,7 @@ ArgumentSpec Interpreter::parse_arg_spec(const Object& form, Object& rest) {
|
||||
throw_eval_error(form, "invalid key argument");
|
||||
}
|
||||
} else {
|
||||
spec.unnamed.push_back(arg.as_symbol()->name);
|
||||
spec.unnamed.push_back(arg.as_symbol().name_ptr);
|
||||
}
|
||||
|
||||
current = current.as_pair()->cdr;
|
||||
@@ -497,17 +524,19 @@ void Interpreter::vararg_check(
|
||||
Object Interpreter::eval_list_return_last(const Object& form,
|
||||
Object rest,
|
||||
const std::shared_ptr<EnvironmentObject>& env) {
|
||||
Object o = std::move(rest);
|
||||
Object rv = Object::make_empty_list();
|
||||
for (;;) {
|
||||
if (o.is_pair()) {
|
||||
auto op = o.as_pair();
|
||||
rv = eval_with_rewind(op->car, env);
|
||||
o = op->cdr;
|
||||
} else if (o.is_empty_list()) {
|
||||
return rv;
|
||||
if (rest.is_empty_list()) {
|
||||
return rest;
|
||||
}
|
||||
|
||||
const Object* iter = &rest;
|
||||
while (true) {
|
||||
const Object* next = &iter->as_pair()->cdr;
|
||||
const Object* item = &iter->as_pair()->car;
|
||||
if (next->is_empty_list()) {
|
||||
return eval_with_rewind(*item, env);
|
||||
} else {
|
||||
throw_eval_error(form, "malformed body to evaluate");
|
||||
eval(*item, env);
|
||||
iter = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -542,6 +571,104 @@ Object Interpreter::eval(Object obj, const std::shared_ptr<EnvironmentObject>& e
|
||||
}
|
||||
}
|
||||
|
||||
EnvironmentMap::EnvironmentMap() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void EnvironmentMap::clear() {
|
||||
m_entries.clear();
|
||||
m_power_of_two_size = 3; // 2 ^ 3 = 8
|
||||
m_entries.resize(8);
|
||||
m_used_entries = 0;
|
||||
m_next_resize = (m_entries.size() * kMaxUsed);
|
||||
m_mask = 0b111;
|
||||
}
|
||||
|
||||
Object* EnvironmentMap::lookup(InternedSymbolPtr str) {
|
||||
if (m_entries.size() < 10) {
|
||||
for (auto& e : m_entries) {
|
||||
if (e.key == str.name_ptr) {
|
||||
return &e.value;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
u32 hash = crc32((const u8*)&str.name_ptr, sizeof(const char*));
|
||||
|
||||
// probe
|
||||
for (u32 i = 0; i < m_entries.size(); i++) {
|
||||
u32 slot_addr = (hash + i) & m_mask;
|
||||
auto& slot = m_entries[slot_addr];
|
||||
if (!slot.key) {
|
||||
return nullptr;
|
||||
} else {
|
||||
if (slot.key != str.name_ptr) {
|
||||
continue; // bad hash
|
||||
}
|
||||
return &slot.value;
|
||||
}
|
||||
}
|
||||
|
||||
// should be impossible to reach.
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void EnvironmentMap::set(InternedSymbolPtr ptr, const Object& obj) {
|
||||
u32 hash = crc32((const u8*)&ptr.name_ptr, sizeof(const char*));
|
||||
|
||||
// probe
|
||||
for (u32 i = 0; i < m_entries.size(); i++) {
|
||||
u32 slot_addr = (hash + i) & m_mask;
|
||||
auto& slot = m_entries[slot_addr];
|
||||
if (!slot.key) {
|
||||
// not found, insert!
|
||||
slot.key = ptr.name_ptr;
|
||||
slot.value = obj;
|
||||
m_used_entries++;
|
||||
|
||||
if (m_used_entries >= m_next_resize) {
|
||||
resize();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (slot.key == ptr.name_ptr) {
|
||||
slot.value = obj;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// should be impossible to reach.
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void EnvironmentMap::resize() {
|
||||
m_power_of_two_size++;
|
||||
m_mask = (1U << m_power_of_two_size) - 1;
|
||||
|
||||
std::vector<Entry> new_entries(m_entries.size() * 2);
|
||||
for (const auto& old_entry : m_entries) {
|
||||
if (old_entry.key) {
|
||||
bool done = false;
|
||||
u32 hash = crc32((const u8*)&old_entry.key, sizeof(const char*));
|
||||
for (u32 i = 0; i < new_entries.size(); i++) {
|
||||
u32 slot_addr = (hash + i) & m_mask;
|
||||
auto& slot = new_entries[slot_addr];
|
||||
if (!slot.key) {
|
||||
slot.key = old_entry.key;
|
||||
slot.value = std::move(old_entry.value);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT(done);
|
||||
}
|
||||
}
|
||||
|
||||
m_entries = std::move(new_entries);
|
||||
m_next_resize = kMaxUsed * m_entries.size();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/*!
|
||||
@@ -552,7 +679,7 @@ bool try_symbol_lookup(const Object& sym,
|
||||
const std::shared_ptr<EnvironmentObject>& env,
|
||||
Object* dest) {
|
||||
// booleans are hard-coded here
|
||||
if (sym.as_symbol()->name == "#t" || sym.as_symbol()->name == "#f") {
|
||||
if (sym.as_symbol() == "#t" || sym.as_symbol() == "#f") {
|
||||
*dest = sym;
|
||||
return true;
|
||||
}
|
||||
@@ -560,9 +687,9 @@ bool try_symbol_lookup(const Object& sym,
|
||||
// loop up envs until we find it.
|
||||
EnvironmentObject* search_env = env.get();
|
||||
for (;;) {
|
||||
const auto& kv = search_env->vars.find(sym.as_symbol());
|
||||
if (kv != search_env->vars.end()) {
|
||||
*dest = kv->second;
|
||||
auto* obj = search_env->vars.lookup(sym.as_symbol());
|
||||
if (obj) {
|
||||
*dest = *obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -593,6 +720,59 @@ bool Interpreter::eval_symbol(const Object& sym,
|
||||
return try_symbol_lookup(sym, env, result);
|
||||
}
|
||||
|
||||
Object Interpreter::eval_let_star(const goos::Object& form,
|
||||
const goos::Object& rest,
|
||||
const std::shared_ptr<EnvironmentObject>& env) {
|
||||
return eval_let_common(form, rest, env, true);
|
||||
}
|
||||
|
||||
Object Interpreter::eval_let(const goos::Object& form,
|
||||
const goos::Object& rest,
|
||||
const std::shared_ptr<EnvironmentObject>& env) {
|
||||
return eval_let_common(form, rest, env, false);
|
||||
}
|
||||
|
||||
Object Interpreter::eval_let_common(const goos::Object& form,
|
||||
const goos::Object& rest,
|
||||
const std::shared_ptr<EnvironmentObject>& env,
|
||||
bool is_star) {
|
||||
if (!rest.is_pair()) {
|
||||
throw_eval_error(form, "first argument to let must be bindings");
|
||||
}
|
||||
|
||||
const auto* bindings_iter = &rest.as_pair()->car;
|
||||
const auto* body_iter = &rest.as_pair()->cdr;
|
||||
|
||||
if (!bindings_iter->is_pair()) {
|
||||
throw_eval_error(form, "let cannot have empty bindings");
|
||||
}
|
||||
|
||||
std::shared_ptr<EnvironmentObject> new_env = std::make_shared<EnvironmentObject>();
|
||||
new_env->parent_env = env;
|
||||
|
||||
while (!bindings_iter->is_empty_list()) {
|
||||
const auto* binding = &bindings_iter->as_pair()->car;
|
||||
if (!binding->is_pair()) {
|
||||
throw_eval_error(form, "let binding invalid");
|
||||
}
|
||||
const auto& name = binding->as_pair()->car;
|
||||
if (!name.is_symbol()) {
|
||||
throw_eval_error(form, "let binding invalid");
|
||||
}
|
||||
|
||||
binding = &binding->as_pair()->cdr;
|
||||
if (!binding->is_pair() || !binding->as_pair()->cdr.is_empty_list()) {
|
||||
throw_eval_error(form, "let binding invalid");
|
||||
}
|
||||
|
||||
new_env->vars.set(name.as_symbol(), eval(binding->as_pair()->car, is_star ? new_env : env));
|
||||
|
||||
bindings_iter = &bindings_iter->as_pair()->cdr;
|
||||
}
|
||||
|
||||
return eval_list_return_last(*body_iter, *body_iter, new_env);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Evaluate a pair, either as special form, builtin form, macro application, or lambda application.
|
||||
*/
|
||||
@@ -606,13 +786,14 @@ Object Interpreter::eval_pair(const Object& obj, const std::shared_ptr<Environme
|
||||
const auto& head_sym = head.as_symbol();
|
||||
|
||||
// try a special form first
|
||||
const auto& kv_sf = special_forms.find(head_sym->name);
|
||||
if (kv_sf != special_forms.end()) {
|
||||
return ((*this).*(kv_sf->second))(obj, rest, env);
|
||||
for (const auto& sf : special_forms) {
|
||||
if (sf.first == head_sym.name_ptr) {
|
||||
return ((*this).*(sf.second))(obj, rest, env);
|
||||
}
|
||||
}
|
||||
|
||||
// try builtins next
|
||||
const auto& kv_b = builtin_forms.find(head_sym->name);
|
||||
const auto& kv_b = builtin_forms.find((void*)head_sym.name_ptr);
|
||||
if (kv_b != builtin_forms.end()) {
|
||||
Arguments args = get_args(obj, rest, make_varargs());
|
||||
// all "built-in" forms expect arguments to be evaluated (that's why they aren't special)
|
||||
@@ -621,10 +802,11 @@ Object Interpreter::eval_pair(const Object& obj, const std::shared_ptr<Environme
|
||||
}
|
||||
|
||||
// try custom forms next
|
||||
const auto& kv_u = m_custom_forms.find(head_sym->name);
|
||||
if (kv_u != m_custom_forms.end()) {
|
||||
Arguments args = get_args(obj, rest, make_varargs());
|
||||
return (kv_u->second)(obj, args, env);
|
||||
for (const auto& cf : m_custom_forms) {
|
||||
if (cf.first == head_sym.name_ptr) {
|
||||
Arguments args = get_args(obj, rest, make_varargs());
|
||||
return (cf.second)(obj, args, env);
|
||||
}
|
||||
}
|
||||
|
||||
// try macros next
|
||||
@@ -678,18 +860,18 @@ void Interpreter::set_args_in_env(const Object& form,
|
||||
|
||||
// unnamed args
|
||||
for (size_t i = 0; i < arg_spec.unnamed.size(); i++) {
|
||||
env->vars[intern(arg_spec.unnamed.at(i)).as_symbol()] = args.unnamed.at(i);
|
||||
env->vars.set(intern_ptr(arg_spec.unnamed.at(i).c_str()), args.unnamed.at(i));
|
||||
}
|
||||
|
||||
// named args
|
||||
for (const auto& kv : arg_spec.named) {
|
||||
env->vars[intern(kv.first).as_symbol()] = args.named.at(kv.first);
|
||||
env->vars.set(intern_ptr(kv.first), args.named.at(kv.first));
|
||||
}
|
||||
|
||||
// rest args
|
||||
if (!arg_spec.rest.empty()) {
|
||||
// will correctly handle the '() case
|
||||
env->vars[intern(arg_spec.rest).as_symbol()] = build_list(args.rest);
|
||||
env->vars.set(intern_ptr(arg_spec.rest), build_list(args.rest));
|
||||
} else {
|
||||
if (!args.rest.empty()) {
|
||||
throw_eval_error(form, "got too many arguments");
|
||||
@@ -714,7 +896,7 @@ Object Interpreter::eval_define(const Object& form,
|
||||
}
|
||||
|
||||
Object value = eval_with_rewind(args.unnamed[1], env);
|
||||
define_env->vars[args.unnamed[0].as_symbol()] = value;
|
||||
define_env->vars.set(args.unnamed[0].as_symbol(), value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -732,10 +914,10 @@ Object Interpreter::eval_set(const Object& form,
|
||||
|
||||
std::shared_ptr<EnvironmentObject> search_env = env;
|
||||
for (;;) {
|
||||
auto kv = search_env->vars.find(to_define.as_symbol());
|
||||
if (kv != search_env->vars.end()) {
|
||||
kv->second = to_set;
|
||||
return kv->second;
|
||||
auto kv = search_env->vars.lookup(to_define.as_symbol());
|
||||
if (kv) {
|
||||
search_env->vars.set(to_define.as_symbol(), to_set);
|
||||
return to_set;
|
||||
}
|
||||
|
||||
auto pe = search_env->parent_env;
|
||||
@@ -819,6 +1001,32 @@ Object Interpreter::eval_quote(const Object& form,
|
||||
return args.unnamed.front();
|
||||
}
|
||||
|
||||
Object build_list_with_spliced_tail(std::vector<Object>&& objects, const Object& tail) {
|
||||
if (objects.empty()) {
|
||||
return tail;
|
||||
}
|
||||
|
||||
std::shared_ptr<PairObject> head = std::make_shared<PairObject>(objects.back(), tail);
|
||||
|
||||
s64 idx = ((s64)objects.size()) - 2;
|
||||
while (idx >= 0) {
|
||||
Object next;
|
||||
next.type = ObjectType::PAIR;
|
||||
next.heap_obj = std::move(head);
|
||||
|
||||
head = std::make_shared<PairObject>();
|
||||
head->car = std::move(objects[idx]);
|
||||
head->cdr = std::move(next);
|
||||
|
||||
idx--;
|
||||
}
|
||||
|
||||
Object result;
|
||||
result.type = ObjectType::PAIR;
|
||||
result.heap_obj = std::move(head);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Recursive quasi-quote evaluation
|
||||
*/
|
||||
@@ -831,7 +1039,7 @@ Object Interpreter::quasiquote_helper(const Object& form,
|
||||
const Object& item = lst_iter->as_pair()->car;
|
||||
if (item.type == ObjectType::PAIR) {
|
||||
if (item.as_pair()->car.type == ObjectType::SYMBOL &&
|
||||
item.as_pair()->car.as_symbol()->name == "unquote") {
|
||||
item.as_pair()->car.as_symbol() == "unquote") {
|
||||
const Object& unquote_arg = item.as_pair()->cdr;
|
||||
if (unquote_arg.type != ObjectType::PAIR ||
|
||||
unquote_arg.as_pair()->cdr.type != ObjectType::EMPTY_LIST) {
|
||||
@@ -841,7 +1049,7 @@ Object Interpreter::quasiquote_helper(const Object& form,
|
||||
lst_iter = &lst_iter->as_pair()->cdr;
|
||||
continue;
|
||||
} else if (item.as_pair()->car.type == ObjectType::SYMBOL &&
|
||||
item.as_pair()->car.as_symbol()->name == "unquote-splicing") {
|
||||
item.as_pair()->car.as_symbol() == "unquote-splicing") {
|
||||
const Object& unquote_arg = item.as_pair()->cdr;
|
||||
if (unquote_arg.type != ObjectType::PAIR ||
|
||||
unquote_arg.as_pair()->cdr.type != ObjectType::EMPTY_LIST) {
|
||||
@@ -851,6 +1059,11 @@ Object Interpreter::quasiquote_helper(const Object& form,
|
||||
// bypass normal addition:
|
||||
lst_iter = &lst_iter->as_pair()->cdr;
|
||||
Object splice_result = eval_with_rewind(unquote_arg.as_pair()->car, env);
|
||||
if (lst_iter->type == ObjectType::EMPTY_LIST) {
|
||||
// optimization!
|
||||
return build_list_with_spliced_tail(std::move(result), splice_result);
|
||||
}
|
||||
|
||||
const Object* to_add = &splice_result;
|
||||
for (;;) {
|
||||
if (to_add->type == ObjectType::PAIR) {
|
||||
@@ -864,8 +1077,13 @@ Object Interpreter::quasiquote_helper(const Object& form,
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
result.push_back(quasiquote_helper(item, env));
|
||||
lst_iter = &lst_iter->as_pair()->cdr;
|
||||
|
||||
if (item.is_pair()) {
|
||||
result.push_back(quasiquote_helper(item, env));
|
||||
} else {
|
||||
result.push_back(item);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -891,7 +1109,7 @@ Object Interpreter::eval_quasiquote(const Object& form,
|
||||
}
|
||||
|
||||
bool Interpreter::truthy(const Object& o) {
|
||||
return !(o.is_symbol() && o.as_symbol()->name == "#f");
|
||||
return !(o.is_symbol() && o.as_symbol().name_ptr == m_false_sym);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -924,7 +1142,7 @@ Object Interpreter::eval_cond(const Object& form,
|
||||
lst = lst.as_pair()->cdr;
|
||||
}
|
||||
} else if (lst.type == ObjectType::EMPTY_LIST) {
|
||||
return SymbolObject::make_new(reader.symbolTable, "#f");
|
||||
return m_false_object;
|
||||
} else {
|
||||
throw_eval_error(form, "malformed cond");
|
||||
}
|
||||
@@ -950,7 +1168,7 @@ Object Interpreter::eval_or(const Object& form,
|
||||
}
|
||||
lst = lst.as_pair()->cdr;
|
||||
} else if (lst.type == ObjectType::EMPTY_LIST) {
|
||||
return SymbolObject::make_new(reader.symbolTable, "#f");
|
||||
return m_false_object;
|
||||
} else {
|
||||
throw_eval_error(form, "invalid or form");
|
||||
}
|
||||
@@ -973,7 +1191,7 @@ Object Interpreter::eval_and(const Object& form,
|
||||
if (lst.type == ObjectType::PAIR) {
|
||||
current = eval_with_rewind(lst.as_pair()->car, env);
|
||||
if (!truthy(current)) {
|
||||
return SymbolObject::make_new(reader.symbolTable, "#f");
|
||||
return m_false_object;
|
||||
}
|
||||
lst = lst.as_pair()->cdr;
|
||||
} else if (lst.type == ObjectType::EMPTY_LIST) {
|
||||
@@ -1000,7 +1218,7 @@ Object Interpreter::eval_while(const Object& form,
|
||||
throw_eval_error(form, "while must have condition and body");
|
||||
}
|
||||
|
||||
Object rv = SymbolObject::make_new(reader.symbolTable, "#f");
|
||||
Object rv = m_false_object;
|
||||
while (truthy(eval_with_rewind(condition, env))) {
|
||||
rv = eval_list_return_last(form, body, env);
|
||||
}
|
||||
@@ -1126,7 +1344,7 @@ Object Interpreter::eval_try_load_file(const Object& form,
|
||||
|
||||
auto path = {args.unnamed.at(0).as_string()->data};
|
||||
if (!fs::exists(file_util::get_file_path(path))) {
|
||||
return SymbolObject::make_new(reader.symbolTable, "#f");
|
||||
return m_false_object;
|
||||
}
|
||||
|
||||
Object o;
|
||||
@@ -1141,7 +1359,7 @@ Object Interpreter::eval_try_load_file(const Object& form,
|
||||
} catch (std::runtime_error& e) {
|
||||
throw_eval_error(form, std::string("eval error inside of try-load-file:\n") + e.what());
|
||||
}
|
||||
return SymbolObject::make_new(reader.symbolTable, "#t");
|
||||
return m_true_object;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1177,6 +1395,14 @@ Object Interpreter::eval_inspect(const Object& form,
|
||||
return Object::make_empty_list();
|
||||
}
|
||||
|
||||
const Object& Interpreter::true_or_false(bool val) {
|
||||
if (val) {
|
||||
return m_true_object;
|
||||
} else {
|
||||
return m_false_object;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Fancy equality check (using Object::operator==)
|
||||
*/
|
||||
@@ -1185,8 +1411,7 @@ Object Interpreter::eval_equals(const Object& form,
|
||||
const std::shared_ptr<EnvironmentObject>& env) {
|
||||
(void)env;
|
||||
vararg_check(form, args, {{}, {}}, {});
|
||||
return SymbolObject::make_new(reader.symbolTable,
|
||||
args.unnamed[0] == args.unnamed[1] ? "#t" : "#f");
|
||||
return true_or_false(args.unnamed[0] == args.unnamed[1]);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1430,7 +1655,7 @@ Object Interpreter::eval_numequals(const Object& form,
|
||||
return Object::make_empty_list();
|
||||
}
|
||||
|
||||
return SymbolObject::make_new(reader.symbolTable, result ? "#t" : "#f");
|
||||
return true_or_false(result);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -1441,7 +1666,7 @@ Object Interpreter::num_lt(const Object& form,
|
||||
(void)env;
|
||||
T a = number<T>(args.unnamed[0]);
|
||||
T b = number<T>(args.unnamed[1]);
|
||||
return SymbolObject::make_new(reader.symbolTable, (a < b) ? "#t" : "#f");
|
||||
return true_or_false(a < b);
|
||||
}
|
||||
|
||||
Object Interpreter::eval_lt(const Object& form,
|
||||
@@ -1469,7 +1694,7 @@ Object Interpreter::num_gt(const Object& form,
|
||||
(void)env;
|
||||
T a = number<T>(args.unnamed[0]);
|
||||
T b = number<T>(args.unnamed[1]);
|
||||
return SymbolObject::make_new(reader.symbolTable, (a > b) ? "#t" : "#f");
|
||||
return true_or_false(a > b);
|
||||
}
|
||||
|
||||
Object Interpreter::eval_gt(const Object& form,
|
||||
@@ -1497,7 +1722,7 @@ Object Interpreter::num_leq(const Object& form,
|
||||
(void)env;
|
||||
T a = number<T>(args.unnamed[0]);
|
||||
T b = number<T>(args.unnamed[1]);
|
||||
return SymbolObject::make_new(reader.symbolTable, (a <= b) ? "#t" : "#f");
|
||||
return true_or_false(a <= b);
|
||||
}
|
||||
|
||||
Object Interpreter::eval_leq(const Object& form,
|
||||
@@ -1525,7 +1750,7 @@ Object Interpreter::num_geq(const Object& form,
|
||||
(void)env;
|
||||
T a = number<T>(args.unnamed[0]);
|
||||
T b = number<T>(args.unnamed[1]);
|
||||
return SymbolObject::make_new(reader.symbolTable, (a >= b) ? "#t" : "#f");
|
||||
return true_or_false(a >= b);
|
||||
}
|
||||
|
||||
Object Interpreter::eval_geq(const Object& form,
|
||||
@@ -1591,7 +1816,7 @@ Object Interpreter::eval_gensym(const Object& form,
|
||||
const std::shared_ptr<EnvironmentObject>& env) {
|
||||
(void)env;
|
||||
vararg_check(form, args, {}, {});
|
||||
return SymbolObject::make_new(reader.symbolTable, "gensym" + std::to_string(gensym_id++));
|
||||
return Object::make_symbol(&reader.symbolTable, ("gensym" + std::to_string(gensym_id++)).c_str());
|
||||
}
|
||||
|
||||
Object Interpreter::eval_cons(const Object& form,
|
||||
@@ -1607,7 +1832,7 @@ Object Interpreter::eval_null(const Object& form,
|
||||
const std::shared_ptr<EnvironmentObject>& env) {
|
||||
(void)env;
|
||||
vararg_check(form, args, {{}}, {});
|
||||
return SymbolObject::make_new(reader.symbolTable, args.unnamed[0].is_empty_list() ? "#t" : "#f");
|
||||
return true_or_false(args.unnamed[0].is_empty_list());
|
||||
}
|
||||
|
||||
Object Interpreter::eval_type(const Object& form,
|
||||
@@ -1616,15 +1841,15 @@ Object Interpreter::eval_type(const Object& form,
|
||||
(void)env;
|
||||
vararg_check(form, args, {{ObjectType::SYMBOL}, {}}, {});
|
||||
|
||||
auto kv = string_to_type.find(args.unnamed[0].as_symbol()->name);
|
||||
auto kv = string_to_type.find(args.unnamed[0].as_symbol().name_ptr);
|
||||
if (kv == string_to_type.end()) {
|
||||
throw_eval_error(form, "invalid type given to type?");
|
||||
}
|
||||
|
||||
if (args.unnamed[1].type == kv->second) {
|
||||
return SymbolObject::make_new(reader.symbolTable, "#t");
|
||||
return m_true_object;
|
||||
} else {
|
||||
return SymbolObject::make_new(reader.symbolTable, "#f");
|
||||
return m_false_object;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1729,9 +1954,9 @@ Object Interpreter::eval_string_starts_with(const Object& form,
|
||||
auto& suffix = args.unnamed.at(1).as_string()->data;
|
||||
|
||||
if (str_util::starts_with(str, suffix)) {
|
||||
return SymbolObject::make_new(reader.symbolTable, "#t");
|
||||
return m_true_object;
|
||||
}
|
||||
return SymbolObject::make_new(reader.symbolTable, "#f");
|
||||
return m_false_object;
|
||||
}
|
||||
|
||||
Object Interpreter::eval_string_ends_with(const Object& form,
|
||||
@@ -1743,9 +1968,9 @@ Object Interpreter::eval_string_ends_with(const Object& form,
|
||||
auto& suffix = args.unnamed.at(1).as_string()->data;
|
||||
|
||||
if (str_util::ends_with(str, suffix)) {
|
||||
return SymbolObject::make_new(reader.symbolTable, "#t");
|
||||
return m_true_object;
|
||||
}
|
||||
return SymbolObject::make_new(reader.symbolTable, "#f");
|
||||
return m_false_object;
|
||||
}
|
||||
|
||||
Object Interpreter::eval_string_split(const Object& form,
|
||||
@@ -1792,14 +2017,14 @@ Object Interpreter::eval_symbol_to_string(const Object& form,
|
||||
Arguments& args,
|
||||
const std::shared_ptr<EnvironmentObject>&) {
|
||||
vararg_check(form, args, {ObjectType::SYMBOL}, {});
|
||||
return StringObject::make_new(args.unnamed.at(0).as_symbol()->name);
|
||||
return StringObject::make_new(args.unnamed.at(0).as_symbol().name_ptr);
|
||||
}
|
||||
|
||||
Object Interpreter::eval_string_to_symbol(const Object& form,
|
||||
Arguments& args,
|
||||
const std::shared_ptr<EnvironmentObject>&) {
|
||||
vararg_check(form, args, {ObjectType::STRING}, {});
|
||||
return SymbolObject::make_new(reader.symbolTable, args.unnamed.at(0).as_string()->data);
|
||||
return Object::make_symbol(&reader.symbolTable, args.unnamed.at(0).as_string()->data.c_str());
|
||||
}
|
||||
|
||||
Object Interpreter::eval_int_to_string(const Object& form,
|
||||
@@ -1846,7 +2071,7 @@ Object Interpreter::eval_hash_table_set(const Object& form,
|
||||
vararg_check(form, args, {ObjectType::STRING_HASH_TABLE, {}, {}}, {});
|
||||
const char* str = nullptr;
|
||||
if (args.unnamed.at(1).is_symbol()) {
|
||||
str = args.unnamed.at(1).as_symbol()->name.c_str();
|
||||
str = args.unnamed.at(1).as_symbol().name_ptr;
|
||||
} else if (args.unnamed.at(1).is_string()) {
|
||||
str = args.unnamed.at(1).as_string()->data.c_str();
|
||||
} else {
|
||||
@@ -1868,7 +2093,7 @@ Object Interpreter::eval_hash_table_try_ref(const Object& form,
|
||||
|
||||
const char* str = nullptr;
|
||||
if (args.unnamed.at(1).is_symbol()) {
|
||||
str = args.unnamed.at(1).as_symbol()->name.c_str();
|
||||
str = args.unnamed.at(1).as_symbol().name_ptr;
|
||||
} else if (args.unnamed.at(1).is_string()) {
|
||||
str = args.unnamed.at(1).as_string()->data.c_str();
|
||||
} else {
|
||||
@@ -1877,10 +2102,9 @@ Object Interpreter::eval_hash_table_try_ref(const Object& form,
|
||||
const auto& it = table->data.find(str);
|
||||
if (it == table->data.end()) {
|
||||
// not in table
|
||||
return PairObject::make_new(SymbolObject::make_new(reader.symbolTable, "#f"),
|
||||
Object::make_empty_list());
|
||||
return PairObject::make_new(m_false_object, Object::make_empty_list());
|
||||
} else {
|
||||
return PairObject::make_new(SymbolObject::make_new(reader.symbolTable, "#t"), it->second);
|
||||
return PairObject::make_new(m_true_object, it->second);
|
||||
}
|
||||
}
|
||||
} // namespace goos
|
||||
|
||||
+43
-13
@@ -25,7 +25,7 @@ class Interpreter {
|
||||
void set_global_variable_to_int(const std::string& name, int value);
|
||||
Object eval(Object obj, const std::shared_ptr<EnvironmentObject>& env);
|
||||
Object intern(const std::string& name);
|
||||
HeapObject* intern_ptr(const std::string& name);
|
||||
InternedSymbolPtr intern_ptr(const std::string& name);
|
||||
void disable_printfs();
|
||||
Object eval_symbol(const Object& sym, const std::shared_ptr<EnvironmentObject>& env);
|
||||
bool eval_symbol(const Object& sym,
|
||||
@@ -55,7 +55,7 @@ class Interpreter {
|
||||
private:
|
||||
friend class Goal;
|
||||
void load_goos_library();
|
||||
void define_var_in_env(Object& env, Object& var, const std::string& name);
|
||||
void define_var_in_env(Object& env, const Object& var, const std::string& name);
|
||||
void expect_env(const Object& form, const Object& o);
|
||||
void vararg_check(
|
||||
const Object& form,
|
||||
@@ -264,6 +264,16 @@ class Interpreter {
|
||||
Object eval_while(const Object& form,
|
||||
const Object& rest,
|
||||
const std::shared_ptr<EnvironmentObject>& env);
|
||||
Object eval_let(const Object& form,
|
||||
const Object& rest,
|
||||
const std::shared_ptr<EnvironmentObject>& env);
|
||||
Object eval_let_star(const Object& form,
|
||||
const Object& rest,
|
||||
const std::shared_ptr<EnvironmentObject>& env);
|
||||
Object eval_let_common(const Object& form,
|
||||
const Object& rest,
|
||||
const std::shared_ptr<EnvironmentObject>& env,
|
||||
bool star);
|
||||
|
||||
Object eval_make_string_hash_table(const Object& form,
|
||||
Arguments& args,
|
||||
@@ -275,26 +285,46 @@ class Interpreter {
|
||||
Arguments& args,
|
||||
const std::shared_ptr<EnvironmentObject>& env);
|
||||
|
||||
const Object& true_or_false(bool val);
|
||||
|
||||
void init_special_forms(
|
||||
const std::unordered_map<std::string,
|
||||
Object (Interpreter::*)(const Object&,
|
||||
const Object&,
|
||||
const std::shared_ptr<EnvironmentObject>&)>&
|
||||
forms);
|
||||
|
||||
void init_builtin_forms(
|
||||
const std::unordered_map<std::string,
|
||||
Object (Interpreter::*)(const Object&,
|
||||
Arguments&,
|
||||
const std::shared_ptr<EnvironmentObject>&)>&
|
||||
forms);
|
||||
|
||||
bool want_exit = false;
|
||||
bool disable_printing = false;
|
||||
|
||||
std::unordered_map<std::string,
|
||||
Object (Interpreter::*)(const Object& form,
|
||||
Arguments& args,
|
||||
const std::shared_ptr<EnvironmentObject>& env)>
|
||||
std::unordered_map<
|
||||
void*,
|
||||
Object (Interpreter::*)(const Object&, Arguments&, const std::shared_ptr<EnvironmentObject>&)>
|
||||
builtin_forms;
|
||||
|
||||
std::unordered_map<
|
||||
std::string,
|
||||
std::function<Object(const Object&, Arguments&, const std::shared_ptr<EnvironmentObject>&)>>
|
||||
std::vector<std::pair<
|
||||
void*,
|
||||
std::function<Object(const Object&, Arguments&, const std::shared_ptr<EnvironmentObject>&)>>>
|
||||
m_custom_forms;
|
||||
std::unordered_map<std::string,
|
||||
Object (Interpreter::*)(const Object& form,
|
||||
const Object& rest,
|
||||
const std::shared_ptr<EnvironmentObject>& env)>
|
||||
|
||||
std::vector<std::pair<void*,
|
||||
Object (Interpreter::*)(const Object& form,
|
||||
const Object& rest,
|
||||
const std::shared_ptr<EnvironmentObject>& env)>>
|
||||
special_forms;
|
||||
int64_t gensym_id = 0;
|
||||
|
||||
std::unordered_map<std::string, ObjectType> string_to_type;
|
||||
|
||||
const char* m_false_sym = nullptr;
|
||||
const char* m_true_sym = nullptr;
|
||||
Object m_false_object, m_true_object;
|
||||
};
|
||||
} // namespace goos
|
||||
|
||||
+84
-10
@@ -44,12 +44,90 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "common/util/crc32.h"
|
||||
#include "common/util/print_float.h"
|
||||
|
||||
#include "third-party/fmt/core.h"
|
||||
|
||||
namespace goos {
|
||||
|
||||
SymbolTable::SymbolTable() {
|
||||
m_power_of_two_size = 1; // 2 ^ 1 = 2
|
||||
m_entries.resize(2);
|
||||
m_used_entries = 0;
|
||||
m_next_resize = (m_entries.size() * kMaxUsed);
|
||||
m_mask = 0b1;
|
||||
}
|
||||
|
||||
SymbolTable::~SymbolTable() {
|
||||
for (auto& e : m_entries) {
|
||||
delete[] e.name;
|
||||
}
|
||||
}
|
||||
|
||||
InternedSymbolPtr SymbolTable::intern(const char* str) {
|
||||
InternedSymbolPtr result;
|
||||
size_t string_len = strlen(str);
|
||||
u32 hash = crc32((const u8*)str, string_len);
|
||||
|
||||
// probe
|
||||
for (u32 i = 0; i < m_entries.size(); i++) {
|
||||
u32 slot_addr = (hash + i) & m_mask;
|
||||
auto& slot = m_entries[slot_addr];
|
||||
if (!slot.name) {
|
||||
// not found, insert!
|
||||
slot.hash = hash;
|
||||
auto* name = new char[string_len + 1];
|
||||
memcpy(name, str, string_len + 1);
|
||||
slot.name = name;
|
||||
m_used_entries++;
|
||||
|
||||
if (m_used_entries >= m_next_resize) {
|
||||
resize();
|
||||
return intern(str);
|
||||
}
|
||||
return {name};
|
||||
} else {
|
||||
if (slot.hash != hash) {
|
||||
continue; // bad hash
|
||||
}
|
||||
if (strcmp(slot.name, str) != 0) {
|
||||
continue; // bad name
|
||||
}
|
||||
return {slot.name};
|
||||
}
|
||||
}
|
||||
|
||||
// should be impossible to reach.
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void SymbolTable::resize() {
|
||||
m_power_of_two_size++;
|
||||
m_mask = (1U << m_power_of_two_size) - 1;
|
||||
|
||||
std::vector<Entry> new_entries(m_entries.size() * 2);
|
||||
for (const auto& old_entry : m_entries) {
|
||||
if (old_entry.name) {
|
||||
bool done = false;
|
||||
for (u32 i = 0; i < new_entries.size(); i++) {
|
||||
u32 slot_addr = (old_entry.hash + i) & m_mask;
|
||||
auto& slot = new_entries[slot_addr];
|
||||
if (!slot.name) {
|
||||
slot.name = old_entry.name;
|
||||
slot.hash = old_entry.hash;
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT(done);
|
||||
}
|
||||
}
|
||||
|
||||
m_entries = std::move(new_entries);
|
||||
m_next_resize = kMaxUsed * m_entries.size();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Convert type to string (name in brackets)
|
||||
*/
|
||||
@@ -137,14 +215,9 @@ std::string fixed_to_string(char x) {
|
||||
return {buff};
|
||||
}
|
||||
|
||||
/*!
|
||||
* Create a new symbol object by interning
|
||||
*/
|
||||
Object SymbolObject::make_new(SymbolTable& st, const std::string& name) {
|
||||
Object obj;
|
||||
obj.type = ObjectType::SYMBOL;
|
||||
obj.heap_obj = st.intern(name);
|
||||
return obj;
|
||||
template <>
|
||||
std::string fixed_to_string(InternedSymbolPtr x) {
|
||||
return x.name_ptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -238,8 +311,9 @@ bool Object::operator==(const Object& other) const {
|
||||
return float_obj == other.float_obj;
|
||||
case ObjectType::CHAR:
|
||||
return char_obj == other.char_obj;
|
||||
|
||||
case ObjectType::SYMBOL:
|
||||
return symbol_obj == other.symbol_obj;
|
||||
|
||||
case ObjectType::ENVIRONMENT:
|
||||
case ObjectType::LAMBDA:
|
||||
case ObjectType::MACRO:
|
||||
@@ -271,7 +345,7 @@ bool Object::operator==(const Object& other) const {
|
||||
}
|
||||
|
||||
bool Object::is_symbol(const std::string& name) const {
|
||||
return is_symbol() && as_symbol()->name == name;
|
||||
return is_symbol() && name == as_symbol().name_ptr;
|
||||
}
|
||||
|
||||
bool Object::is_string(const std::string& val) const {
|
||||
|
||||
+105
-72
@@ -43,6 +43,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
@@ -57,9 +58,6 @@
|
||||
|
||||
namespace goos {
|
||||
|
||||
using FloatType = double;
|
||||
using IntType = s64;
|
||||
|
||||
/*!
|
||||
* All objects have one of these kinds
|
||||
*/
|
||||
@@ -71,9 +69,9 @@ enum class ObjectType : u8 {
|
||||
INTEGER,
|
||||
FLOAT,
|
||||
CHAR,
|
||||
SYMBOL,
|
||||
|
||||
// allocated
|
||||
SYMBOL,
|
||||
STRING,
|
||||
PAIR,
|
||||
ARRAY,
|
||||
@@ -87,6 +85,29 @@ enum class ObjectType : u8 {
|
||||
std::string object_type_to_string(ObjectType kind);
|
||||
|
||||
// Some objects are "fixed", meaning they are stored inline in the Object, and not heap allocated.
|
||||
// These use value semantics and are copied on object assignment.
|
||||
|
||||
// For int/float, these are simply double/int64_t
|
||||
using FloatType = double;
|
||||
using IntType = s64;
|
||||
|
||||
// For symbols, we simply store a pointer to the symbol's name string.
|
||||
// this is wrapped in a type just to avoid confusion with normal const char*.
|
||||
struct InternedSymbolPtr {
|
||||
const char* name_ptr;
|
||||
|
||||
struct hash {
|
||||
auto operator()(const InternedSymbolPtr& x) const {
|
||||
return std::hash<const void*>()((const void*)x.name_ptr);
|
||||
}
|
||||
};
|
||||
bool operator==(const char* msg) const { return strcmp(msg, name_ptr) == 0; }
|
||||
bool operator!=(const char* msg) const { return strcmp(msg, name_ptr) != 0; }
|
||||
bool operator==(const std::string& str) const { return str == name_ptr; }
|
||||
bool operator!=(const std::string& str) const { return str != name_ptr; }
|
||||
bool operator==(const InternedSymbolPtr& other) const { return other.name_ptr == name_ptr; }
|
||||
bool operator!=(const InternedSymbolPtr& other) const { return other.name_ptr != name_ptr; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* By default, convert a fixed object data to string with std::to_string.
|
||||
@@ -115,6 +136,31 @@ std::string fixed_to_string<char>(char);
|
||||
template <>
|
||||
std::string fixed_to_string<IntType>(IntType);
|
||||
|
||||
template <>
|
||||
std::string fixed_to_string<InternedSymbolPtr>(InternedSymbolPtr);
|
||||
|
||||
class SymbolTable {
|
||||
public:
|
||||
SymbolTable(const SymbolTable&) = delete;
|
||||
SymbolTable& operator=(const SymbolTable&) = delete;
|
||||
SymbolTable();
|
||||
~SymbolTable();
|
||||
InternedSymbolPtr intern(const char* str);
|
||||
|
||||
private:
|
||||
void resize();
|
||||
int m_power_of_two_size = 0;
|
||||
struct Entry {
|
||||
u32 hash = 0;
|
||||
const char* name = nullptr;
|
||||
};
|
||||
std::vector<Entry> m_entries;
|
||||
int m_used_entries = 0;
|
||||
int m_next_resize = 0;
|
||||
u32 m_mask = 0;
|
||||
static constexpr float kMaxUsed = 0.7;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Common implementation for a fixed object
|
||||
*/
|
||||
@@ -139,6 +185,8 @@ class FixedObject {
|
||||
return object_type_to_string(ObjectType::INTEGER);
|
||||
if (std::is_same<T, char>())
|
||||
return object_type_to_string(ObjectType::CHAR);
|
||||
if (std::is_same<T, InternedSymbolPtr>())
|
||||
return object_type_to_string(ObjectType::SYMBOL);
|
||||
throw std::runtime_error("Unsupported FixedObject type");
|
||||
}
|
||||
};
|
||||
@@ -149,6 +197,7 @@ class FixedObject {
|
||||
using IntegerObject = FixedObject<int64_t>;
|
||||
using FloatObject = FixedObject<double>;
|
||||
using CharObject = FixedObject<char>;
|
||||
using SymbolObject = FixedObject<InternedSymbolPtr>;
|
||||
|
||||
// Other objects are separate allocated on the heap. These objects should be HeapObjects.
|
||||
|
||||
@@ -162,7 +211,6 @@ class HeapObject {
|
||||
// forward declare all HeapObjects
|
||||
class PairObject;
|
||||
class EnvironmentObject;
|
||||
class SymbolObject;
|
||||
class StringObject;
|
||||
class LambdaObject;
|
||||
class MacroObject;
|
||||
@@ -180,6 +228,7 @@ class Object {
|
||||
IntegerObject integer_obj;
|
||||
FloatObject float_obj;
|
||||
CharObject char_obj;
|
||||
SymbolObject symbol_obj;
|
||||
};
|
||||
|
||||
ObjectType type = ObjectType::INVALID;
|
||||
@@ -192,6 +241,8 @@ class Object {
|
||||
return float_obj.print();
|
||||
case ObjectType::CHAR:
|
||||
return char_obj.print();
|
||||
case ObjectType::SYMBOL:
|
||||
return symbol_obj.print();
|
||||
case ObjectType::EMPTY_LIST:
|
||||
return "()";
|
||||
default:
|
||||
@@ -207,6 +258,8 @@ class Object {
|
||||
return float_obj.inspect();
|
||||
case ObjectType::CHAR:
|
||||
return char_obj.inspect();
|
||||
case ObjectType::SYMBOL:
|
||||
return symbol_obj.inspect();
|
||||
case ObjectType::EMPTY_LIST:
|
||||
return "[empty list] ()\n";
|
||||
default:
|
||||
@@ -244,16 +297,30 @@ class Object {
|
||||
return o;
|
||||
}
|
||||
|
||||
static Object make_symbol(SymbolTable* table, const char* name) {
|
||||
Object o;
|
||||
o.type = ObjectType::SYMBOL;
|
||||
o.symbol_obj.value = table->intern(name);
|
||||
return o;
|
||||
}
|
||||
|
||||
PairObject* as_pair() const;
|
||||
EnvironmentObject* as_env() const;
|
||||
std::shared_ptr<EnvironmentObject> as_env_ptr() const;
|
||||
SymbolObject* as_symbol() const;
|
||||
StringObject* as_string() const;
|
||||
LambdaObject* as_lambda() const;
|
||||
MacroObject* as_macro() const;
|
||||
ArrayObject* as_array() const;
|
||||
StringHashTableObject* as_string_hash_table() const;
|
||||
|
||||
const InternedSymbolPtr& as_symbol() const {
|
||||
if (type != ObjectType::SYMBOL) {
|
||||
throw std::runtime_error("as_symbol called on a " + object_type_to_string(type) + " " +
|
||||
print());
|
||||
}
|
||||
return symbol_obj.value;
|
||||
}
|
||||
|
||||
IntType& as_int() {
|
||||
if (type != ObjectType::INTEGER) {
|
||||
throw std::runtime_error("as_int called on a " + object_type_to_string(type) + " " + print());
|
||||
@@ -315,56 +382,6 @@ class Object {
|
||||
bool operator!=(const Object& other) const { return !((*this) == other); }
|
||||
};
|
||||
|
||||
class SymbolTable;
|
||||
|
||||
/*!
|
||||
* A Symbol Object, which is just a wrapper around a string.
|
||||
* The make_new function will correctly
|
||||
*/
|
||||
class SymbolObject : public HeapObject {
|
||||
public:
|
||||
std::string name;
|
||||
explicit SymbolObject(std::string _name) : name(std::move(_name)) {}
|
||||
static Object make_new(SymbolTable& st, const std::string& name);
|
||||
|
||||
std::string print() const override { return name; }
|
||||
|
||||
std::string inspect() const override { return "[symbol] " + name + "\n"; }
|
||||
|
||||
~SymbolObject() = default;
|
||||
};
|
||||
|
||||
/*!
|
||||
* A Symbol Table, which holds all symbols.
|
||||
*/
|
||||
class SymbolTable {
|
||||
public:
|
||||
std::shared_ptr<HeapObject> intern(const std::string& name) {
|
||||
const auto& kv = table.find(name);
|
||||
if (kv == table.end()) {
|
||||
auto iter = table.insert({name, std::make_shared<SymbolObject>(name)});
|
||||
return (*iter.first).second;
|
||||
} else {
|
||||
return kv->second;
|
||||
}
|
||||
}
|
||||
|
||||
HeapObject* intern_ptr(const std::string& name) {
|
||||
const auto& kv = table.find(name);
|
||||
if (kv == table.end()) {
|
||||
auto iter = table.insert({name, std::make_shared<SymbolObject>(name)});
|
||||
return (*iter.first).second.get();
|
||||
} else {
|
||||
return kv->second.get();
|
||||
}
|
||||
}
|
||||
|
||||
~SymbolTable() = default;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, std::shared_ptr<HeapObject>> table;
|
||||
};
|
||||
|
||||
class StringObject : public HeapObject {
|
||||
public:
|
||||
std::string data;
|
||||
@@ -439,14 +456,41 @@ class PairObject : public HeapObject {
|
||||
~PairObject() = default;
|
||||
};
|
||||
|
||||
class EnvironmentMap {
|
||||
public:
|
||||
EnvironmentMap(const EnvironmentMap&) = delete;
|
||||
EnvironmentMap& operator=(const EnvironmentMap&) = delete;
|
||||
EnvironmentMap();
|
||||
Object* lookup(InternedSymbolPtr ptr);
|
||||
void set(InternedSymbolPtr ptr, const Object& obj);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
struct Entry {
|
||||
const char* key = nullptr;
|
||||
Object value;
|
||||
};
|
||||
std::vector<Entry> m_entries;
|
||||
|
||||
void resize();
|
||||
int m_power_of_two_size = 0;
|
||||
int m_used_entries = 0;
|
||||
int m_next_resize = 0;
|
||||
u32 m_mask = 0;
|
||||
static constexpr float kMaxUsed = 0.7;
|
||||
};
|
||||
|
||||
class EnvironmentObject : public HeapObject {
|
||||
public:
|
||||
std::string name;
|
||||
std::shared_ptr<EnvironmentObject> parent_env;
|
||||
|
||||
// the symbols will be stored in the symbol table and never removed, so we don't need shared
|
||||
// pointers here.
|
||||
std::unordered_map<HeapObject*, Object> vars;
|
||||
// note: this is keyed on the address in the symbol table.
|
||||
EnvironmentMap vars;
|
||||
|
||||
// this find work by any name string
|
||||
Object* find(const char* n, SymbolTable* st) { return vars.lookup(st->intern(n)); }
|
||||
Object* find(InternedSymbolPtr ptr) { return vars.lookup(ptr); }
|
||||
|
||||
EnvironmentObject() = default;
|
||||
|
||||
@@ -478,11 +522,8 @@ class EnvironmentObject : public HeapObject {
|
||||
|
||||
std::string inspect() const override {
|
||||
std::string result = "[environment]\n name: " + name +
|
||||
"\n parent: " + (parent_env ? parent_env->print() : "NONE") +
|
||||
"\n vars:\n";
|
||||
for (const auto& kv : vars) {
|
||||
result += " " + kv.first->print() + ": " + kv.second.print() + "\n";
|
||||
}
|
||||
"\n parent: " + (parent_env ? parent_env->print() : "NONE") + "\n";
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
@@ -662,14 +703,6 @@ inline std::shared_ptr<EnvironmentObject> Object::as_env_ptr() const {
|
||||
return std::dynamic_pointer_cast<EnvironmentObject>(heap_obj);
|
||||
}
|
||||
|
||||
inline SymbolObject* Object::as_symbol() const {
|
||||
if (type != ObjectType::SYMBOL) {
|
||||
throw std::runtime_error("as_symbol called on a " + object_type_to_string(type) + " " +
|
||||
print());
|
||||
}
|
||||
return static_cast<SymbolObject*>(heap_obj.get());
|
||||
}
|
||||
|
||||
inline StringObject* Object::as_string() const {
|
||||
if (type != ObjectType::STRING) {
|
||||
throw std::runtime_error("as_string called on a " + object_type_to_string(type) + " " +
|
||||
|
||||
@@ -12,12 +12,12 @@ bool get_va(const goos::Object& rest, std::string* err_string, goos::Arguments*
|
||||
auto arg = current.as_pair()->car;
|
||||
|
||||
// did we get a ":keyword"
|
||||
if (arg.is_symbol() && arg.as_symbol()->name.at(0) == ':') {
|
||||
auto key_name = arg.as_symbol()->name.substr(1);
|
||||
if (arg.is_symbol() && arg.as_symbol().name_ptr[0] == ':') {
|
||||
auto key_name = arg.as_symbol().name_ptr + 1;
|
||||
|
||||
// check for multiple definition of key
|
||||
if (args.named.find(key_name) != args.named.end()) {
|
||||
*err_string = "Key argument " + key_name + " multiply defined";
|
||||
*err_string = fmt::format("Key argument {} multiply defined", key_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ void add_to_token_list(const goos::Object& obj, std::vector<FormToken>* tokens)
|
||||
// look for a (quote x) to print as 'x
|
||||
|
||||
auto& first = obj.as_pair()->car;
|
||||
if (first.is_symbol() && first.as_symbol()->name == "quote") {
|
||||
if (first.is_symbol() && first.as_symbol() == "quote") {
|
||||
auto& second = obj.as_pair()->cdr;
|
||||
if (second.is_pair() && second.as_pair()->cdr.is_empty_list()) {
|
||||
tokens->emplace_back(FormToken::TokenKind::QUOTE);
|
||||
|
||||
@@ -49,7 +49,7 @@ goos::Reader& get_pretty_printer_reader() {
|
||||
|
||||
goos::Object to_symbol(const std::string& str) {
|
||||
std::lock_guard<std::mutex> guard(pretty_printer_reader_mutex);
|
||||
return goos::SymbolObject::make_new(get_pretty_printer_reader().symbolTable, str);
|
||||
return goos::Object::make_symbol(&get_pretty_printer_reader().symbolTable, str.c_str());
|
||||
}
|
||||
|
||||
goos::Object new_string(const std::string& str) {
|
||||
|
||||
+57
-16
@@ -286,7 +286,7 @@ Object Reader::internal_read(std::shared_ptr<SourceText> text,
|
||||
try {
|
||||
auto objs = read_list(ts, false);
|
||||
if (add_top_level) {
|
||||
return PairObject::make_new(SymbolObject::make_new(symbolTable, "top-level"), objs);
|
||||
return PairObject::make_new(Object::make_symbol(&symbolTable, "top-level"), objs);
|
||||
} else {
|
||||
return objs;
|
||||
}
|
||||
@@ -459,12 +459,51 @@ bool Reader::read_array(TextStream& stream, Object& o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ListBuilder {
|
||||
Object head;
|
||||
std::shared_ptr<PairObject> prev_tail;
|
||||
std::shared_ptr<PairObject> tail;
|
||||
int size = 0;
|
||||
|
||||
ListBuilder() { head = Object::make_empty_list(); }
|
||||
|
||||
void push_back(Object&& o) {
|
||||
size++;
|
||||
if (!tail) {
|
||||
tail = std::make_shared<PairObject>(o, Object{});
|
||||
head.type = ObjectType::PAIR;
|
||||
head.heap_obj = tail;
|
||||
} else {
|
||||
auto next = std::make_shared<PairObject>(o, Object{});
|
||||
tail->cdr.type = ObjectType::PAIR;
|
||||
tail->cdr.heap_obj = next;
|
||||
prev_tail = std::move(tail);
|
||||
tail = std::move(next);
|
||||
}
|
||||
}
|
||||
|
||||
Object pop_back() {
|
||||
auto obj = tail->car;
|
||||
tail = std::move(prev_tail);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void finalize() {
|
||||
if (tail) {
|
||||
tail->cdr = Object::make_empty_list();
|
||||
} else {
|
||||
head = Object::make_empty_list();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* Call this on the character after the open paren.
|
||||
*/
|
||||
Object Reader::read_list(TextStream& ts, bool expect_close_paren) {
|
||||
ts.seek_past_whitespace_and_comments();
|
||||
std::vector<Object> objects;
|
||||
// std::vector<Object> objects;
|
||||
ListBuilder list_builder;
|
||||
|
||||
bool got_close_paren = false; // does this list end?
|
||||
bool got_dot = false; // did we get a . ?
|
||||
@@ -506,22 +545,23 @@ Object Reader::read_list(TextStream& ts, bool expect_close_paren) {
|
||||
}
|
||||
|
||||
// inserter function, used to properly insert a next object
|
||||
auto insert_object = [&](const Object& o) {
|
||||
auto insert_object = [&](Object&& o) {
|
||||
if (got_thing_after_dot) {
|
||||
throw_reader_error(ts, "A list cannot have multiple entries after the dot", -1);
|
||||
}
|
||||
|
||||
if (reader_macro_string_stack.empty()) {
|
||||
objects.push_back(o);
|
||||
list_builder.push_back(std::move(o));
|
||||
// objects.push_back(o);
|
||||
} else {
|
||||
Object to_push_back = o;
|
||||
Object to_push_back = std::move(o);
|
||||
while (!reader_macro_string_stack.empty()) {
|
||||
to_push_back =
|
||||
build_list({SymbolObject::make_new(symbolTable, reader_macro_string_stack.back()),
|
||||
to_push_back});
|
||||
to_push_back = build_list(
|
||||
{Object::make_symbol(&symbolTable, reader_macro_string_stack.back().c_str()),
|
||||
to_push_back});
|
||||
reader_macro_string_stack.pop_back();
|
||||
}
|
||||
objects.push_back(to_push_back);
|
||||
list_builder.push_back(std::move(to_push_back));
|
||||
}
|
||||
|
||||
// remember if we got an object after the dot
|
||||
@@ -551,7 +591,7 @@ Object Reader::read_list(TextStream& ts, bool expect_close_paren) {
|
||||
|
||||
if (read_object(tok, ts, obj)) {
|
||||
ts.seek_past_whitespace_and_comments();
|
||||
insert_object(obj);
|
||||
insert_object(std::move(obj));
|
||||
} else {
|
||||
throw_reader_error(ts, "invalid token encountered in reader: " + tok.text,
|
||||
-int(tok.text.size()));
|
||||
@@ -574,12 +614,12 @@ Object Reader::read_list(TextStream& ts, bool expect_close_paren) {
|
||||
|
||||
// build up list or improper list, link it, and return!
|
||||
if (got_thing_after_dot) {
|
||||
if (objects.size() < 2) {
|
||||
if (list_builder.size < 2) {
|
||||
throw_reader_error(ts, "A list with a dot must have at least one thing before the dot", -1);
|
||||
}
|
||||
auto back = objects.back();
|
||||
objects.pop_back();
|
||||
auto rv = build_list(objects);
|
||||
auto back = list_builder.pop_back();
|
||||
list_builder.finalize();
|
||||
auto rv = list_builder.head;
|
||||
|
||||
auto lst = rv;
|
||||
while (true) {
|
||||
@@ -593,7 +633,8 @@ Object Reader::read_list(TextStream& ts, bool expect_close_paren) {
|
||||
db.link(rv, ts.text, start_offset);
|
||||
return rv;
|
||||
} else {
|
||||
auto rv = build_list(std::move(objects));
|
||||
list_builder.finalize();
|
||||
auto rv = list_builder.head;
|
||||
db.link(rv, ts.text, start_offset);
|
||||
return rv;
|
||||
}
|
||||
@@ -607,7 +648,7 @@ bool Reader::try_token_as_symbol(const Token& tok, Object& obj) {
|
||||
ASSERT(!tok.text.empty());
|
||||
char start = tok.text[0];
|
||||
if (m_valid_symbols_chars[(int)start]) {
|
||||
obj = SymbolObject::make_new(symbolTable, tok.text);
|
||||
obj = Object::make_symbol(&symbolTable, tok.text.c_str());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -13,20 +13,20 @@ void open_subtitle_project(const std::string& project_kind,
|
||||
goos::Reader reader;
|
||||
auto& proj = reader.read_from_file({file_path}).as_pair()->cdr.as_pair()->car;
|
||||
if (!proj.is_pair() || !proj.as_pair()->car.is_symbol() ||
|
||||
proj.as_pair()->car.as_symbol()->name != project_kind) {
|
||||
proj.as_pair()->car.as_symbol() != project_kind) {
|
||||
throw std::runtime_error(fmt::format("invalid project '{}'", project_kind));
|
||||
}
|
||||
|
||||
goos::for_each_in_list(proj.as_pair()->cdr, [&](const goos::Object& o) {
|
||||
if (o.is_pair() && o.as_pair()->cdr.is_pair()) {
|
||||
auto args = o.as_pair();
|
||||
auto& action = args->car.as_symbol()->name;
|
||||
auto& action = args->car.as_symbol();
|
||||
args = args->cdr.as_pair();
|
||||
|
||||
if (action == "file-json") {
|
||||
auto new_file = GameSubtitleDefinitionFile();
|
||||
while (true) {
|
||||
const auto& kwarg = args->car.as_symbol()->name;
|
||||
const auto& kwarg = args->car.as_symbol();
|
||||
args = args->cdr.as_pair();
|
||||
if (kwarg == ":language-id") {
|
||||
new_file.language_id = args->car.as_int();
|
||||
@@ -49,7 +49,7 @@ void open_subtitle_project(const std::string& project_kind,
|
||||
subtitle_files.push_back(new_file);
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
fmt::format("unknown action {} in {} project", action, project_kind));
|
||||
fmt::format("unknown action {} in {} project", action.name_ptr, project_kind));
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error(fmt::format("invalid entry in {} project", project_kind));
|
||||
|
||||
@@ -147,7 +147,7 @@ void parse_text_goal(const goos::Object& data,
|
||||
throw std::runtime_error("invalid text version entry");
|
||||
}
|
||||
|
||||
font = get_font_bank(ver_name.as_symbol()->name);
|
||||
font = get_font_bank(ver_name.as_symbol().name_ptr);
|
||||
}
|
||||
|
||||
else if (head.is_int()) {
|
||||
@@ -278,7 +278,7 @@ GameTextVersion parse_text_only_version(const goos::Object& data) {
|
||||
throw std::runtime_error("invalid text version entry");
|
||||
}
|
||||
|
||||
font = get_font_bank(ver_name.as_symbol()->name);
|
||||
font = get_font_bank(ver_name.as_symbol().name_ptr);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -294,14 +294,14 @@ void open_text_project(const std::string& kind,
|
||||
goos::Reader reader;
|
||||
auto& proj = reader.read_from_file({filename}).as_pair()->cdr.as_pair()->car;
|
||||
if (!proj.is_pair() || !proj.as_pair()->car.is_symbol() ||
|
||||
proj.as_pair()->car.as_symbol()->name != kind) {
|
||||
proj.as_pair()->car.as_symbol() != kind) {
|
||||
throw std::runtime_error(fmt::format("invalid {} project", kind));
|
||||
}
|
||||
|
||||
goos::for_each_in_list(proj.as_pair()->cdr, [&](const goos::Object& o) {
|
||||
if (o.is_pair() && o.as_pair()->cdr.is_pair()) {
|
||||
auto args = o.as_pair();
|
||||
auto& action = args->car.as_symbol()->name;
|
||||
auto& action = args->car.as_symbol();
|
||||
args = args->cdr.as_pair();
|
||||
|
||||
if (action == "file") {
|
||||
@@ -313,17 +313,18 @@ void open_text_project(const std::string& kind,
|
||||
} else if (action == "file-json") {
|
||||
auto& language_id = args->car.as_int();
|
||||
args = args->cdr.as_pair();
|
||||
auto& text_version = args->car.as_symbol()->name;
|
||||
auto& text_version = args->car.as_symbol();
|
||||
args = args->cdr.as_pair();
|
||||
std::optional<std::string> group_name = std::nullopt;
|
||||
group_name = args->car.as_string()->data;
|
||||
args = args->cdr.as_pair()->car.as_pair();
|
||||
goos::for_each_in_list(args->cdr.as_pair()->car, [&](const goos::Object& o) {
|
||||
text_files.push_back({GameTextDefinitionFile::Format::JSON, o.as_string()->data,
|
||||
(int)language_id, text_version, group_name});
|
||||
(int)language_id, text_version.name_ptr, group_name});
|
||||
});
|
||||
} else {
|
||||
throw std::runtime_error(fmt::format("unknown action {} in {} project", action, kind));
|
||||
throw std::runtime_error(
|
||||
fmt::format("unknown action {} in {} project", action.name_ptr, kind));
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error(fmt::format("invalid entry in {} project", kind));
|
||||
|
||||
@@ -38,7 +38,7 @@ bool is_type(const std::string& expected, const TypeSpec& actual, const TypeSyst
|
||||
|
||||
std::string symbol_string(const goos::Object& obj) {
|
||||
if (obj.is_symbol()) {
|
||||
return obj.as_symbol()->name;
|
||||
return obj.as_symbol().name_ptr;
|
||||
}
|
||||
throw std::runtime_error(obj.print() + " was supposed to be a symbol, but isn't");
|
||||
}
|
||||
@@ -69,7 +69,7 @@ EnumType* parse_defenum(const goos::Object& defenum,
|
||||
if (!enum_name_obj.is_symbol()) {
|
||||
throw std::runtime_error("defenum must be given a symbol as its name");
|
||||
}
|
||||
std::string name = enum_name_obj.as_symbol()->name;
|
||||
std::string name = enum_name_obj.as_symbol().name_ptr;
|
||||
|
||||
auto current = car(iter);
|
||||
while (current.is_symbol() && symbol_string(current).at(0) == ':') {
|
||||
|
||||
@@ -54,7 +54,7 @@ std::string deftype_parent_list(const goos::Object& list) {
|
||||
throw std::runtime_error("invalid parent in deftype parent list");
|
||||
}
|
||||
|
||||
return parent.as_symbol()->name;
|
||||
return parent.as_symbol().name_ptr;
|
||||
}
|
||||
|
||||
bool is_type(const std::string& expected, const TypeSpec& actual, const TypeSystem* ts) {
|
||||
@@ -63,7 +63,7 @@ bool is_type(const std::string& expected, const TypeSpec& actual, const TypeSyst
|
||||
|
||||
std::string symbol_string(const goos::Object& obj) {
|
||||
if (obj.is_symbol()) {
|
||||
return obj.as_symbol()->name;
|
||||
return obj.as_symbol().name_ptr;
|
||||
}
|
||||
throw std::runtime_error(obj.print() + " was supposed to be a symbol, but isn't");
|
||||
}
|
||||
@@ -84,10 +84,12 @@ double get_float(const goos::Object& obj) {
|
||||
throw std::runtime_error(obj.print() + " was supposed to be an number, but isn't");
|
||||
}
|
||||
|
||||
void add_field(StructureType* structure,
|
||||
TypeSystem* ts,
|
||||
const goos::Object& def,
|
||||
std::unordered_map<goos::HeapObject*, goos::Object>& constants) {
|
||||
void add_field(
|
||||
StructureType* structure,
|
||||
TypeSystem* ts,
|
||||
const goos::Object& def,
|
||||
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>&
|
||||
constants) {
|
||||
auto rest = &def;
|
||||
|
||||
auto name = symbol_string(car(rest));
|
||||
@@ -317,7 +319,7 @@ void declare_method(Type* type,
|
||||
//
|
||||
// Doing it like this makes the ordering not critical
|
||||
while (!obj->is_empty_list() && car(obj).is_symbol()) {
|
||||
const auto& keyword = car(obj).as_symbol()->name;
|
||||
const auto& keyword = car(obj).as_symbol();
|
||||
if (keyword == ":no-virtual") {
|
||||
no_virtual = true;
|
||||
} else if (keyword == ":replace") {
|
||||
@@ -334,8 +336,8 @@ void declare_method(Type* type,
|
||||
auto docstring_list = &car(obj);
|
||||
auto elem = docstring_list;
|
||||
while (!elem->is_empty_list() && car(elem).is_symbol()) {
|
||||
const auto& handler = car(elem).as_symbol()->name;
|
||||
const auto handler_kind = handler_keyword_to_kind(handler);
|
||||
const auto& handler = car(elem).as_symbol();
|
||||
const auto handler_kind = handler_keyword_to_kind(handler.name_ptr);
|
||||
|
||||
// Get the docstring
|
||||
elem = cdr(elem);
|
||||
@@ -419,8 +421,8 @@ void declare_state(Type* type,
|
||||
auto docstring_list = &car(obj);
|
||||
auto elem = docstring_list;
|
||||
while (!elem->is_empty_list() && car(elem).is_symbol()) {
|
||||
const auto& handler = car(elem).as_symbol()->name;
|
||||
const auto handler_kind = handler_keyword_to_kind(handler);
|
||||
const auto& handler = car(elem).as_symbol();
|
||||
const auto handler_kind = handler_keyword_to_kind(handler.name_ptr);
|
||||
|
||||
// Get the docstring
|
||||
elem = cdr(elem);
|
||||
@@ -463,7 +465,8 @@ StructureDefResult parse_structure_def(
|
||||
TypeSystem* ts,
|
||||
const goos::Object& fields,
|
||||
const goos::Object& options,
|
||||
std::unordered_map<goos::HeapObject*, goos::Object>& constants) {
|
||||
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>&
|
||||
constants) {
|
||||
StructureDefResult result;
|
||||
for_each_in_list(fields, [&](const goos::Object& o) { add_field(type, ts, o, constants); });
|
||||
TypeFlags flags;
|
||||
@@ -686,8 +689,8 @@ TypeSpec parse_typespec(const TypeSystem* type_system, const goos::Object& src)
|
||||
while (rest->is_pair()) {
|
||||
auto& it = rest->as_pair()->car;
|
||||
|
||||
if (it.is_symbol() && it.as_symbol()->name.at(0) == ':') {
|
||||
auto tag_name = it.as_symbol()->name.substr(1);
|
||||
if (it.is_symbol() && it.as_symbol().name_ptr[0] == ':') {
|
||||
auto tag_name = it.as_symbol().name_ptr + 1;
|
||||
rest = &rest->as_pair()->cdr;
|
||||
|
||||
if (!rest->is_pair()) {
|
||||
@@ -696,13 +699,13 @@ TypeSpec parse_typespec(const TypeSystem* type_system, const goos::Object& src)
|
||||
|
||||
auto& tag_val = rest->as_pair()->car;
|
||||
|
||||
if (tag_name == "behavior") {
|
||||
if (!type_system->fully_defined_type_exists(tag_val.as_symbol()->name) &&
|
||||
!type_system->partially_defined_type_exists(tag_val.as_symbol()->name)) {
|
||||
if (std::string_view(tag_name) == "behavior") {
|
||||
if (!type_system->fully_defined_type_exists(tag_val.as_symbol().name_ptr) &&
|
||||
!type_system->partially_defined_type_exists(tag_val.as_symbol().name_ptr)) {
|
||||
throw std::runtime_error(
|
||||
fmt::format("Behavior tag uses an unknown type {}", tag_val.as_symbol()->name));
|
||||
fmt::format("Behavior tag uses an unknown type {}", tag_val.as_symbol().name_ptr));
|
||||
}
|
||||
ts.add_new_tag(tag_name, tag_val.as_symbol()->name);
|
||||
ts.add_new_tag(tag_name, tag_val.as_symbol().name_ptr);
|
||||
} else {
|
||||
throw std::runtime_error(fmt::format("Type tag {} is unknown", tag_name));
|
||||
}
|
||||
@@ -723,11 +726,14 @@ TypeSpec parse_typespec(const TypeSystem* type_system, const goos::Object& src)
|
||||
return {};
|
||||
}
|
||||
|
||||
DeftypeResult parse_deftype(const goos::Object& deftype,
|
||||
TypeSystem* ts,
|
||||
std::unordered_map<goos::HeapObject*, goos::Object>* constants) {
|
||||
DeftypeResult parse_deftype(
|
||||
const goos::Object& deftype,
|
||||
TypeSystem* ts,
|
||||
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>*
|
||||
constants) {
|
||||
DefinitionMetadata symbol_metadata;
|
||||
std::unordered_map<goos::HeapObject*, goos::Object> no_consts;
|
||||
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>
|
||||
no_consts;
|
||||
auto& constants_to_use = no_consts;
|
||||
if (constants != nullptr) {
|
||||
constants_to_use = *constants;
|
||||
@@ -752,7 +758,7 @@ DeftypeResult parse_deftype(const goos::Object& deftype,
|
||||
throw std::runtime_error("deftype must be given a symbol as the type name");
|
||||
}
|
||||
|
||||
auto& name = type_name_obj.as_symbol()->name;
|
||||
auto& name = type_name_obj.as_symbol().name_ptr;
|
||||
auto parent_type_name = deftype_parent_list(parent_list_obj);
|
||||
auto parent_type = ts->make_typespec(parent_type_name);
|
||||
DeftypeResult result;
|
||||
|
||||
@@ -20,5 +20,6 @@ struct DeftypeResult {
|
||||
DeftypeResult parse_deftype(
|
||||
const goos::Object& deftype,
|
||||
TypeSystem* ts,
|
||||
std::unordered_map<goos::HeapObject*, goos::Object>* constants = nullptr);
|
||||
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>*
|
||||
constants = nullptr);
|
||||
TypeSpec parse_typespec(const TypeSystem* type_system, const goos::Object& src);
|
||||
|
||||
@@ -1,41 +1 @@
|
||||
#include "crc32.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#ifdef __aarch64__
|
||||
#include <arm_acle.h>
|
||||
u32 crc32(const u8* data, size_t size) {
|
||||
u32 result = 0xffffffff;
|
||||
while (size >= 4) {
|
||||
u32 x;
|
||||
memcpy(&x, data, 4);
|
||||
data += 4;
|
||||
size -= 4;
|
||||
result = __crc32w(result, x);
|
||||
}
|
||||
while (size) {
|
||||
result = __crc32b(result, *data);
|
||||
data++;
|
||||
size--;
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
#else
|
||||
#include <immintrin.h>
|
||||
u32 crc32(const u8* data, size_t size) {
|
||||
u32 result = 0xffffffff;
|
||||
while (size >= 4) {
|
||||
u32 x;
|
||||
memcpy(&x, data, 4);
|
||||
data += 4;
|
||||
size -= 4;
|
||||
result = _mm_crc32_u32(result, x);
|
||||
}
|
||||
while (size) {
|
||||
result = _mm_crc32_u8(result, *data);
|
||||
data++;
|
||||
size--;
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
#endif
|
||||
|
||||
+41
-1
@@ -2,4 +2,44 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
u32 crc32(const u8* data, size_t size);
|
||||
u32 crc32(const u8* data, size_t size);
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#ifdef __aarch64__
|
||||
#include <arm_acle.h>
|
||||
inline u32 crc32(const u8* data, size_t size) {
|
||||
u32 result = 0xffffffff;
|
||||
while (size >= 4) {
|
||||
u32 x;
|
||||
memcpy(&x, data, 4);
|
||||
data += 4;
|
||||
size -= 4;
|
||||
result = __crc32w(result, x);
|
||||
}
|
||||
while (size) {
|
||||
result = __crc32b(result, *data);
|
||||
data++;
|
||||
size--;
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
#else
|
||||
#include <immintrin.h>
|
||||
inline u32 crc32(const u8* data, size_t size) {
|
||||
u32 result = 0xffffffff;
|
||||
while (size >= 4) {
|
||||
u32 x;
|
||||
memcpy(&x, data, 4);
|
||||
data += 4;
|
||||
size -= 4;
|
||||
result = _mm_crc32_u32(result, x);
|
||||
}
|
||||
while (size) {
|
||||
result = _mm_crc32_u8(result, *data);
|
||||
data++;
|
||||
size--;
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
#endif
|
||||
@@ -3537,7 +3537,7 @@ void FunctionCallElement::update_from_stack(const Env& env,
|
||||
Form* so_group_f = nullptr;
|
||||
if (!elt_group->elts().at(0)->to_form(env).is_symbol("sfx")) {
|
||||
so_group_f = pool.form<ConstantTokenElement>(
|
||||
elt_group->elts().at(0)->to_form(env).as_symbol()->name);
|
||||
elt_group->elts().at(0)->to_form(env).as_symbol().name_ptr);
|
||||
}
|
||||
auto so_positional_f = arg_forms.at(6);
|
||||
if (so_positional_f->to_form(env).is_symbol("#t")) {
|
||||
|
||||
@@ -1281,7 +1281,7 @@ FormElement* rewrite_joint_macro(LetElement* in, const Env& env, FormPool& pool)
|
||||
}
|
||||
|
||||
auto group_lisp = strip_cast("art-joint-anim", arg_group)->to_form(env);
|
||||
if (group_lisp.is_symbol() && group_lisp.as_symbol()->name == "#f") {
|
||||
if (group_lisp.is_symbol() && group_lisp.as_symbol() == "#f") {
|
||||
arg_group = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ void DecompilerTypeSystem::parse_type_defs(const std::vector<std::string>& file_
|
||||
|
||||
for_each_in_list(data, [&](goos::Object& o) {
|
||||
try {
|
||||
if (car(o).as_symbol()->name == "define-extern") {
|
||||
if (car(o).as_symbol() == "define-extern") {
|
||||
auto symbol_metadata = DefinitionMetadata();
|
||||
auto* rest = &cdr(o);
|
||||
auto sym_name = car(*rest);
|
||||
@@ -69,8 +69,8 @@ void DecompilerTypeSystem::parse_type_defs(const std::vector<std::string>& file_
|
||||
throw std::runtime_error("malformed define-extern");
|
||||
}
|
||||
symbol_metadata.definition_info = m_reader.db.get_short_info_for(o);
|
||||
add_symbol(sym_name.as_symbol()->name, parse_typespec(&ts, sym_type), symbol_metadata);
|
||||
} else if (car(o).as_symbol()->name == "deftype") {
|
||||
add_symbol(sym_name.as_symbol().name_ptr, parse_typespec(&ts, sym_type), symbol_metadata);
|
||||
} else if (car(o).as_symbol() == "deftype") {
|
||||
auto dtr = parse_deftype(cdr(o), &ts);
|
||||
dtr.type_info->m_metadata.definition_info = m_reader.db.get_short_info_for(o);
|
||||
if (dtr.create_runtime_type) {
|
||||
@@ -87,7 +87,7 @@ void DecompilerTypeSystem::parse_type_defs(const std::vector<std::string>& file_
|
||||
for (const auto& [state_name, meta] : dtr.type_info->m_state_definition_meta) {
|
||||
state_metadata.emplace(state_name, meta);
|
||||
}
|
||||
} else if (car(o).as_symbol()->name == "declare-type") {
|
||||
} else if (car(o).as_symbol() == "declare-type") {
|
||||
auto* rest = &cdr(o);
|
||||
auto type_name = car(*rest);
|
||||
rest = &cdr(*rest);
|
||||
@@ -95,14 +95,14 @@ void DecompilerTypeSystem::parse_type_defs(const std::vector<std::string>& file_
|
||||
if (!cdr(*rest).is_empty_list()) {
|
||||
throw std::runtime_error("malformed declare-type");
|
||||
}
|
||||
ts.forward_declare_type_as(type_name.as_symbol()->name, type_kind.as_symbol()->name);
|
||||
} else if (car(o).as_symbol()->name == "defenum") {
|
||||
ts.forward_declare_type_as(type_name.as_symbol().name_ptr, type_kind.as_symbol().name_ptr);
|
||||
} else if (car(o).as_symbol() == "defenum") {
|
||||
auto symbol_metadata = DefinitionMetadata();
|
||||
parse_defenum(cdr(o), &ts, &symbol_metadata);
|
||||
symbol_metadata.definition_info = m_reader.db.get_short_info_for(o);
|
||||
auto* rest = &cdr(o);
|
||||
const auto& enum_name = car(*rest).as_symbol()->name;
|
||||
symbol_metadata_map[enum_name] = symbol_metadata;
|
||||
const auto& enum_name = car(*rest).as_symbol();
|
||||
symbol_metadata_map[enum_name.name_ptr] = symbol_metadata;
|
||||
// so far, enums are never runtime types so there's no symbol for them.
|
||||
} else {
|
||||
throw std::runtime_error("Decompiler cannot parse " + car(o).print());
|
||||
|
||||
@@ -343,7 +343,7 @@ s32 word_as_s32(const LinkedWord& w) {
|
||||
|
||||
std::string print_def(const goos::Object& obj) {
|
||||
if (obj.is_pair() && obj.as_pair()->car.is_symbol() &&
|
||||
obj.as_pair()->car.as_symbol()->name == "quote") {
|
||||
obj.as_pair()->car.as_symbol() == "quote") {
|
||||
auto& rest = obj.as_pair()->cdr;
|
||||
if (rest.is_pair() && rest.as_pair()->cdr.is_empty_list()) {
|
||||
return fmt::format("'{}", rest.as_pair()->car.print());
|
||||
|
||||
+15
-13
@@ -225,20 +225,22 @@
|
||||
)
|
||||
)
|
||||
|
||||
(defsmacro let (bindings &rest body)
|
||||
`((lambda ,(apply first bindings) ,@body)
|
||||
,@(apply second bindings)))
|
||||
;; These are now implemented in Interpreter.cpp for speed.
|
||||
;; But I leave these here because it was cool to implement them in GOOS itself.
|
||||
; (defsmacro let (bindings &rest body)
|
||||
; `((lambda ,(apply first bindings) ,@body)
|
||||
; ,@(apply second bindings)))
|
||||
|
||||
(defsmacro let* (bindings &rest body)
|
||||
(if (null? bindings)
|
||||
`(begin ,@body)
|
||||
`((lambda (,(caar bindings))
|
||||
(let* ,(cdr bindings) ,@body))
|
||||
;;(begin ,@(cdar bindings))
|
||||
,(car (cdar bindings))
|
||||
)
|
||||
)
|
||||
)
|
||||
; (defsmacro let* (bindings &rest body)
|
||||
; (if (null? bindings)
|
||||
; `(begin ,@body)
|
||||
; `((lambda (,(caar bindings))
|
||||
; (let* ,(cdr bindings) ,@body))
|
||||
; ;;(begin ,@(cdar bindings))
|
||||
; ,(car (cdar bindings))
|
||||
; )
|
||||
; )
|
||||
; )
|
||||
|
||||
(defsmacro dotimes (var &rest body)
|
||||
`(let (( ,(first var) 0))
|
||||
|
||||
@@ -166,10 +166,10 @@ std::unique_ptr<FunctionEnv> Compiler::compile_top_level_function(const std::str
|
||||
// the compiler doesn't waste much time.
|
||||
// the actual source code is (top-level ...) right now though so we need some tricks.
|
||||
code.as_pair()->cdr = PairObject::make_new(
|
||||
PairObject::make_new(SymbolObject::make_new(m_goos.reader.symbolTable, "when"),
|
||||
PairObject::make_new(SymbolObject::make_new(m_goos.reader.symbolTable,
|
||||
"*debug-segment*"),
|
||||
code.as_pair()->cdr)),
|
||||
PairObject::make_new(
|
||||
Object::make_symbol(&m_goos.reader.symbolTable, "when"),
|
||||
PairObject::make_new(Object::make_symbol(&m_goos.reader.symbolTable, "*debug-segment*"),
|
||||
code.as_pair()->cdr)),
|
||||
Object::make_empty_list());
|
||||
result = compile_error_guard(code, fe.get());
|
||||
}
|
||||
@@ -252,7 +252,7 @@ void Compiler::color_object_file(FileEnv* env) {
|
||||
input.is_asm_function = f->is_asm_func;
|
||||
for (auto& i : f->code()) {
|
||||
input.instructions.push_back(i->to_rai());
|
||||
input.debug_instruction_names.push_back(i->print());
|
||||
// input.debug_instruction_names.push_back(i->print());
|
||||
}
|
||||
|
||||
for (auto& reg_val : f->reg_vals()) {
|
||||
@@ -385,7 +385,7 @@ void Compiler::setup_goos_forms() {
|
||||
va_check(form, args, {goos::ObjectType::SYMBOL}, {});
|
||||
std::vector<Object> enum_vals;
|
||||
|
||||
const auto& enum_name = args.unnamed.at(0).as_symbol()->name;
|
||||
const auto& enum_name = args.unnamed.at(0).as_symbol().name_ptr;
|
||||
auto enum_type = m_ts.try_enum_lookup(enum_name);
|
||||
if (!enum_type) {
|
||||
throw_compiler_error(form, "Unknown enum {} in get-enum-vals", enum_name);
|
||||
|
||||
@@ -97,7 +97,7 @@ class Compiler {
|
||||
MakeSystem& make_system() { return m_make; }
|
||||
std::set<std::string> lookup_symbol_infos_starting_with(const std::string& prefix) const;
|
||||
std::vector<SymbolInfo>* lookup_exact_name_info(const std::string& name) const;
|
||||
std::optional<TypeSpec> lookup_typespec(const std::string& symbol_name) const;
|
||||
std::optional<TypeSpec> lookup_typespec(const std::string& symbol_name);
|
||||
|
||||
private:
|
||||
GameVersion m_version;
|
||||
@@ -110,9 +110,12 @@ class Compiler {
|
||||
goos::Interpreter m_goos;
|
||||
Debugger m_debugger;
|
||||
std::unordered_map<std::string, goos::ArgumentSpec> m_macro_specs;
|
||||
std::unordered_map<std::string, TypeSpec> m_symbol_types;
|
||||
std::unordered_map<goos::HeapObject*, goos::Object> m_global_constants;
|
||||
std::unordered_map<goos::HeapObject*, InlineableFunction> m_inlineable_functions;
|
||||
std::unordered_map<goos::InternedSymbolPtr, TypeSpec, goos::InternedSymbolPtr::hash>
|
||||
m_symbol_types;
|
||||
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>
|
||||
m_global_constants;
|
||||
std::unordered_map<goos::InternedSymbolPtr, InlineableFunction, goos::InternedSymbolPtr::hash>
|
||||
m_inlineable_functions;
|
||||
CompilerSettings m_settings;
|
||||
bool m_throw_on_define_extern_redefinition = false;
|
||||
std::unordered_set<std::string> m_allow_inconsistent_definition_symbols;
|
||||
@@ -220,7 +223,7 @@ class Compiler {
|
||||
const std::unordered_map<std::string,
|
||||
std::pair<bool, std::optional<goos::ObjectType>>>& named);
|
||||
const std::string& as_string(const goos::Object& o);
|
||||
const std::string& symbol_string(const goos::Object& o);
|
||||
std::string symbol_string(const goos::Object& o);
|
||||
std::string quoted_sym_as_string(const goos::Object& o);
|
||||
goos::Object unquote(const goos::Object& o);
|
||||
bool is_quoted_sym(const goos::Object& o);
|
||||
|
||||
@@ -19,7 +19,7 @@ void CompilerSettings::set(const std::string& name, const goos::Object& value) {
|
||||
|
||||
kv->second.value = value;
|
||||
if (kv->second.boolp) {
|
||||
*kv->second.boolp = !(value.is_symbol() && value.as_symbol()->name == "#f");
|
||||
*kv->second.boolp = !(value.is_symbol() && value.as_symbol() == "#f");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -278,7 +278,7 @@ RegVal* FunctionEnv::lexical_lookup(goos::Object sym) {
|
||||
throw std::runtime_error("invalid symbol in lexical_lookup");
|
||||
}
|
||||
|
||||
auto kv = params.find(sym.as_symbol()->name);
|
||||
auto kv = params.find(sym.as_symbol());
|
||||
if (kv == params.end()) {
|
||||
return parent()->lexical_lookup(sym);
|
||||
}
|
||||
@@ -350,7 +350,7 @@ RegVal* LexicalEnv::lexical_lookup(goos::Object sym) {
|
||||
throw std::runtime_error("invalid symbol in lexical_lookup");
|
||||
}
|
||||
|
||||
auto kv = vars.find(sym.as_symbol()->name);
|
||||
auto kv = vars.find(sym.as_symbol());
|
||||
if (kv == vars.end()) {
|
||||
return parent()->lexical_lookup(sym);
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ class FunctionEnv : public DeclareEnv {
|
||||
TypeSpec asm_func_return_type;
|
||||
std::vector<UnresolvedGoto> unresolved_gotos;
|
||||
std::vector<UnresolvedConditionalGoto> unresolved_cond_gotos;
|
||||
std::unordered_map<std::string, RegVal*> params;
|
||||
std::unordered_map<goos::InternedSymbolPtr, RegVal*, goos::InternedSymbolPtr::hash> params;
|
||||
|
||||
protected:
|
||||
void resolve_gotos();
|
||||
@@ -288,7 +288,7 @@ class LexicalEnv : public DeclareEnv {
|
||||
explicit LexicalEnv(Env* parent) : DeclareEnv(EnvKind::OTHER_ENV, parent) {}
|
||||
RegVal* lexical_lookup(goos::Object sym) override;
|
||||
std::string print() override;
|
||||
std::unordered_map<std::string, RegVal*> vars;
|
||||
std::unordered_map<goos::InternedSymbolPtr, RegVal*, goos::InternedSymbolPtr::hash> vars;
|
||||
};
|
||||
|
||||
class LabelEnv : public Env {
|
||||
@@ -306,14 +306,14 @@ class SymbolMacroEnv : public Env {
|
||||
public:
|
||||
explicit SymbolMacroEnv(Env* parent) : Env(EnvKind::SYMBOL_MACRO_ENV, parent) {}
|
||||
// key is goos symbols.
|
||||
std::unordered_map<goos::HeapObject*, goos::Object> macros;
|
||||
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash> macros;
|
||||
std::string print() override { return "symbol-macro-env"; }
|
||||
};
|
||||
|
||||
class MacroExpandEnv : public Env {
|
||||
public:
|
||||
MacroExpandEnv(Env* parent,
|
||||
const goos::HeapObject* macro_name,
|
||||
const goos::InternedSymbolPtr macro_name,
|
||||
const goos::Object& macro_body,
|
||||
const goos::Object& macro_use)
|
||||
: Env(EnvKind::MACRO_EXPAND_ENV, parent),
|
||||
@@ -333,13 +333,13 @@ class MacroExpandEnv : public Env {
|
||||
|
||||
std::string print() override { return "macro-env"; }
|
||||
|
||||
const goos::HeapObject* name() const { return m_macro_name; }
|
||||
const goos::InternedSymbolPtr name() const { return m_macro_name; }
|
||||
const goos::Object& macro_body() const { return m_macro_body; }
|
||||
const goos::Object& macro_use_location() const { return m_macro_use_location; }
|
||||
const goos::Object& root_form() const { return m_root_form; }
|
||||
|
||||
private:
|
||||
const goos::HeapObject* m_macro_name = nullptr;
|
||||
const goos::InternedSymbolPtr m_macro_name = {nullptr};
|
||||
goos::Object m_macro_body;
|
||||
goos::Object m_macro_use_location;
|
||||
goos::Object m_root_form;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// note - we cannot easily reuse the GOOS argument system because GOAL's is slightly different.
|
||||
// there's no rest or keyword support.
|
||||
struct GoalArg {
|
||||
std::string name;
|
||||
std::string name; // todo intern
|
||||
TypeSpec type;
|
||||
};
|
||||
|
||||
|
||||
@@ -219,10 +219,10 @@ const std::string& Compiler::as_string(const goos::Object& o) {
|
||||
}
|
||||
|
||||
/*!
|
||||
* Convert a goos::Object that's a symbol to a std::string. Must be a string.
|
||||
* Convert a goos::Object that's a symbol to a std::string. Must be a symbol.
|
||||
*/
|
||||
const std::string& Compiler::symbol_string(const goos::Object& o) {
|
||||
return o.as_symbol()->name;
|
||||
std::string Compiler::symbol_string(const goos::Object& o) {
|
||||
return o.as_symbol().name_ptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -257,7 +257,7 @@ bool Compiler::is_quoted_sym(const goos::Object& o) {
|
||||
if (o.is_pair()) {
|
||||
auto car = pair_car(o);
|
||||
auto cdr = pair_cdr(o);
|
||||
if (car.is_symbol() && car.as_symbol()->name == "quote") {
|
||||
if (car.is_symbol() && car.as_symbol() == "quote") {
|
||||
if (cdr.is_pair()) {
|
||||
auto thing = pair_car(cdr);
|
||||
if (thing.is_symbol()) {
|
||||
@@ -348,10 +348,10 @@ bool Compiler::is_symbol(const TypeSpec& ts) {
|
||||
bool Compiler::get_true_or_false(const goos::Object& form, const goos::Object& boolean) {
|
||||
// todo try other things.
|
||||
if (boolean.is_symbol()) {
|
||||
if (boolean.as_symbol()->name == "#t") {
|
||||
if (boolean.as_symbol() == "#t") {
|
||||
return true;
|
||||
}
|
||||
if (boolean.as_symbol()->name == "#f") {
|
||||
if (boolean.as_symbol() == "#f") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ emitter::Register Compiler::parse_register(const goos::Object& code) {
|
||||
|
||||
auto nas = code.as_symbol();
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (nas->name == reg_names[i]) {
|
||||
if (std::string_view(nas.name_ptr) == reg_names[i]) {
|
||||
return emitter::Register(i);
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,7 @@ Val* Compiler::compile_rlet(const goos::Object& form, const goos::Object& rest,
|
||||
// figure out the class
|
||||
RegClass register_class = RegClass::GPR_64;
|
||||
if (def_args.has_named("class")) {
|
||||
auto& class_name = def_args.named.at("class").as_symbol()->name;
|
||||
auto& class_name = def_args.named.at("class").as_symbol();
|
||||
if (class_name == "gpr") {
|
||||
register_class = RegClass::GPR_64;
|
||||
} else if (class_name == "fpr") {
|
||||
@@ -70,7 +70,7 @@ Val* Compiler::compile_rlet(const goos::Object& form, const goos::Object& rest,
|
||||
} else if (class_name == "i128") {
|
||||
register_class = RegClass::INT_128;
|
||||
} else {
|
||||
throw_compiler_error(o, "Register class {} is unknown.", class_name);
|
||||
throw_compiler_error(o, "Register class {} is unknown.", class_name.name_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ Val* Compiler::compile_rlet(const goos::Object& form, const goos::Object& rest,
|
||||
}
|
||||
}
|
||||
|
||||
lenv->vars[new_place_name.as_symbol()->name] = new_place_reg;
|
||||
lenv->vars[new_place_name.as_symbol()] = new_place_reg;
|
||||
});
|
||||
|
||||
if (!reset_regs.empty()) {
|
||||
@@ -218,10 +218,10 @@ Val* Compiler::compile_asm_load_sym(const goos::Object& form, const goos::Object
|
||||
va_check(
|
||||
form, args, {{}, {goos::ObjectType::SYMBOL}},
|
||||
{{"sext", {false, goos::ObjectType::SYMBOL}}, {"color", {false, goos::ObjectType::SYMBOL}}});
|
||||
auto& sym_name = args.unnamed.at(1).as_symbol()->name;
|
||||
auto& sym_name = args.unnamed.at(1).as_symbol();
|
||||
auto sym_kv = m_symbol_types.find(sym_name);
|
||||
if (sym_kv == m_symbol_types.end()) {
|
||||
throw_compiler_error(form, "Cannot find a symbol named {}.", sym_name);
|
||||
throw_compiler_error(form, "Cannot find a symbol named {}.", sym_name.name_ptr);
|
||||
}
|
||||
auto ts = sym_kv->second;
|
||||
bool sext = m_ts.lookup_type(ts)->get_load_signed();
|
||||
@@ -239,7 +239,7 @@ Val* Compiler::compile_asm_load_sym(const goos::Object& form, const goos::Object
|
||||
throw_compiler_error(form, "Cannot .load-sym this. Got a {}.", dest->print());
|
||||
}
|
||||
|
||||
env->emit_ir<IR_GetSymbolValueAsm>(form, color, dest, sym_name, sext);
|
||||
env->emit_ir<IR_GetSymbolValueAsm>(form, color, dest, sym_name.name_ptr, sext);
|
||||
return get_none();
|
||||
}
|
||||
|
||||
|
||||
@@ -323,14 +323,14 @@ Val* Compiler::compile_pair(const goos::Object& code, Env* env) {
|
||||
}
|
||||
|
||||
// next try as a goal compiler form
|
||||
auto kv_gfs = g_goal_forms.find(head_sym->name);
|
||||
auto kv_gfs = g_goal_forms.find(head_sym.name_ptr);
|
||||
if (kv_gfs != g_goal_forms.end()) {
|
||||
auto& [docstring, func] = kv_gfs->second;
|
||||
return ((*this).*(func))(code, rest, env);
|
||||
}
|
||||
|
||||
// next try as an enum
|
||||
auto enum_type = m_ts.try_enum_lookup(head_sym->name);
|
||||
auto enum_type = m_ts.try_enum_lookup(head_sym.name_ptr);
|
||||
if (enum_type) {
|
||||
return compile_enum_lookup(code, enum_type, rest, env);
|
||||
}
|
||||
@@ -388,7 +388,7 @@ SymbolVal* Compiler::compile_get_sym_obj(const std::string& name, Env* env) {
|
||||
Val* Compiler::compile_get_symbol_value(const goos::Object& form,
|
||||
const std::string& name,
|
||||
Env* env) {
|
||||
auto existing_symbol = m_symbol_types.find(name);
|
||||
auto existing_symbol = m_symbol_types.find(m_goos.intern_ptr(name));
|
||||
if (existing_symbol == m_symbol_types.end()) {
|
||||
throw_compiler_error(
|
||||
form, "The symbol {} was looked up as a global variable, but it does not exist.", name);
|
||||
@@ -432,7 +432,7 @@ Val* Compiler::compile_symbol(const goos::Object& form, Env* env) {
|
||||
}
|
||||
|
||||
auto global_constant = m_global_constants.find(form.as_symbol());
|
||||
auto existing_symbol = m_symbol_types.find(form.as_symbol()->name);
|
||||
auto existing_symbol = m_symbol_types.find(form.as_symbol());
|
||||
|
||||
// see if it's a constant
|
||||
if (global_constant != m_global_constants.end()) {
|
||||
|
||||
@@ -360,7 +360,7 @@ std::string Compiler::make_symbol_info_description(const SymbolInfo& info) {
|
||||
switch (info.kind()) {
|
||||
case SymbolInfo::Kind::GLOBAL_VAR:
|
||||
return fmt::format("[Global Variable] Type: {} Defined: {}",
|
||||
m_symbol_types.at(info.name()).print(),
|
||||
m_symbol_types.at(m_goos.intern_ptr(info.name())).print(),
|
||||
m_goos.reader.db.get_info_for(info.src_form()));
|
||||
case SymbolInfo::Kind::LANGUAGE_BUILTIN:
|
||||
return fmt::format("[Built-in Form] {}\n", info.name());
|
||||
@@ -377,7 +377,7 @@ std::string Compiler::make_symbol_info_description(const SymbolInfo& info) {
|
||||
case SymbolInfo::Kind::CONSTANT:
|
||||
return fmt::format(
|
||||
"[Constant] Name: {} Value: {} Defined: {}", info.name(),
|
||||
m_global_constants.at(m_goos.reader.symbolTable.intern_ptr(info.name())).print(),
|
||||
m_global_constants.at(m_goos.reader.symbolTable.intern(info.name().c_str())).print(),
|
||||
m_goos.reader.db.get_info_for(info.src_form()));
|
||||
case SymbolInfo::Kind::FUNCTION:
|
||||
return fmt::format("[Function] Name: {} Defined: {}", info.name(),
|
||||
@@ -396,7 +396,7 @@ Val* Compiler::compile_get_info(const goos::Object& form, const goos::Object& re
|
||||
auto args = get_va(form, rest);
|
||||
va_check(form, args, {goos::ObjectType::SYMBOL}, {});
|
||||
|
||||
auto result = m_symbol_info.lookup_exact_name(args.unnamed.at(0).as_symbol()->name);
|
||||
auto result = m_symbol_info.lookup_exact_name(args.unnamed.at(0).as_symbol().name_ptr);
|
||||
if (!result) {
|
||||
lg::print("No results found.\n");
|
||||
} else {
|
||||
@@ -548,7 +548,7 @@ Val* Compiler::compile_autocomplete(const goos::Object& form, const goos::Object
|
||||
va_check(form, args, {goos::ObjectType::SYMBOL}, {});
|
||||
|
||||
Timer timer;
|
||||
auto result = m_symbol_info.lookup_symbols_starting_with(args.unnamed.at(0).as_symbol()->name);
|
||||
auto result = m_symbol_info.lookup_symbols_starting_with(args.unnamed.at(0).as_symbol().name_ptr);
|
||||
auto time = timer.getMs();
|
||||
|
||||
for (auto& x : result) {
|
||||
@@ -575,7 +575,7 @@ Val* Compiler::compile_update_macro_metadata(const goos::Object& form,
|
||||
throw_compiler_error(form, "Invalid arguments provided to `update-macro-metadata");
|
||||
}
|
||||
|
||||
auto& name = args.unnamed.at(0).as_symbol()->name;
|
||||
auto& name = args.unnamed.at(0).as_symbol().name_ptr;
|
||||
|
||||
auto arg_spec = m_goos.parse_arg_spec(form, args.unnamed.at(2));
|
||||
m_macro_specs[name] = arg_spec;
|
||||
@@ -601,9 +601,10 @@ std::vector<SymbolInfo>* Compiler::lookup_exact_name_info(const std::string& nam
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<TypeSpec> Compiler::lookup_typespec(const std::string& symbol_name) const {
|
||||
if (m_symbol_types.find(symbol_name) != m_symbol_types.end()) {
|
||||
return m_symbol_types.at(symbol_name);
|
||||
std::optional<TypeSpec> Compiler::lookup_typespec(const std::string& symbol_name) {
|
||||
const auto& it = m_symbol_types.find(m_goos.intern_ptr(symbol_name));
|
||||
if (it != m_symbol_types.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -716,7 +717,7 @@ Val* Compiler::compile_gen_docs(const goos::Object& form, const goos::Object& re
|
||||
if (sym_info.kind() == SymbolInfo::Kind::CONSTANT) {
|
||||
var.type = "unknown"; // Unfortunately, constants are not properly typed
|
||||
} else {
|
||||
var.type = m_symbol_types.at(var.name).base_type();
|
||||
var.type = m_symbol_types.at(m_goos.intern_ptr(var.name)).base_type();
|
||||
}
|
||||
var.def_location = def_loc;
|
||||
if (sym_info.kind() == SymbolInfo::Kind::GLOBAL_VAR) {
|
||||
@@ -731,7 +732,7 @@ Val* Compiler::compile_gen_docs(const goos::Object& form, const goos::Object& re
|
||||
func.def_location = def_loc;
|
||||
func.args = Docs::get_args_from_docstring(sym_info.args(), func.description);
|
||||
// The last arg in the typespec is the return type
|
||||
const auto& func_type = m_symbol_types.at(func.name);
|
||||
const auto& func_type = m_symbol_types.at(m_goos.intern_ptr(func.name));
|
||||
func.return_type = func_type.last_arg().base_type();
|
||||
file_doc.functions.push_back(func);
|
||||
} else if (sym_info.kind() == SymbolInfo::Kind::TYPE) {
|
||||
|
||||
@@ -188,7 +188,7 @@ Compiler::ConstPropResult Compiler::constant_propagation_dispatch(const goos::Ob
|
||||
|
||||
// it can either be a global or symbol
|
||||
const auto& global_constant = m_global_constants.find(expanded.as_symbol());
|
||||
const auto& existing_symbol = m_symbol_types.find(expanded.as_symbol()->name);
|
||||
const auto& existing_symbol = m_symbol_types.find(expanded.as_symbol());
|
||||
|
||||
// see if it's a constant
|
||||
if (global_constant != m_global_constants.end()) {
|
||||
@@ -225,12 +225,12 @@ Compiler::ConstPropResult Compiler::constant_propagation_dispatch(const goos::Ob
|
||||
// all are expanded, so we don't need to do it again.
|
||||
|
||||
// first try as a goal compiler form
|
||||
auto kv_gfs = g_const_prop_forms.find(head_sym->name);
|
||||
auto kv_gfs = g_const_prop_forms.find(head_sym.name_ptr);
|
||||
if (kv_gfs != g_const_prop_forms.end()) {
|
||||
return ((*this).*(kv_gfs->second))(expanded, rest, env);
|
||||
}
|
||||
|
||||
const auto& kv_goal = g_goal_forms.find(head_sym->name);
|
||||
const auto& kv_goal = g_goal_forms.find(head_sym.name_ptr);
|
||||
if (kv_goal != g_goal_forms.end()) {
|
||||
// it's a compiler form that we can't constant propagate.
|
||||
return {expanded, true};
|
||||
@@ -250,7 +250,7 @@ s64 Compiler::get_constant_integer_or_error(const goos::Object& in, Env* env) {
|
||||
auto head = prop.value.as_pair()->car;
|
||||
if (head.is_symbol()) {
|
||||
auto head_sym = head.as_symbol();
|
||||
auto enum_type = m_ts.try_enum_lookup(head_sym->name);
|
||||
auto enum_type = m_ts.try_enum_lookup(head_sym.name_ptr);
|
||||
if (enum_type) {
|
||||
bool success;
|
||||
u64 as_enum =
|
||||
@@ -281,7 +281,7 @@ ValOrConstInt Compiler::get_constant_integer_or_variable(const goos::Object& in,
|
||||
auto head = prop.value.as_pair()->car;
|
||||
if (head.is_symbol()) {
|
||||
auto head_sym = head.as_symbol();
|
||||
auto enum_type = m_ts.try_enum_lookup(head_sym->name);
|
||||
auto enum_type = m_ts.try_enum_lookup(head_sym.name_ptr);
|
||||
if (enum_type) {
|
||||
bool success;
|
||||
u64 as_enum =
|
||||
|
||||
@@ -54,7 +54,7 @@ Condition Compiler::compile_condition(const goos::Object& condition, Env* env, b
|
||||
auto fas = first.as_symbol();
|
||||
|
||||
// if there's a not, we can just try again to get an optimization with the invert flipped.
|
||||
if (fas->name == "not") {
|
||||
if (fas == "not") {
|
||||
if (!pair_cdr(rest).is_empty_list()) {
|
||||
throw_compiler_error(condition, "A condition with \"not\" can have only one argument");
|
||||
}
|
||||
@@ -62,7 +62,7 @@ Condition Compiler::compile_condition(const goos::Object& condition, Env* env, b
|
||||
}
|
||||
|
||||
auto& conditions = invert ? conditions_inverted : conditions_normal;
|
||||
auto nc_kv = conditions.find(fas->name);
|
||||
auto nc_kv = conditions.find(fas.name_ptr);
|
||||
|
||||
if (nc_kv != conditions.end()) {
|
||||
// it is an optimizable condition!
|
||||
@@ -290,7 +290,7 @@ Val* Compiler::compile_cond(const goos::Object& form, const goos::Object& rest,
|
||||
}
|
||||
|
||||
Val* Compiler::compile_and_or(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
std::string op_name = form.as_pair()->car.as_symbol()->name;
|
||||
std::string op_name = form.as_pair()->car.as_symbol().name_ptr;
|
||||
bool is_and = false;
|
||||
if (op_name == "and") {
|
||||
is_and = true;
|
||||
|
||||
@@ -63,9 +63,9 @@ Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest
|
||||
}
|
||||
|
||||
auto in_gpr = compiled_val->to_gpr(form, fe);
|
||||
auto existing_type = m_symbol_types.find(sym.as_symbol()->name);
|
||||
auto existing_type = m_symbol_types.find(sym.as_symbol());
|
||||
if (existing_type == m_symbol_types.end()) {
|
||||
m_symbol_types[sym.as_symbol()->name] = in_gpr->type();
|
||||
m_symbol_types[sym.as_symbol()] = in_gpr->type();
|
||||
} else {
|
||||
bool do_typecheck = true;
|
||||
if (args.has_named("no-typecheck")) {
|
||||
@@ -73,7 +73,7 @@ Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest
|
||||
}
|
||||
if (do_typecheck) {
|
||||
typecheck(form, existing_type->second, in_gpr->type(),
|
||||
fmt::format("define on existing symbol {}", sym.as_symbol()->name));
|
||||
fmt::format("define on existing symbol {}", sym.as_symbol().name_ptr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ Val* Compiler::compile_define_extern(const goos::Object& form, const goos::Objec
|
||||
|
||||
auto new_type = parse_typespec(typespec, env);
|
||||
|
||||
auto existing_type = m_symbol_types.find(symbol_string(sym));
|
||||
auto existing_type = m_symbol_types.find(sym.as_symbol());
|
||||
// symbol already declared, and doesn't match existing definition. do more checks...
|
||||
if (existing_type != m_symbol_types.end() && existing_type->second != new_type) {
|
||||
if (m_allow_inconsistent_definition_symbols.find(symbol_string(sym)) ==
|
||||
@@ -124,7 +124,7 @@ Val* Compiler::compile_define_extern(const goos::Object& form, const goos::Objec
|
||||
}
|
||||
}
|
||||
|
||||
m_symbol_types[symbol_string(sym)] = new_type;
|
||||
m_symbol_types[sym.as_symbol()] = new_type;
|
||||
m_symbol_info.add_fwd_dec(symbol_string(sym), form);
|
||||
return get_none();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ const goos::Object& get_lambda_body(const goos::Object& def) {
|
||||
auto* iter = &def;
|
||||
while (true) {
|
||||
auto car = iter->as_pair()->car;
|
||||
if (car.is_symbol() && car.as_symbol()->name.at(0) == ':') {
|
||||
if (car.is_symbol() && car.as_symbol().name_ptr[0] == ':') {
|
||||
iter = &iter->as_pair()->cdr;
|
||||
iter = &iter->as_pair()->cdr;
|
||||
} else {
|
||||
@@ -56,9 +56,10 @@ Val* Compiler::compile_local_vars(const goos::Object& form, const goos::Object&
|
||||
for_each_in_list(rest, [&](const goos::Object& o) {
|
||||
if (o.is_symbol()) {
|
||||
// if it has no type, assume object.
|
||||
auto name = symbol_string(o);
|
||||
auto name = o.as_symbol();
|
||||
if (fe->params.find(name) != fe->params.end()) {
|
||||
throw_compiler_error(form, "Cannot declare a local named {}, this already exists.", name);
|
||||
throw_compiler_error(form, "Cannot declare a local named {}, this already exists.",
|
||||
name.name_ptr);
|
||||
}
|
||||
auto ireg = fe->make_ireg(m_ts.make_typespec("object"), RegClass::GPR_64);
|
||||
ireg->mark_as_settable();
|
||||
@@ -66,11 +67,12 @@ Val* Compiler::compile_local_vars(const goos::Object& form, const goos::Object&
|
||||
} else {
|
||||
auto param_args = get_va(o, o);
|
||||
va_check(o, param_args, {goos::ObjectType::SYMBOL, {}}, {});
|
||||
auto name = symbol_string(param_args.unnamed.at(0));
|
||||
auto name = param_args.unnamed.at(0).as_symbol();
|
||||
auto type = parse_typespec(param_args.unnamed.at(1), env);
|
||||
|
||||
if (fe->params.find(name) != fe->params.end()) {
|
||||
throw_compiler_error(form, "Cannot declare a local named {}, this already exists.", name);
|
||||
throw_compiler_error(form, "Cannot declare a local named {}, this already exists.",
|
||||
name.name_ptr);
|
||||
}
|
||||
|
||||
if (m_ts.tc(TypeSpec("float"), type)) {
|
||||
@@ -207,10 +209,10 @@ Val* Compiler::compile_lambda(const goos::Object& form, const goos::Object& rest
|
||||
self_var->set_rlet_constraint(constr.desired_register);
|
||||
new_func_env->constrain(constr);
|
||||
|
||||
if (new_func_env->params.find("self") != new_func_env->params.end()) {
|
||||
if (new_func_env->params.find(m_goos.intern_ptr("self")) != new_func_env->params.end()) {
|
||||
throw_compiler_error(form, "Cannot have an argument named self in a behavior");
|
||||
}
|
||||
new_func_env->params["self"] = self_var;
|
||||
new_func_env->params[m_goos.intern_ptr("self")] = self_var;
|
||||
reset_args_for_coloring.push_back(self_var);
|
||||
lambda_ts.add_new_tag("behavior", behavior_type);
|
||||
}
|
||||
@@ -228,7 +230,8 @@ Val* Compiler::compile_lambda(const goos::Object& form, const goos::Object& rest
|
||||
auto ireg = new_func_env->make_ireg(
|
||||
lambda.params.at(i).type, arg_regs.at(i).is_gpr() ? RegClass::GPR_64 : RegClass::INT_128);
|
||||
ireg->mark_as_settable();
|
||||
if (!new_func_env->params.insert({lambda.params.at(i).name, ireg}).second) {
|
||||
if (!new_func_env->params.insert({m_goos.intern_ptr(lambda.params.at(i).name), ireg})
|
||||
.second) {
|
||||
throw_compiler_error(form, "lambda has multiple arguments named {}",
|
||||
lambda.params.at(i).name);
|
||||
}
|
||||
@@ -340,11 +343,11 @@ Val* Compiler::compile_function_or_method_call(const goos::Object& form, Env* en
|
||||
if (!auto_inline) {
|
||||
// if auto-inlining failed, we must get the thing to call in a different way.
|
||||
if (uneval_head.is_symbol()) {
|
||||
if (uneval_head.as_symbol()->name == "inspect" || uneval_head.as_symbol()->name == "print") {
|
||||
if (uneval_head.as_symbol() == "inspect" || uneval_head.as_symbol() == "print") {
|
||||
is_method_call = true;
|
||||
} else {
|
||||
if (is_local_symbol(uneval_head, env) ||
|
||||
m_symbol_types.find(symbol_string(uneval_head)) != m_symbol_types.end()) {
|
||||
m_symbol_types.find(uneval_head.as_symbol()) != m_symbol_types.end()) {
|
||||
// the local environment (mlets, lexicals, constants, globals) defines this symbol.
|
||||
// this will "win" over a method name lookup, so we should compile as normal
|
||||
head = compile_error_guard(args.unnamed.front(), env);
|
||||
@@ -457,7 +460,7 @@ Val* Compiler::compile_function_or_method_call(const goos::Object& form, Env* en
|
||||
env->make_ireg(type, m_ts.lookup_type_allow_partial_def(type)->get_preferred_reg_class());
|
||||
env->emit_ir<IR_RegSet>(form, copy, eval_args.at(i));
|
||||
copy->mark_as_settable();
|
||||
lexical_env->vars[head_as_lambda->lambda.params.at(i).name] = copy;
|
||||
lexical_env->vars[m_goos.intern_ptr(head_as_lambda->lambda.params.at(i).name)] = copy;
|
||||
}
|
||||
|
||||
// setup env
|
||||
@@ -668,21 +671,21 @@ Val* Compiler::compile_declare(const goos::Object& form, const goos::Object& res
|
||||
first.print());
|
||||
}
|
||||
|
||||
if (first.as_symbol()->name == "inline") {
|
||||
if (first.as_symbol() == "inline") {
|
||||
if (!rrest->is_empty_list()) {
|
||||
throw_compiler_error(first, "Invalid inline declare, no options were expected.");
|
||||
}
|
||||
settings.allow_inline = true;
|
||||
settings.inline_by_default = true;
|
||||
settings.save_code = true;
|
||||
} else if (first.as_symbol()->name == "allow-inline") {
|
||||
} else if (first.as_symbol() == "allow-inline") {
|
||||
if (!rrest->is_empty_list()) {
|
||||
throw_compiler_error(first, "Invalid allow-inline declare");
|
||||
}
|
||||
settings.allow_inline = true;
|
||||
settings.inline_by_default = false;
|
||||
settings.save_code = true;
|
||||
} else if (first.as_symbol()->name == "asm-func") {
|
||||
} else if (first.as_symbol() == "asm-func") {
|
||||
auto fe = env->function_env();
|
||||
fe->is_asm_func = true;
|
||||
if (!rrest->is_pair()) {
|
||||
@@ -693,13 +696,13 @@ Val* Compiler::compile_declare(const goos::Object& form, const goos::Object& res
|
||||
if (!rrest->as_pair()->cdr.is_empty_list()) {
|
||||
throw_compiler_error(first, "Invalid asm-func declare");
|
||||
}
|
||||
} else if (first.as_symbol()->name == "print-asm") {
|
||||
} else if (first.as_symbol() == "print-asm") {
|
||||
if (!rrest->is_empty_list()) {
|
||||
throw_compiler_error(first, "Invalid print-asm declare");
|
||||
}
|
||||
settings.print_asm = true;
|
||||
|
||||
} else if (first.as_symbol()->name == "allow-saved-regs") {
|
||||
} else if (first.as_symbol() == "allow-saved-regs") {
|
||||
if (!rrest->is_empty_list()) {
|
||||
throw_compiler_error(first, "Invalid allow-saved-regs declare");
|
||||
}
|
||||
@@ -730,7 +733,7 @@ Val* Compiler::compile_declare_file(const goos::Object& /*form*/,
|
||||
first.print());
|
||||
}
|
||||
|
||||
if (first.as_symbol()->name == "debug") {
|
||||
if (first.as_symbol() == "debug") {
|
||||
if (!rrest->is_empty_list()) {
|
||||
throw_compiler_error(first, "Invalid debug declare");
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ Val* Compiler::compile_quote(const goos::Object& form, const goos::Object& rest,
|
||||
auto& thing = args.unnamed.front();
|
||||
switch (thing.type) {
|
||||
case goos::ObjectType::SYMBOL:
|
||||
return compile_get_sym_obj(thing.as_symbol()->name, env);
|
||||
return compile_get_sym_obj(thing.as_symbol().name_ptr, env);
|
||||
case goos::ObjectType::EMPTY_LIST: {
|
||||
auto empty_pair = compile_get_sym_obj("_empty_", env);
|
||||
empty_pair->set_type(m_ts.make_typespec("pair"));
|
||||
@@ -196,16 +196,16 @@ Val* Compiler::compile_define_constant(const goos::Object& form,
|
||||
|
||||
// GOAL constant
|
||||
if (goal) {
|
||||
if (m_symbol_types.find(sym->name) != m_symbol_types.end()) {
|
||||
if (m_symbol_types.find(sym) != m_symbol_types.end()) {
|
||||
throw_compiler_error(form,
|
||||
"Cannot define {} as a constant because "
|
||||
"it is already the name of a symbol of type {}",
|
||||
sym->name, m_symbol_types.at(sym->name).print());
|
||||
sym.name_ptr, m_symbol_types.at(sym).print());
|
||||
}
|
||||
|
||||
auto existing = m_global_constants.find(sym);
|
||||
if (existing != m_global_constants.end() && existing->second != value) {
|
||||
print_compiler_warning("Constant {} has been redefined {} -> {}", sym->print(),
|
||||
print_compiler_warning("Constant {} has been redefined {} -> {}", sym.name_ptr,
|
||||
existing->second.print(), value.print());
|
||||
}
|
||||
m_global_constants[sym] = value;
|
||||
@@ -213,12 +213,12 @@ Val* Compiler::compile_define_constant(const goos::Object& form,
|
||||
|
||||
// GOOS constant
|
||||
if (goos) {
|
||||
m_goos.global_environment.as_env()->vars[sym] = value;
|
||||
m_goos.global_environment.as_env()->vars.set(sym, value);
|
||||
}
|
||||
|
||||
// TODO - eventually, it'd be nice if global constants were properly typed
|
||||
// and this information was propagated
|
||||
m_symbol_info.add_constant(sym->name, form, sym_meta);
|
||||
m_symbol_info.add_constant(sym.name_ptr, form, sym_meta);
|
||||
|
||||
return get_none();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ void Compiler::compile_state_handler_set(StructureType* state_type_info,
|
||||
// we don't use #f here because you might want to actually set the state to #f
|
||||
// (see crate-buzzer wait)
|
||||
auto& arg = args.named.at(name);
|
||||
if (!(arg.is_symbol() && arg.as_symbol()->name == "*no-state*")) {
|
||||
if (!(arg.is_symbol() && arg.as_symbol() == "*no-state*")) {
|
||||
auto field = get_field_of_structure(state_type_info, state_object, name, env);
|
||||
auto value = compile_error_guard(arg, env);
|
||||
// we need to save these for typechecking later
|
||||
@@ -60,8 +60,8 @@ Val* Compiler::compile_define_state_hook(const goos::Object& form,
|
||||
Val* enter_value = NULL;
|
||||
|
||||
// check parent
|
||||
auto& state_parent = args.unnamed.at(1).as_symbol()->name;
|
||||
auto state_parent_type = m_ts.make_typespec(state_parent);
|
||||
auto& state_parent = args.unnamed.at(1).as_symbol();
|
||||
auto state_parent_type = m_ts.make_typespec(state_parent.name_ptr);
|
||||
if (!m_ts.tc(TypeSpec("process"), state_parent_type)) {
|
||||
throw_compiler_error(form, "define-state got a type {} which is not a child of process",
|
||||
state_parent_type.print());
|
||||
@@ -97,7 +97,7 @@ Val* Compiler::compile_define_state_hook(const goos::Object& form,
|
||||
state_parent_type);
|
||||
}
|
||||
|
||||
auto& state_name = args.unnamed.at(0).as_symbol()->name;
|
||||
auto& state_name = args.unnamed.at(0).as_symbol();
|
||||
auto existing_var = m_symbol_types.find(state_name);
|
||||
|
||||
TypeSpec type_to_use;
|
||||
@@ -107,7 +107,7 @@ Val* Compiler::compile_define_state_hook(const goos::Object& form,
|
||||
throw_compiler_error(form,
|
||||
"define-state doesn't have enough information to determine the type of "
|
||||
"state {}, and it was not forward declared.",
|
||||
state_name);
|
||||
state_name.name_ptr);
|
||||
}
|
||||
type_to_use = *state_type;
|
||||
m_symbol_types[state_name] = *state_type;
|
||||
@@ -115,11 +115,11 @@ Val* Compiler::compile_define_state_hook(const goos::Object& form,
|
||||
type_to_use = existing_var->second;
|
||||
if (state_type) {
|
||||
typecheck(form, existing_var->second, *state_type,
|
||||
fmt::format("type of state {}", state_name));
|
||||
fmt::format("type of state {}", state_name.name_ptr));
|
||||
}
|
||||
}
|
||||
|
||||
auto sym_val = env->function_env()->alloc_val<SymbolVal>(state_name, type_to_use);
|
||||
auto sym_val = env->function_env()->alloc_val<SymbolVal>(state_name.name_ptr, type_to_use);
|
||||
|
||||
env->emit_ir<IR_SetSymbolValue>(form, sym_val, state_object);
|
||||
|
||||
@@ -158,8 +158,8 @@ Val* Compiler::compile_define_virtual_state_hook(const goos::Object& form,
|
||||
Val* enter_value = NULL;
|
||||
|
||||
// check parent
|
||||
auto& state_parent = args.unnamed.at(1).as_symbol()->name;
|
||||
auto state_parent_type = m_ts.make_typespec(state_parent);
|
||||
auto& state_parent = args.unnamed.at(1).as_symbol();
|
||||
auto state_parent_type = m_ts.make_typespec(state_parent.name_ptr);
|
||||
if (!m_ts.tc(TypeSpec("process"), state_parent_type)) {
|
||||
throw_compiler_error(form, "define-state got a type {} which is not a child of process",
|
||||
state_parent_type.print());
|
||||
@@ -172,24 +172,24 @@ Val* Compiler::compile_define_virtual_state_hook(const goos::Object& form,
|
||||
state_object->type().print());
|
||||
}
|
||||
|
||||
auto& state_name = args.unnamed.at(0).as_symbol()->name;
|
||||
auto& state_name = args.unnamed.at(0).as_symbol();
|
||||
|
||||
MethodInfo child_method_info;
|
||||
if (!m_ts.try_lookup_method(state_parent, state_name, &child_method_info)) {
|
||||
if (!m_ts.try_lookup_method(state_parent.name_ptr, state_name.name_ptr, &child_method_info)) {
|
||||
throw_compiler_error(
|
||||
form, "Tried to define a virtual state {} for type {}, but the state was not declared.",
|
||||
state_name, state_parent);
|
||||
state_name.name_ptr, state_parent.name_ptr);
|
||||
}
|
||||
|
||||
MethodInfo parent_method_info;
|
||||
auto parent_of_parent_type = m_ts.lookup_type(state_parent)->get_parent();
|
||||
if (m_ts.try_lookup_method(parent_of_parent_type, state_name, &parent_method_info) &&
|
||||
args.unnamed.at(3).as_symbol()->name == "#f") {
|
||||
auto parent_of_parent_type = m_ts.lookup_type(state_parent.name_ptr)->get_parent();
|
||||
if (m_ts.try_lookup_method(parent_of_parent_type, state_name.name_ptr, &parent_method_info) &&
|
||||
args.unnamed.at(3).as_symbol() == "#f") {
|
||||
// need to call inherit state TODO
|
||||
auto inherit_state_func =
|
||||
compile_get_symbol_value(form, "inherit-state", env)->to_gpr(form, env);
|
||||
auto parents_state =
|
||||
compile_get_method_of_type(form, TypeSpec(parent_of_parent_type), state_name, env)
|
||||
compile_get_method_of_type(form, TypeSpec(parent_of_parent_type), state_name.name_ptr, env)
|
||||
->to_gpr(form, env);
|
||||
compile_real_function_call(form, inherit_state_func, {state_object, parents_state}, env);
|
||||
}
|
||||
@@ -197,7 +197,7 @@ Val* Compiler::compile_define_virtual_state_hook(const goos::Object& form,
|
||||
// call method set.
|
||||
// (method-set! sunken-elevator 22 (the-as function gp-0))
|
||||
auto method_set_func = compile_get_symbol_value(form, "method-set!", env)->to_gpr(form, env);
|
||||
auto type_obj = compile_get_symbol_value(form, state_parent, env)->to_gpr(form, env);
|
||||
auto type_obj = compile_get_symbol_value(form, state_parent.name_ptr, env)->to_gpr(form, env);
|
||||
auto method_id = compile_integer(child_method_info.id, env)->to_gpr(form, env);
|
||||
compile_real_function_call(form, method_set_func, {type_obj, method_id, state_object}, env);
|
||||
|
||||
@@ -229,8 +229,8 @@ Val* Compiler::compile_define_virtual_state_hook(const goos::Object& form,
|
||||
child_method_info.type.substitute_for_method_call(state_parent_type.base_type())) {
|
||||
throw_compiler_error(
|
||||
form, "Virtual state {} of {} was declared as {}, but got {}. First declared in type {}.",
|
||||
state_name, state_parent, child_method_info.type.print(), state_type->print(),
|
||||
child_method_info.defined_in_type);
|
||||
state_name.name_ptr, state_parent.name_ptr, child_method_info.type.print(),
|
||||
state_type->print(), child_method_info.defined_in_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,13 +64,13 @@ void Compiler::compile_static_structure_inline(const goos::Object& form,
|
||||
"Array field must be defined with (new 'static ['array, 'inline-array] type-name ...)");
|
||||
}
|
||||
|
||||
if (!new_form.at(0).is_symbol() || new_form.at(0).as_symbol()->name != "new") {
|
||||
if (!new_form.at(0).is_symbol() || new_form.at(0).as_symbol() != "new") {
|
||||
throw_compiler_error(
|
||||
field_value,
|
||||
"Array field must be defined with (new 'static ['array, 'inline-array] type-name ...)");
|
||||
}
|
||||
|
||||
if (!is_quoted_sym(new_form.at(1)) || unquote(new_form.at(1)).as_symbol()->name != "static") {
|
||||
if (!is_quoted_sym(new_form.at(1)) || unquote(new_form.at(1)).as_symbol() != "static") {
|
||||
throw_compiler_error(
|
||||
field_value,
|
||||
"Array field must be defined with (new 'static ['array, 'inline-array] type-name ...)");
|
||||
@@ -169,13 +169,12 @@ void Compiler::compile_static_structure_inline(const goos::Object& form,
|
||||
"Inline field must be defined with (new 'static 'type-name ...)");
|
||||
}
|
||||
|
||||
if (!new_form.at(0).is_symbol() || new_form.at(0).as_symbol()->name != "new") {
|
||||
if (!new_form.at(0).is_symbol() || new_form.at(0).as_symbol() != "new") {
|
||||
throw_compiler_error(field_value,
|
||||
"Inline field must be defined with (new 'static 'type-name ...)");
|
||||
}
|
||||
|
||||
if (!is_quoted_sym(new_form.at(1)) ||
|
||||
unquote(new_form.at(1)).as_symbol()->name != "static") {
|
||||
if (!is_quoted_sym(new_form.at(1)) || unquote(new_form.at(1)).as_symbol() != "static") {
|
||||
throw_compiler_error(field_value,
|
||||
"Inline field must be defined with (new 'static 'type-name ...)");
|
||||
}
|
||||
@@ -615,7 +614,7 @@ StaticResult Compiler::compile_static_no_eval_for_pairs(const goos::Object& form
|
||||
(can_macro && form.as_pair()->car.is_symbol("lambda"))) {
|
||||
return compile_static(form, env);
|
||||
}
|
||||
if (form.as_pair()->car.is_symbol() && form.as_pair()->car.as_symbol()->name == "unquote") {
|
||||
if (form.as_pair()->car.is_symbol() && form.as_pair()->car.as_symbol() == "unquote") {
|
||||
// ,(macro-name args...) is actually (unquote (macro-name args...))
|
||||
// decompile the arg as macro if possible.
|
||||
// ,(lambda ...) is also a special case.
|
||||
@@ -658,7 +657,7 @@ StaticResult Compiler::compile_static_no_eval_for_pairs(const goos::Object& form
|
||||
}
|
||||
return StaticResult::make_constant_data(bint_val, TypeSpec("int32"));
|
||||
} else if (form.is_symbol()) {
|
||||
return StaticResult::make_symbol(form.as_symbol()->name);
|
||||
return StaticResult::make_symbol(form.as_symbol().name_ptr);
|
||||
} else if (form.is_empty_list()) {
|
||||
return StaticResult::make_symbol("_empty_");
|
||||
} else if (form.is_string()) {
|
||||
@@ -695,9 +694,9 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env
|
||||
|
||||
if (form.is_symbol()) {
|
||||
// constant, #t, or #f
|
||||
auto& name = form.as_symbol()->name;
|
||||
auto& name = form.as_symbol();
|
||||
if (name == "#t" || name == "#f") {
|
||||
return StaticResult::make_symbol(name);
|
||||
return StaticResult::make_symbol(name.name_ptr);
|
||||
}
|
||||
|
||||
// as a constant
|
||||
@@ -715,7 +714,7 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env
|
||||
} else if (form.is_int()) {
|
||||
return StaticResult::make_constant_data(form.as_int(), TypeSpec("integer"));
|
||||
} else if (is_quoted_sym(form)) {
|
||||
return StaticResult::make_symbol(unquote(form).as_symbol()->name);
|
||||
return StaticResult::make_symbol(unquote(form).as_symbol().name_ptr);
|
||||
} else if (form.is_string()) {
|
||||
// todo string pool
|
||||
auto obj = std::make_unique<StaticString>(form.as_string()->data, segment);
|
||||
@@ -725,7 +724,7 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env
|
||||
} else if (form.is_pair()) {
|
||||
auto first = form.as_pair()->car;
|
||||
auto rest = form.as_pair()->cdr;
|
||||
if (first.is_symbol() && first.as_symbol()->name == "quote") {
|
||||
if (first.is_symbol() && first.as_symbol() == "quote") {
|
||||
if (rest.is_pair()) {
|
||||
auto second = rest.as_pair()->car;
|
||||
if (!rest.as_pair()->cdr.is_empty_list()) {
|
||||
@@ -739,14 +738,14 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env
|
||||
}
|
||||
}
|
||||
throw_compiler_error(form, "The quoted form {} has no argument.", form.print());
|
||||
} else if (first.is_symbol() && first.as_symbol()->name == "new") {
|
||||
} else if (first.is_symbol() && first.as_symbol() == "new") {
|
||||
goos::Object constructor_args;
|
||||
auto args = get_list_as_vector(rest, &constructor_args, 2);
|
||||
if (args.size() < 2) {
|
||||
throw_compiler_error(form,
|
||||
"New form evaluated at compile must specify (new 'static <type> ...)");
|
||||
}
|
||||
if (!is_quoted_sym(args.at(0)) || unquote(args.at(0)).as_symbol()->name != "static") {
|
||||
if (!is_quoted_sym(args.at(0)) || unquote(args.at(0)).as_symbol() != "static") {
|
||||
throw_compiler_error(form, "New form evaluated at compile time must use 'static. Got {}.",
|
||||
args.at(0).print());
|
||||
}
|
||||
@@ -757,11 +756,11 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env
|
||||
}
|
||||
|
||||
auto unquoted_type = unquote(args.at(1));
|
||||
if (unquoted_type.as_symbol()->name == "boxed-array") {
|
||||
if (unquoted_type.as_symbol() == "boxed-array") {
|
||||
return fill_static_boxed_array(form, rest, env, segment, "array");
|
||||
} else if (unquoted_type.as_symbol()->name == "array") {
|
||||
} else if (unquoted_type.as_symbol() == "array") {
|
||||
return fill_static_array(form, rest, env, segment);
|
||||
} else if (unquoted_type.as_symbol()->name == "inline-array") {
|
||||
} else if (unquoted_type.as_symbol() == "inline-array") {
|
||||
return fill_static_inline_array(form, rest, env, segment);
|
||||
} else {
|
||||
auto ts = parse_typespec(unquoted_type, env);
|
||||
@@ -792,7 +791,7 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env
|
||||
throw_compiler_error(form, "Cannot construct a static {}.", ts.print());
|
||||
}
|
||||
}
|
||||
} else if (first.is_symbol() && first.as_symbol()->name == "the-as") {
|
||||
} else if (first.is_symbol() && first.as_symbol() == "the-as") {
|
||||
auto args = get_va(form, rest);
|
||||
va_check(form, args, {{}, {}}, {});
|
||||
auto type = parse_typespec(args.unnamed.at(0), env);
|
||||
@@ -802,7 +801,7 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env
|
||||
return StaticResult::make_constant_data(value, TypeSpec("float"));
|
||||
}
|
||||
}
|
||||
} else if (first.is_symbol() && first.as_symbol()->name == "the") {
|
||||
} else if (first.is_symbol() && first.as_symbol() == "the") {
|
||||
auto args = get_va(form, rest);
|
||||
va_check(form, args, {{}, {}}, {});
|
||||
auto type = parse_typespec(args.unnamed.at(0), env);
|
||||
@@ -817,7 +816,7 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env
|
||||
va_check(form, args, {goos::ObjectType::SYMBOL},
|
||||
{{{"method-count", {false, goos::ObjectType::INTEGER}}}});
|
||||
|
||||
auto type_name = args.unnamed.at(0).as_symbol()->name;
|
||||
std::string type_name = args.unnamed.at(0).as_symbol().name_ptr;
|
||||
|
||||
std::optional<int> expected_method_count = m_ts.try_get_type_method_count(type_name);
|
||||
int method_count = -1;
|
||||
@@ -878,7 +877,7 @@ void Compiler::fill_static_array_inline(const goos::Object& form,
|
||||
// Special case for symbols that refer to types
|
||||
StaticResult sr;
|
||||
if (content_type == TypeSpec("type") && arg.is_symbol()) {
|
||||
const auto& type_name = arg.as_symbol()->name;
|
||||
std::string type_name = arg.as_symbol().name_ptr;
|
||||
std::optional<int> expected_method_count = m_ts.try_get_type_method_count(type_name);
|
||||
if (!expected_method_count) {
|
||||
throw_compiler_error(form, "Undeclared type used in inline-array - {}", type_name);
|
||||
@@ -1076,12 +1075,12 @@ void Compiler::fill_static_inline_array_inline(const goos::Object& form,
|
||||
elt_def, "Inline array element must be defined with (new 'static 'type-name ...)");
|
||||
}
|
||||
|
||||
if (!new_form.at(0).is_symbol() || new_form.at(0).as_symbol()->name != "new") {
|
||||
if (!new_form.at(0).is_symbol() || new_form.at(0).as_symbol() != "new") {
|
||||
throw_compiler_error(
|
||||
elt_def, "Inline array element must be defined with (new 'static 'type-name ...)");
|
||||
}
|
||||
|
||||
if (!is_quoted_sym(new_form.at(1)) || unquote(new_form.at(1)).as_symbol()->name != "static") {
|
||||
if (!is_quoted_sym(new_form.at(1)) || unquote(new_form.at(1)).as_symbol() != "static") {
|
||||
throw_compiler_error(
|
||||
elt_def, "Inline array element must be defined with (new 'static 'type-name ...)");
|
||||
}
|
||||
|
||||
@@ -369,18 +369,19 @@ Val* Compiler::compile_deftype(const goos::Object& form, const goos::Object& res
|
||||
auto result = parse_deftype(rest, &m_ts, &m_global_constants);
|
||||
|
||||
// look up the type name
|
||||
auto kv = m_symbol_types.find(result.type.base_type());
|
||||
auto kv = m_symbol_types.find(m_goos.intern_ptr(result.type.base_type()));
|
||||
if (kv != m_symbol_types.end() && kv->second.base_type() != "type") {
|
||||
// we already have something that's not a type with the same name, this is bad.
|
||||
lg::print("[Warning] deftype will redefine {} from {} to a type.\n", result.type.base_type(),
|
||||
kv->second.print());
|
||||
}
|
||||
// remember that this is a type
|
||||
m_symbol_types[result.type.base_type()] = m_ts.make_typespec("type");
|
||||
m_symbol_types[m_goos.intern_ptr(result.type.base_type())] = m_ts.make_typespec("type");
|
||||
|
||||
// add declared states
|
||||
for (auto& state : result.type_info->get_states_declared_for_type()) {
|
||||
auto existing_type = m_symbol_types.find(state.first);
|
||||
auto interned_state_first = m_goos.intern_ptr(state.first);
|
||||
auto existing_type = m_symbol_types.find(interned_state_first);
|
||||
if (existing_type != m_symbol_types.end() && existing_type->second != state.second) {
|
||||
if (m_throw_on_define_extern_redefinition) {
|
||||
throw_compiler_error(form, "deftype would redefine the type of state {} from {} to {}.",
|
||||
@@ -394,7 +395,7 @@ Val* Compiler::compile_deftype(const goos::Object& form, const goos::Object& res
|
||||
}
|
||||
}
|
||||
|
||||
m_symbol_types[state.first] = state.second;
|
||||
m_symbol_types[interned_state_first] = state.second;
|
||||
m_symbol_info.add_fwd_dec(state.first, form);
|
||||
}
|
||||
|
||||
@@ -530,10 +531,10 @@ Val* Compiler::compile_defmethod(const goos::Object& form, const goos::Object& _
|
||||
self_var->set_rlet_constraint(constr.desired_register);
|
||||
new_func_env->constrain(constr);
|
||||
|
||||
if (new_func_env->params.find("self") != new_func_env->params.end()) {
|
||||
if (new_func_env->params.find(m_goos.intern_ptr("self")) != new_func_env->params.end()) {
|
||||
throw_compiler_error(form, "Cannot have an argument named self in a behavior");
|
||||
}
|
||||
new_func_env->params["self"] = self_var;
|
||||
new_func_env->params[m_goos.intern_ptr("self")] = self_var;
|
||||
reset_args_for_coloring.push_back(self_var);
|
||||
lambda_ts.add_new_tag("behavior", *behavior);
|
||||
}
|
||||
@@ -551,7 +552,7 @@ Val* Compiler::compile_defmethod(const goos::Object& form, const goos::Object& _
|
||||
auto ireg = new_func_env->make_ireg(
|
||||
lambda.params.at(i).type, arg_regs.at(i).is_gpr() ? RegClass::GPR_64 : RegClass::INT_128);
|
||||
ireg->mark_as_settable();
|
||||
if (!new_func_env->params.insert({lambda.params.at(i).name, ireg}).second) {
|
||||
if (!new_func_env->params.insert({m_goos.intern_ptr(lambda.params.at(i).name), ireg}).second) {
|
||||
throw_compiler_error(form, "defmethod has multiple arguments named {}",
|
||||
lambda.params.at(i).name);
|
||||
}
|
||||
@@ -975,7 +976,7 @@ Val* Compiler::compile_heap_new(const goos::Object& form,
|
||||
const goos::Object& type,
|
||||
const goos::Object* rest,
|
||||
Env* env) {
|
||||
bool making_boxed_array = unquote(type).as_symbol()->name == "boxed-array";
|
||||
bool making_boxed_array = unquote(type).as_symbol() == "boxed-array";
|
||||
TypeSpec main_type;
|
||||
if (!making_boxed_array) {
|
||||
main_type = parse_typespec(unquote(type), env);
|
||||
@@ -1042,7 +1043,7 @@ Val* Compiler::compile_heap_new(const goos::Object& form,
|
||||
if (making_boxed_array && !got_content_type) {
|
||||
got_content_type = true;
|
||||
if (o.is_symbol()) {
|
||||
content_type = o.as_symbol()->name;
|
||||
content_type = o.as_symbol().name_ptr;
|
||||
args.push_back(compile_get_symbol_value(form, content_type, env)->to_reg(form, env));
|
||||
} else {
|
||||
throw_compiler_error(form, "Invalid boxed-array type {}", o.print());
|
||||
@@ -1070,7 +1071,7 @@ Val* Compiler::compile_static_new(const goos::Object& form,
|
||||
const goos::Object* rest,
|
||||
Env* env) {
|
||||
auto unquoted_type = unquote(type);
|
||||
const auto& sym_name = unquoted_type.as_symbol()->name;
|
||||
const auto& sym_name = unquoted_type.as_symbol();
|
||||
// Check if the type is an array or a subtype of 'array'
|
||||
bool is_array = sym_name == "boxed-array" || sym_name == "array" || sym_name == "inline-array";
|
||||
if (!is_array) {
|
||||
@@ -1369,14 +1370,14 @@ Val* Compiler::compile_declare_type(const goos::Object& form, const goos::Object
|
||||
va_check(form, args, {goos::ObjectType::SYMBOL, goos::ObjectType::SYMBOL}, {});
|
||||
|
||||
auto kind = symbol_string(args.unnamed.at(1));
|
||||
auto type_name = symbol_string(args.unnamed.at(0));
|
||||
auto type_name = args.unnamed.at(0).as_symbol();
|
||||
|
||||
m_ts.forward_declare_type_as(type_name, kind);
|
||||
m_ts.forward_declare_type_as(type_name.name_ptr, kind);
|
||||
|
||||
auto existing_type = m_symbol_types.find(type_name);
|
||||
if (existing_type != m_symbol_types.end() && existing_type->second != TypeSpec("type")) {
|
||||
throw_compiler_error(form, "Cannot forward declare {} as a type: it is already a {}", type_name,
|
||||
existing_type->second.print());
|
||||
throw_compiler_error(form, "Cannot forward declare {} as a type: it is already a {}",
|
||||
type_name.name_ptr, existing_type->second.print());
|
||||
}
|
||||
m_symbol_types[type_name] = TypeSpec("type");
|
||||
|
||||
@@ -1473,15 +1474,15 @@ int Compiler::get_size_for_size_of(const goos::Object& form, const goos::Object&
|
||||
auto args = get_va(form, rest);
|
||||
va_check(form, args, {goos::ObjectType::SYMBOL}, {});
|
||||
|
||||
auto type_to_look_for = args.unnamed.at(0).as_symbol()->name;
|
||||
auto type_to_look_for = args.unnamed.at(0).as_symbol();
|
||||
|
||||
if (!m_ts.fully_defined_type_exists(type_to_look_for)) {
|
||||
if (!m_ts.fully_defined_type_exists(type_to_look_for.name_ptr)) {
|
||||
throw_compiler_error(
|
||||
form, "The type or enum {} given to size-of could not be found, or was not fully defined",
|
||||
args.unnamed.at(0).print());
|
||||
}
|
||||
|
||||
auto type = m_ts.lookup_type(type_to_look_for);
|
||||
auto type = m_ts.lookup_type(type_to_look_for.name_ptr);
|
||||
auto as_value = dynamic_cast<ValueType*>(type);
|
||||
auto as_structure = dynamic_cast<StructureType*>(type);
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ goos::Object MakeSystem::handle_defstep(const goos::Object& form,
|
||||
step->outputs.push_back(m_path_map.apply_remaps(obj.as_string()->data));
|
||||
});
|
||||
|
||||
step->tool = args.get_named("tool").as_symbol()->name;
|
||||
step->tool = args.get_named("tool").as_symbol().name_ptr;
|
||||
|
||||
if (m_tools.find(step->tool) == m_tools.end()) {
|
||||
throw std::runtime_error(fmt::format("The tool {} is unknown.", step->tool));
|
||||
@@ -232,7 +232,7 @@ goos::Object MakeSystem::handle_get_gsrc_path(const goos::Object& form,
|
||||
if (m_gsrc_files.count(file_name) != 0) {
|
||||
return goos::StringObject::make_new(m_gsrc_files.at(file_name));
|
||||
} else {
|
||||
return goos::SymbolObject::make_new(m_goos.reader.symbolTable, "#f");
|
||||
return goos::Object::make_symbol(&m_goos.reader.symbolTable, "#f");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -131,11 +131,11 @@ std::optional<DefinitionMetadata> Workspace::get_definition_info_from_all_types(
|
||||
if (m_tracked_all_types_files.count(all_types_uri) == 0) {
|
||||
return {};
|
||||
}
|
||||
const auto& dts = m_tracked_all_types_files[all_types_uri].m_dts;
|
||||
if (dts.symbol_metadata_map.count(symbol_name) == 0) {
|
||||
const auto& dts = m_tracked_all_types_files[all_types_uri]->m_dts;
|
||||
if (dts->symbol_metadata_map.count(symbol_name) == 0) {
|
||||
return {};
|
||||
}
|
||||
return dts.symbol_metadata_map.at(symbol_name);
|
||||
return dts->symbol_metadata_map.at(symbol_name);
|
||||
}
|
||||
|
||||
// TODO - a gross hack that should go away when the language isn't so tightly coupled to the jak
|
||||
@@ -219,9 +219,9 @@ void Workspace::start_tracking_file(const LSPSpec::DocumentUri& file_uri,
|
||||
if (!file.m_all_types_uri.empty()) {
|
||||
if (m_tracked_all_types_files.count(file.m_all_types_uri) == 0) {
|
||||
lg::debug("new all-types file - {}", file.m_all_types_uri);
|
||||
m_tracked_all_types_files[file.m_all_types_uri] = WorkspaceAllTypesFile(
|
||||
m_tracked_all_types_files[file.m_all_types_uri] = std::make_unique<WorkspaceAllTypesFile>(
|
||||
file.m_all_types_uri, file.m_game_version, file.m_all_types_file_path);
|
||||
m_tracked_all_types_files[file.m_all_types_uri].parse_type_system();
|
||||
m_tracked_all_types_files[file.m_all_types_uri]->parse_type_system();
|
||||
}
|
||||
}
|
||||
} else if (language_id == "opengoal") {
|
||||
@@ -269,10 +269,10 @@ void Workspace::update_tracked_file(const LSPSpec::DocumentUri& file_uri,
|
||||
if (!file.m_all_types_uri.empty() &&
|
||||
m_tracked_all_types_files.count(file.m_all_types_uri) == 0) {
|
||||
auto& all_types_file = m_tracked_all_types_files[file.m_all_types_uri];
|
||||
all_types_file.m_file_path = file.m_all_types_file_path;
|
||||
all_types_file.m_uri = file.m_all_types_uri;
|
||||
all_types_file.m_game_version = file.m_game_version;
|
||||
all_types_file.update_type_system();
|
||||
all_types_file->m_file_path = file.m_all_types_file_path;
|
||||
all_types_file->m_uri = file.m_all_types_uri;
|
||||
all_types_file->m_game_version = file.m_game_version;
|
||||
all_types_file->update_type_system();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ void Workspace::update_tracked_file(const LSPSpec::DocumentUri& file_uri,
|
||||
lg::debug("updating tracked all types file - {}", file_uri);
|
||||
// If the all-types file has changed, re-parse it
|
||||
// NOTE - this assumes its still for the same game version!
|
||||
m_tracked_all_types_files[file_uri].update_type_system();
|
||||
m_tracked_all_types_files[file_uri]->update_type_system();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -504,11 +504,11 @@ std::optional<std::string> WorkspaceIRFile::get_symbol_at_position(
|
||||
|
||||
void WorkspaceAllTypesFile::parse_type_system() {
|
||||
lg::debug("DTS Loading - '{}'", m_file_path.string());
|
||||
m_dts.parse_type_defs({m_file_path.string()});
|
||||
m_dts->parse_type_defs({m_file_path.string()});
|
||||
lg::debug("DTS Loaded At - '{}'", m_file_path.string());
|
||||
}
|
||||
|
||||
void WorkspaceAllTypesFile::update_type_system() {
|
||||
m_dts = decompiler::DecompilerTypeSystem(m_game_version);
|
||||
m_dts = std::make_unique<decompiler::DecompilerTypeSystem>(m_game_version);
|
||||
parse_type_system();
|
||||
}
|
||||
|
||||
@@ -58,15 +58,19 @@ class WorkspaceIRFile {
|
||||
|
||||
class WorkspaceAllTypesFile {
|
||||
public:
|
||||
WorkspaceAllTypesFile() : m_dts(GameVersion::Jak1){};
|
||||
WorkspaceAllTypesFile()
|
||||
: m_dts(std::make_unique<decompiler::DecompilerTypeSystem>(GameVersion::Jak1)){};
|
||||
WorkspaceAllTypesFile(const LSPSpec::DocumentUri& uri,
|
||||
const GameVersion version,
|
||||
const fs::path file_path)
|
||||
: m_game_version(version), m_uri(uri), m_dts(m_game_version), m_file_path(file_path){};
|
||||
: m_game_version(version),
|
||||
m_uri(uri),
|
||||
m_dts(std::make_unique<decompiler::DecompilerTypeSystem>(m_game_version)),
|
||||
m_file_path(file_path){};
|
||||
|
||||
GameVersion m_game_version;
|
||||
LSPSpec::DocumentUri m_uri;
|
||||
decompiler::DecompilerTypeSystem m_dts;
|
||||
std::unique_ptr<decompiler::DecompilerTypeSystem> m_dts;
|
||||
fs::path m_file_path;
|
||||
|
||||
void parse_type_system();
|
||||
@@ -110,7 +114,8 @@ class Workspace {
|
||||
bool m_initialized = false;
|
||||
std::unordered_map<LSPSpec::DocumentUri, WorkspaceOGFile> m_tracked_og_files = {};
|
||||
std::unordered_map<LSPSpec::DocumentUri, WorkspaceIRFile> m_tracked_ir_files = {};
|
||||
std::unordered_map<LSPSpec::DocumentUri, WorkspaceAllTypesFile> m_tracked_all_types_files = {};
|
||||
std::unordered_map<LSPSpec::DocumentUri, std::unique_ptr<WorkspaceAllTypesFile>>
|
||||
m_tracked_all_types_files = {};
|
||||
|
||||
// TODO:
|
||||
// OpenGOAL is still incredibly tightly coupled to the jak projects as a language
|
||||
|
||||
+7
-32
@@ -441,31 +441,6 @@ TEST(GoosBuiltins, Type) {
|
||||
EXPECT_EQ(e(i, "(type? 'environment '())"), "#f");
|
||||
}
|
||||
|
||||
/*!
|
||||
* Confirm that the global and goos env variables appear
|
||||
*/
|
||||
TEST(GoosEval, GlobalAndGoalEnv) {
|
||||
Interpreter i;
|
||||
Object goal_env, goos_env;
|
||||
EXPECT_TRUE(i.get_global_variable_by_name("*global-env*", &goos_env));
|
||||
EXPECT_TRUE(i.get_global_variable_by_name("*goal-env*", &goal_env));
|
||||
|
||||
auto& goal_vars = goal_env.as_env()->vars;
|
||||
auto& goos_vars = goos_env.as_env()->vars;
|
||||
|
||||
EXPECT_TRUE(goal_vars.find(i.intern("*global-env*").as_symbol()) != goal_vars.end());
|
||||
EXPECT_TRUE(goal_vars.find(i.intern("*goal-env*").as_symbol()) != goal_vars.end());
|
||||
EXPECT_TRUE(goos_vars.find(i.intern("*global-env*").as_symbol()) != goos_vars.end());
|
||||
EXPECT_TRUE(goos_vars.find(i.intern("*goal-env*").as_symbol()) != goos_vars.end());
|
||||
|
||||
EXPECT_TRUE(goos_vars.find(i.intern("*goal-env*").as_symbol())->second ==
|
||||
goal_vars.find(i.intern("*goal-env*").as_symbol())->second);
|
||||
EXPECT_TRUE(goos_vars.find(i.intern("*global-env*").as_symbol())->second ==
|
||||
goal_vars.find(i.intern("*global-env*").as_symbol())->second);
|
||||
EXPECT_TRUE(goos_vars.find(i.intern("*global-env*").as_symbol())->second !=
|
||||
goos_vars.find(i.intern("*goal-env*").as_symbol())->second);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Confirm that the GOOS Library is loaded automatically on interpreter start.
|
||||
*/
|
||||
@@ -1047,10 +1022,10 @@ TEST(GoosObject, Char) {
|
||||
*/
|
||||
TEST(GoosObject, Symbol) {
|
||||
SymbolTable st, st2;
|
||||
Object obj = SymbolObject::make_new(st, "test1");
|
||||
Object obj2 = SymbolObject::make_new(st, "test2");
|
||||
Object obj3 = SymbolObject::make_new(st, "test1");
|
||||
Object obj4 = SymbolObject::make_new(st2, "test1");
|
||||
Object obj = Object::make_symbol(&st, "test1");
|
||||
Object obj2 = Object::make_symbol(&st, "test2");
|
||||
Object obj3 = Object::make_symbol(&st, "test1");
|
||||
Object obj4 = Object::make_symbol(&st2, "test1");
|
||||
|
||||
// check type
|
||||
EXPECT_TRUE(obj.is_symbol());
|
||||
@@ -1173,9 +1148,9 @@ TEST(GoosSpecialForms, Define) {
|
||||
Object goal_env;
|
||||
EXPECT_TRUE(i.get_global_variable_by_name("*goal-env*", &goal_env));
|
||||
|
||||
auto x_in_goal_env = goal_env.as_env()->vars.find(i.intern("x").as_symbol());
|
||||
EXPECT_TRUE(x_in_goal_env != goal_env.as_env()->vars.end());
|
||||
EXPECT_EQ(x_in_goal_env->second.print(), "20");
|
||||
auto x_in_goal_env = goal_env.as_env()->vars.lookup(i.intern("x").as_symbol());
|
||||
EXPECT_TRUE(x_in_goal_env);
|
||||
EXPECT_EQ(x_in_goal_env->print(), "20");
|
||||
|
||||
// test automatic environment of define
|
||||
e(i, "(begin (desfun test-define () (define x 500)) (test-define))");
|
||||
|
||||
@@ -26,7 +26,7 @@ bool check_first_float(Object o, double x) {
|
||||
}
|
||||
|
||||
bool check_first_symbol(Object o, const std::string& sym) {
|
||||
return o.as_pair()->cdr.as_pair()->car.as_symbol()->name == sym;
|
||||
return o.as_pair()->cdr.as_pair()->car.as_symbol() == sym;
|
||||
}
|
||||
|
||||
bool check_first_string(Object o, const std::string& str) {
|
||||
|
||||
Reference in New Issue
Block a user