mirror of
https://github.com/open-goal/jak-project.git
synced 2024-11-23 06:09:57 +00:00
[goalc] speed up jak3 compilation (#3454)
I noticed that jak 3's compilation was spending a lot of time accessing the `unordered_map`s we use to store constants and symbol types. I repurposed the `EnvironmentMap` originally made for GOOS for this. It turns out that we were copying the entire constant map whenever we encountered a `deftype`, and fixed that too. This speeds up jak3 compiles from ~16 to 11 seconds for me.
This commit is contained in:
parent
376194a3e7
commit
cc8801a27b
@ -571,104 +571,6 @@ 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 {
|
||||
|
||||
/*!
|
||||
|
@ -55,6 +55,7 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/Assert.h"
|
||||
#include "common/util/crc32.h"
|
||||
|
||||
namespace goos {
|
||||
|
||||
@ -456,23 +457,111 @@ class PairObject : public HeapObject {
|
||||
~PairObject() = default;
|
||||
};
|
||||
|
||||
class EnvironmentMap {
|
||||
template <typename T>
|
||||
class InternedPtrMap {
|
||||
public:
|
||||
EnvironmentMap(const EnvironmentMap&) = delete;
|
||||
EnvironmentMap& operator=(const EnvironmentMap&) = delete;
|
||||
EnvironmentMap();
|
||||
Object* lookup(InternedSymbolPtr ptr);
|
||||
void set(InternedSymbolPtr ptr, const Object& obj);
|
||||
void clear();
|
||||
InternedPtrMap(const InternedPtrMap&) = delete;
|
||||
InternedPtrMap& operator=(const InternedPtrMap&) = delete;
|
||||
InternedPtrMap() { clear(); }
|
||||
|
||||
T* 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 set(InternedSymbolPtr ptr, const T& 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 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;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Entry {
|
||||
const char* key = nullptr;
|
||||
Object value;
|
||||
T value;
|
||||
};
|
||||
std::vector<Entry> m_entries;
|
||||
|
||||
void resize();
|
||||
void 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();
|
||||
}
|
||||
int m_power_of_two_size = 0;
|
||||
int m_used_entries = 0;
|
||||
int m_next_resize = 0;
|
||||
@ -480,6 +569,8 @@ class EnvironmentMap {
|
||||
static constexpr float kMaxUsed = 0.7;
|
||||
};
|
||||
|
||||
using EnvironmentMap = InternedPtrMap<Object>;
|
||||
|
||||
class EnvironmentObject : public HeapObject {
|
||||
public:
|
||||
std::string name;
|
||||
|
@ -84,12 +84,10 @@ 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::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>&
|
||||
constants) {
|
||||
void add_field(StructureType* structure,
|
||||
TypeSystem* ts,
|
||||
const goos::Object& def,
|
||||
goos::EnvironmentMap* constants) {
|
||||
auto rest = &def;
|
||||
|
||||
auto name = symbol_string(car(rest));
|
||||
@ -113,9 +111,8 @@ void add_field(
|
||||
if (car(rest).is_int()) {
|
||||
array_size = car(rest).integer_obj.value;
|
||||
rest = cdr(rest);
|
||||
} else if (car(rest).is_symbol() &&
|
||||
constants.find((car(rest)).as_symbol()) != constants.end()) {
|
||||
array_size = get_int(constants[(car(rest)).as_symbol()]);
|
||||
} else if (car(rest).is_symbol() && constants && constants->lookup((car(rest)).as_symbol())) {
|
||||
array_size = get_int(*constants->lookup((car(rest)).as_symbol()));
|
||||
rest = cdr(rest);
|
||||
}
|
||||
|
||||
@ -543,13 +540,11 @@ void declare_state(Type* type,
|
||||
});
|
||||
}
|
||||
|
||||
StructureDefResult parse_structure_def(
|
||||
StructureType* type,
|
||||
TypeSystem* ts,
|
||||
const goos::Object& fields,
|
||||
const goos::Object& options,
|
||||
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>&
|
||||
constants) {
|
||||
StructureDefResult parse_structure_def(StructureType* type,
|
||||
TypeSystem* ts,
|
||||
const goos::Object& fields,
|
||||
const goos::Object& options,
|
||||
goos::EnvironmentMap* constants) {
|
||||
StructureDefResult result;
|
||||
for_each_in_list(fields, [&](const goos::Object& o) { add_field(type, ts, o, constants); });
|
||||
TypeFlags flags;
|
||||
@ -811,18 +806,11 @@ 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::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>*
|
||||
constants) {
|
||||
DeftypeResult parse_deftype(const goos::Object& deftype,
|
||||
TypeSystem* ts,
|
||||
goos::EnvironmentMap* constants) {
|
||||
DefinitionMetadata symbol_metadata;
|
||||
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;
|
||||
}
|
||||
goos::EnvironmentMap no_consts;
|
||||
|
||||
auto iter = &deftype;
|
||||
|
||||
@ -861,8 +849,7 @@ DeftypeResult parse_deftype(
|
||||
}
|
||||
new_type->inherit(pto);
|
||||
ts->forward_declare_type_as(name, pto->get_name());
|
||||
auto sr =
|
||||
parse_structure_def(new_type.get(), ts, field_list_obj, options_obj, constants_to_use);
|
||||
auto sr = parse_structure_def(new_type.get(), ts, field_list_obj, options_obj, constants);
|
||||
result.flags = sr.flags;
|
||||
result.create_runtime_type = sr.generate_runtime_type;
|
||||
structure_result = sr;
|
||||
@ -891,8 +878,7 @@ DeftypeResult parse_deftype(
|
||||
ASSERT(pto);
|
||||
new_type->inherit(pto);
|
||||
ts->forward_declare_type_as(name, pto->get_name());
|
||||
auto sr =
|
||||
parse_structure_def(new_type.get(), ts, field_list_obj, options_obj, constants_to_use);
|
||||
auto sr = parse_structure_def(new_type.get(), ts, field_list_obj, options_obj, constants);
|
||||
result.flags = sr.flags;
|
||||
result.create_runtime_type = sr.generate_runtime_type;
|
||||
structure_result = sr;
|
||||
|
@ -17,9 +17,7 @@ struct DeftypeResult {
|
||||
bool create_runtime_type = true;
|
||||
};
|
||||
|
||||
DeftypeResult parse_deftype(
|
||||
const goos::Object& deftype,
|
||||
TypeSystem* ts,
|
||||
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>*
|
||||
constants = nullptr);
|
||||
DeftypeResult parse_deftype(const goos::Object& deftype,
|
||||
TypeSystem* ts,
|
||||
goos::EnvironmentMap* constants = nullptr);
|
||||
TypeSpec parse_typespec(const TypeSystem* type_system, const goos::Object& src);
|
||||
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
@ -125,10 +125,8 @@ class Compiler {
|
||||
// TODO - this should be able to be removed, these are stored in `m_symbol_info`
|
||||
std::unordered_map<std::string, goos::ArgumentSpec> m_macro_specs;
|
||||
// TODO - this should be able to be removed, these are stored in `m_symbol_info`
|
||||
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;
|
||||
goos::InternedPtrMap<TypeSpec> m_symbol_types;
|
||||
goos::InternedPtrMap<goos::Object> m_global_constants;
|
||||
std::unordered_map<goos::InternedSymbolPtr, InlineableFunction, goos::InternedSymbolPtr::hash>
|
||||
m_inlineable_functions;
|
||||
CompilerSettings m_settings;
|
||||
|
@ -314,7 +314,7 @@ bool Compiler::is_local_symbol(const goos::Object& obj, Env* env) {
|
||||
}
|
||||
|
||||
// check global constants
|
||||
if (m_global_constants.find(obj.as_symbol()) != m_global_constants.end()) {
|
||||
if (m_global_constants.lookup(obj.as_symbol())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -219,12 +219,11 @@ Val* Compiler::compile_asm_load_sym(const goos::Object& form, const goos::Object
|
||||
form, args, {{}, {goos::ObjectType::SYMBOL}},
|
||||
{{"sext", {false, goos::ObjectType::SYMBOL}}, {"color", {false, goos::ObjectType::SYMBOL}}});
|
||||
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()) {
|
||||
const auto* sym_ts = m_symbol_types.lookup(sym_name);
|
||||
if (!sym_ts) {
|
||||
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();
|
||||
bool sext = m_ts.lookup_type(*sym_ts)->get_load_signed();
|
||||
if (args.has_named("sext")) {
|
||||
sext = get_true_or_false(form, args.named.at("sext"));
|
||||
}
|
||||
|
@ -388,13 +388,13 @@ 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(m_goos.intern_ptr(name));
|
||||
if (existing_symbol == m_symbol_types.end()) {
|
||||
auto existing_symbol = m_symbol_types.lookup(m_goos.intern_ptr(name));
|
||||
if (!existing_symbol) {
|
||||
throw_compiler_error(
|
||||
form, "The symbol {} was looked up as a global variable, but it does not exist.", name);
|
||||
}
|
||||
|
||||
auto ts = existing_symbol->second;
|
||||
const auto& ts = *existing_symbol;
|
||||
auto sext = m_ts.lookup_type_allow_partial_def(ts)->get_load_signed();
|
||||
auto fe = env->function_env();
|
||||
auto sym = fe->alloc_val<SymbolVal>(name, m_ts.make_typespec("symbol"));
|
||||
@ -431,20 +431,20 @@ Val* Compiler::compile_symbol(const goos::Object& form, Env* env) {
|
||||
return lexical;
|
||||
}
|
||||
|
||||
auto global_constant = m_global_constants.find(form.as_symbol());
|
||||
auto existing_symbol = m_symbol_types.find(form.as_symbol());
|
||||
auto global_constant = m_global_constants.lookup(form.as_symbol());
|
||||
auto existing_symbol = m_symbol_types.lookup(form.as_symbol());
|
||||
|
||||
// see if it's a constant
|
||||
if (global_constant != m_global_constants.end()) {
|
||||
if (global_constant) {
|
||||
// check there is no symbol with the same name
|
||||
if (existing_symbol != m_symbol_types.end()) {
|
||||
if (existing_symbol) {
|
||||
throw_compiler_error(form,
|
||||
"Ambiguous symbol: {} is both a global variable and a constant and it "
|
||||
"is not clear which should be used here.");
|
||||
}
|
||||
|
||||
// got a global constant
|
||||
return compile_error_guard(global_constant->second, env);
|
||||
return compile_error_guard(*global_constant, env);
|
||||
}
|
||||
|
||||
// none of those, so get a global symbol.
|
||||
|
@ -362,7 +362,7 @@ std::string Compiler::make_symbol_info_description(const symbol_info::SymbolInfo
|
||||
switch (info->m_kind) {
|
||||
case symbol_info::Kind::GLOBAL_VAR:
|
||||
return fmt::format("[Global Variable] Type: {} Defined: {}",
|
||||
m_symbol_types.at(m_goos.intern_ptr(info->m_name)).print(),
|
||||
m_symbol_types.lookup(m_goos.intern_ptr(info->m_name))->print(),
|
||||
m_goos.reader.db.get_info_for(info->m_def_form));
|
||||
case symbol_info::Kind::LANGUAGE_BUILTIN:
|
||||
return fmt::format("[Built-in Form] {}\n", info->m_name);
|
||||
@ -379,7 +379,8 @@ std::string Compiler::make_symbol_info_description(const symbol_info::SymbolInfo
|
||||
case symbol_info::Kind::CONSTANT:
|
||||
return fmt::format(
|
||||
"[Constant] Name: {} Value: {} Defined: {}", info->m_name,
|
||||
m_global_constants.at(m_goos.reader.symbolTable.intern(info->m_name.c_str())).print(),
|
||||
m_global_constants.lookup(m_goos.reader.symbolTable.intern(info->m_name.c_str()))
|
||||
->print(),
|
||||
m_goos.reader.db.get_info_for(info->m_def_form));
|
||||
case symbol_info::Kind::FUNCTION:
|
||||
return fmt::format("[Function] Name: {} Defined: {}", info->m_name,
|
||||
@ -615,9 +616,9 @@ std::vector<symbol_info::SymbolInfo*> Compiler::lookup_exact_name_info(
|
||||
}
|
||||
|
||||
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;
|
||||
const auto it = m_symbol_types.lookup(m_goos.intern_ptr(symbol_name));
|
||||
if (it) {
|
||||
return *it;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@ -686,7 +687,7 @@ Compiler::generate_per_file_symbol_info() {
|
||||
if (sym_info->m_kind == symbol_info::Kind::CONSTANT) {
|
||||
var.type = "unknown"; // Unfortunately, constants are not properly typed
|
||||
} else {
|
||||
var.type = m_symbol_types.at(m_goos.intern_ptr(var.name)).base_type();
|
||||
var.type = m_symbol_types.lookup(m_goos.intern_ptr(var.name))->base_type();
|
||||
}
|
||||
var.def_location = def_loc;
|
||||
if (sym_info->m_kind == symbol_info::Kind::GLOBAL_VAR) {
|
||||
@ -701,8 +702,8 @@ Compiler::generate_per_file_symbol_info() {
|
||||
func.def_location = def_loc;
|
||||
func.args = Docs::get_args_from_docstring(sym_info->m_args, func.description);
|
||||
// The last arg in the typespec is the return type
|
||||
const auto& func_type = m_symbol_types.at(m_goos.intern_ptr(func.name));
|
||||
func.return_type = func_type.last_arg().base_type();
|
||||
const auto func_type = m_symbol_types.lookup(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->m_kind == symbol_info::Kind::TYPE) {
|
||||
Docs::TypeDocumentation type;
|
||||
|
@ -187,13 +187,13 @@ 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());
|
||||
const auto* global_constant = m_global_constants.lookup(expanded.as_symbol());
|
||||
const auto* existing_symbol = m_symbol_types.lookup(expanded.as_symbol());
|
||||
|
||||
// see if it's a constant
|
||||
if (global_constant != m_global_constants.end()) {
|
||||
if (global_constant) {
|
||||
// check there is no symbol with the same name, this is likely a bug and complain.
|
||||
if (existing_symbol != m_symbol_types.end()) {
|
||||
if (existing_symbol) {
|
||||
throw_compiler_error(
|
||||
code,
|
||||
"Ambiguous symbol: {} is both a global variable and a constant and it "
|
||||
@ -201,7 +201,7 @@ Compiler::ConstPropResult Compiler::constant_propagation_dispatch(const goos::Ob
|
||||
}
|
||||
|
||||
// got a global constant
|
||||
return try_constant_propagation(global_constant->second, env);
|
||||
return try_constant_propagation(*global_constant, env);
|
||||
} else {
|
||||
// return to the compiler, we can't figure it out.
|
||||
return {expanded, true};
|
||||
|
@ -24,11 +24,11 @@ Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest
|
||||
auto& val = args.unnamed.at(1);
|
||||
|
||||
// check we aren't duplicated a name as both a symbol and global constant
|
||||
auto global_constant = m_global_constants.find(sym.as_symbol());
|
||||
if (global_constant != m_global_constants.end()) {
|
||||
auto global_constant = m_global_constants.lookup(sym.as_symbol());
|
||||
if (global_constant) {
|
||||
throw_compiler_error(
|
||||
form, "Cannot define a symbol named {}, it already exists as a global constant (value {}).",
|
||||
sym.print(), global_constant->second.print());
|
||||
sym.print(), global_constant->print());
|
||||
}
|
||||
|
||||
auto fe = env->function_env();
|
||||
@ -66,16 +66,16 @@ Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest
|
||||
throw_compiler_error(form, "Cannot define {} because it cannot be set.", sym_val->print());
|
||||
}
|
||||
|
||||
auto existing_type = m_symbol_types.find(sym.as_symbol());
|
||||
if (existing_type == m_symbol_types.end()) {
|
||||
m_symbol_types[sym.as_symbol()] = in_gpr->type();
|
||||
auto existing_type = m_symbol_types.lookup(sym.as_symbol());
|
||||
if (!existing_type) {
|
||||
m_symbol_types.set(sym.as_symbol(), in_gpr->type());
|
||||
} else {
|
||||
bool do_typecheck = true;
|
||||
if (args.has_named("no-typecheck")) {
|
||||
do_typecheck = !get_true_or_false(form, args.named.at("no-typecheck"));
|
||||
}
|
||||
if (do_typecheck) {
|
||||
typecheck(form, existing_type->second, in_gpr->type(),
|
||||
typecheck(form, *existing_type, in_gpr->type(),
|
||||
fmt::format("define on existing symbol {}", sym.as_symbol().name_ptr));
|
||||
}
|
||||
}
|
||||
@ -107,27 +107,26 @@ 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(sym.as_symbol());
|
||||
auto existing_type = m_symbol_types.lookup(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 (existing_type && *existing_type != new_type) {
|
||||
if (m_allow_inconsistent_definition_symbols.find(symbol_string(sym)) ==
|
||||
m_allow_inconsistent_definition_symbols.end()) {
|
||||
// throw if we have throws enabled, and new definition is NOT just more generic
|
||||
// (that case is fine in goal)
|
||||
if (!m_ts.tc(new_type, existing_type->second) && m_throw_on_define_extern_redefinition) {
|
||||
if (!m_ts.tc(new_type, *existing_type) && m_throw_on_define_extern_redefinition) {
|
||||
throw_compiler_error(form,
|
||||
"define-extern would redefine the type of symbol {} from {} to {}.",
|
||||
symbol_string(sym), existing_type->second.print(), new_type.print());
|
||||
symbol_string(sym), existing_type->print(), new_type.print());
|
||||
} else {
|
||||
print_compiler_warning(
|
||||
"define-extern has redefined the type of symbol {}\npreviously: {}\nnow: {}\n",
|
||||
symbol_string(sym).c_str(), existing_type->second.print().c_str(),
|
||||
new_type.print().c_str());
|
||||
symbol_string(sym).c_str(), existing_type->print().c_str(), new_type.print().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_symbol_types[sym.as_symbol()] = new_type;
|
||||
m_symbol_types.set(sym.as_symbol(), new_type);
|
||||
m_symbol_info.add_fwd_dec(symbol_string(sym), form);
|
||||
return get_none();
|
||||
}
|
||||
|
@ -346,8 +346,7 @@ Val* Compiler::compile_function_or_method_call(const goos::Object& form, Env* en
|
||||
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(uneval_head.as_symbol()) != m_symbol_types.end()) {
|
||||
if (is_local_symbol(uneval_head, env) || m_symbol_types.lookup(uneval_head.as_symbol())) {
|
||||
// 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);
|
||||
|
@ -196,19 +196,19 @@ Val* Compiler::compile_define_constant(const goos::Object& form,
|
||||
|
||||
// GOAL constant
|
||||
if (goal) {
|
||||
if (m_symbol_types.find(sym) != m_symbol_types.end()) {
|
||||
if (m_symbol_types.lookup(sym)) {
|
||||
throw_compiler_error(form,
|
||||
"Cannot define {} as a constant because "
|
||||
"it is already the name of a symbol of type {}",
|
||||
sym.name_ptr, m_symbol_types.at(sym).print());
|
||||
sym.name_ptr, m_symbol_types.lookup(sym)->print());
|
||||
}
|
||||
|
||||
auto existing = m_global_constants.find(sym);
|
||||
if (existing != m_global_constants.end() && existing->second != value) {
|
||||
auto existing = m_global_constants.lookup(sym);
|
||||
if (existing && *existing != value) {
|
||||
print_compiler_warning("Constant {} has been redefined {} -> {}", sym.name_ptr,
|
||||
existing->second.print(), value.print());
|
||||
existing->print(), value.print());
|
||||
}
|
||||
m_global_constants[sym] = value;
|
||||
m_global_constants.set(sym, value);
|
||||
}
|
||||
|
||||
// GOOS constant
|
||||
|
@ -98,10 +98,10 @@ Val* Compiler::compile_define_state_hook(const goos::Object& form,
|
||||
}
|
||||
|
||||
auto& state_name = args.unnamed.at(0).as_symbol();
|
||||
auto existing_var = m_symbol_types.find(state_name);
|
||||
auto existing_var = m_symbol_types.lookup(state_name);
|
||||
|
||||
TypeSpec type_to_use;
|
||||
if (existing_var == m_symbol_types.end()) {
|
||||
if (!existing_var) {
|
||||
// we're a new state. we must have a type.
|
||||
if (!state_type) {
|
||||
throw_compiler_error(form,
|
||||
@ -110,11 +110,11 @@ Val* Compiler::compile_define_state_hook(const goos::Object& form,
|
||||
state_name.name_ptr);
|
||||
}
|
||||
type_to_use = *state_type;
|
||||
m_symbol_types[state_name] = *state_type;
|
||||
m_symbol_types.set(state_name, *state_type);
|
||||
} else {
|
||||
type_to_use = existing_var->second;
|
||||
type_to_use = *existing_var;
|
||||
if (state_type) {
|
||||
typecheck(form, existing_var->second, *state_type,
|
||||
typecheck(form, *existing_var, *state_type,
|
||||
fmt::format("type of state {}", state_name.name_ptr));
|
||||
}
|
||||
}
|
||||
|
@ -700,10 +700,10 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env
|
||||
}
|
||||
|
||||
// as a constant
|
||||
auto kv = m_global_constants.find(form.as_symbol());
|
||||
if (kv != m_global_constants.end()) {
|
||||
auto kv = m_global_constants.lookup(form.as_symbol());
|
||||
if (kv) {
|
||||
// expand constant and compile again.
|
||||
return compile_static(kv->second, env);
|
||||
return compile_static(*kv, env);
|
||||
} else {
|
||||
throw_compiler_error(form, "The symbol {} could not be evaluated at compile time",
|
||||
form.print());
|
||||
|
@ -386,33 +386,32 @@ 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(m_goos.intern_ptr(result.type.base_type()));
|
||||
if (kv != m_symbol_types.end() && kv->second.base_type() != "type") {
|
||||
auto kv = m_symbol_types.lookup(m_goos.intern_ptr(result.type.base_type()));
|
||||
if (kv && kv->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());
|
||||
kv->print());
|
||||
}
|
||||
// remember that this is a type
|
||||
m_symbol_types[m_goos.intern_ptr(result.type.base_type())] = m_ts.make_typespec("type");
|
||||
m_symbol_types.set(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 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) {
|
||||
auto existing_type = m_symbol_types.lookup(interned_state_first);
|
||||
if (existing_type && *existing_type != state.second) {
|
||||
if (m_throw_on_define_extern_redefinition) {
|
||||
throw_compiler_error(form, "deftype would redefine the type of state {} from {} to {}.",
|
||||
state.first, existing_type->second.print(), state.second.print());
|
||||
state.first, existing_type->print(), state.second.print());
|
||||
} else {
|
||||
print_compiler_warning(
|
||||
"[Warning] deftype has redefined the type of state {}\npreviously: {}\nnow: "
|
||||
"{}\n",
|
||||
state.first.c_str(), existing_type->second.print().c_str(),
|
||||
state.second.print().c_str());
|
||||
state.first.c_str(), existing_type->print().c_str(), state.second.print().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
m_symbol_types[interned_state_first] = state.second;
|
||||
m_symbol_types.set(interned_state_first, state.second);
|
||||
m_symbol_info.add_fwd_dec(state.first, form);
|
||||
}
|
||||
|
||||
@ -1444,12 +1443,12 @@ Val* Compiler::compile_declare_type(const goos::Object& form, const goos::Object
|
||||
|
||||
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")) {
|
||||
auto existing_type = m_symbol_types.lookup(type_name);
|
||||
if (existing_type && *existing_type != TypeSpec("type")) {
|
||||
throw_compiler_error(form, "Cannot forward declare {} as a type: it is already a {}",
|
||||
type_name.name_ptr, existing_type->second.print());
|
||||
type_name.name_ptr, existing_type->print());
|
||||
}
|
||||
m_symbol_types[type_name] = TypeSpec("type");
|
||||
m_symbol_types.set(type_name, TypeSpec("type"));
|
||||
|
||||
return get_none();
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ void SymbolInfoMap::add_builtin(const std::string& name, const std::string& docs
|
||||
void SymbolInfoMap::add_method(const std::string& method_name,
|
||||
const std::vector<GoalArg>& args,
|
||||
const MethodInfo& method_info,
|
||||
const goos::Object& defining_form) {
|
||||
const goos::Object& /*defining_form*/) {
|
||||
SymbolInfo info = {
|
||||
.m_kind = Kind::METHOD,
|
||||
.m_name = method_name,
|
||||
|
Loading…
Reference in New Issue
Block a user