[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:
water111
2023-10-07 07:48:17 -07:00
committed by GitHub
parent af6f489657
commit 395c98db19
43 changed files with 948 additions and 549 deletions
+361 -137
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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) + " " +
+3 -3
View File
@@ -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;
}
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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
View File
@@ -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;
+4 -4
View File
@@ -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));
+8 -7
View File
@@ -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));
+2 -2
View File
@@ -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) == ':') {
+30 -24
View File
@@ -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;
+2 -1
View File
@@ -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);
-40
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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")) {
+1 -1
View File
@@ -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;
}
+8 -8
View File
@@ -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());
+1 -1
View File
@@ -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
View File
@@ -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))
+6 -6
View File
@@ -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);
+8 -5
View File
@@ -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);
+1 -1
View File
@@ -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");
}
}
+2 -2
View File
@@ -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);
}
+6 -6
View File
@@ -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;
+1 -1
View File
@@ -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;
};
+6 -6
View File
@@ -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;
}
}
+7 -7
View File
@@ -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();
}
+4 -4
View File
@@ -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()) {
+11 -10
View File
@@ -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 =
+3 -3
View File
@@ -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;
+5 -5
View File
@@ -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();
}
+20 -17
View File
@@ -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");
}
+6 -6
View File
@@ -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();
}
+19 -19
View File
@@ -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);
}
}
+21 -22
View File
@@ -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 ...)");
}
+18 -17
View File
@@ -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);
+2 -2
View File
@@ -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
View File
@@ -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();
}
+9 -4
View File
@@ -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
View File
@@ -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))");
+1 -1
View File
@@ -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) {