mirror of
https://github.com/open-goal/jak-project
synced 2026-06-08 20:29:54 -04:00
Add enums and some cleanup (#148)
* support enums * better compiler warnings * tweaks to build with clang
This commit is contained in:
+5
-5
@@ -9,7 +9,7 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Set default compile flags for GCC
|
||||
# optimization level can be set here. Note that game/ overwrites this for building game C++ code.
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
if (UNIX)
|
||||
message(STATUS "GCC detected, adding compile flags")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} \
|
||||
@@ -17,10 +17,10 @@ if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
-Winit-self \
|
||||
-ggdb \
|
||||
-Wextra \
|
||||
-Wcast-align \
|
||||
-Wno-cast-align \
|
||||
-Wcast-qual \
|
||||
-Wdisabled-optimization \
|
||||
-Wformat=2 \
|
||||
-Wformat \
|
||||
-Wmissing-include-dirs \
|
||||
-Woverloaded-virtual \
|
||||
-Wredundant-decls \
|
||||
@@ -29,7 +29,7 @@ if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
else ()
|
||||
set(CMAKE_CXX_FLAGS "/EHsc")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10000000")
|
||||
endif (CMAKE_COMPILER_IS_GNUCXX)
|
||||
endif (UNIX)
|
||||
|
||||
IF (WIN32)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
@@ -41,7 +41,7 @@ ENDIF ()
|
||||
option(CODE_COVERAGE "Enable Code Coverage Compiler Flags" OFF)
|
||||
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/third-party/cmake/modules/)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX AND CODE_COVERAGE)
|
||||
if(UNIX AND CODE_COVERAGE)
|
||||
include(CodeCoverage)
|
||||
append_coverage_compiler_flags()
|
||||
message("Code Coverage build is enabled!")
|
||||
|
||||
@@ -27,6 +27,7 @@ class IR {
|
||||
virtual TP_Type get_expression_type(const TypeState& input,
|
||||
const LinkedObjectFile& file,
|
||||
DecompilerTypeSystem& dts);
|
||||
virtual ~IR() = default;
|
||||
};
|
||||
|
||||
class IR_Atomic : public virtual IR {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
class ObjectFileData;
|
||||
struct ObjectFileData;
|
||||
|
||||
struct TPageResultStats {
|
||||
int total_textures = 0;
|
||||
|
||||
+8
-8
@@ -3,18 +3,18 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Set default compile flags for GCC
|
||||
# optimization level can be set here. Note that game/ overwrites this for building game C++ code.
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if(UNIX)
|
||||
message(STATUS "GCC detected, adding compile flags")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} \
|
||||
-ggdb \
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} \
|
||||
-Wall \
|
||||
-Winit-self \
|
||||
-Winit-self \
|
||||
-ggdb \
|
||||
-Wextra \
|
||||
-Wcast-align \
|
||||
-Wno-cast-align \
|
||||
-Wcast-qual \
|
||||
-Wdisabled-optimization \
|
||||
-Wformat=2 \
|
||||
-Wformat \
|
||||
-Wmissing-include-dirs \
|
||||
-Woverloaded-virtual \
|
||||
-Wredundant-decls \
|
||||
@@ -22,7 +22,7 @@ if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
-Wsign-promo")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "/EHsc")
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
endif(UNIX)
|
||||
|
||||
enable_language(ASM_NASM)
|
||||
set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} asm)
|
||||
|
||||
@@ -49,8 +49,6 @@ class SystemThread {
|
||||
Timer stats_timer;
|
||||
Timer stat_diff_timer;
|
||||
double cpu_user = 0, cpu_kernel = 0;
|
||||
uint64_t last_cpu_user = 0, last_cpu_kernel = 0;
|
||||
uint64_t last_collection_nanoseconds = 0;
|
||||
int id = -1;
|
||||
bool want_exit = false;
|
||||
bool running = false;
|
||||
|
||||
@@ -54,8 +54,38 @@
|
||||
;; ENUMS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
; todo, processs mask
|
||||
; bitfield enum to indicate proprties about a process-tree
|
||||
(defenum process-mask :bitfield #t :type int32
|
||||
(execute 0) ; 1
|
||||
(draw 1) ; 2
|
||||
(pause 2) ; 4
|
||||
(menu 3) ; 8
|
||||
(progress 4) ; 16
|
||||
(actor-pause 5) ; 32
|
||||
(sleep 6) ; 64
|
||||
(sleep-code 7) ; 128
|
||||
(process-tree 8) ; 256 ; not an actual process, just a "tree node" for organization
|
||||
(heap-shrunk 9) ; 512
|
||||
(going 10) ; 1024
|
||||
(movie 11) ; 2048
|
||||
(movie-subject 12) ; 4096
|
||||
(target 13) ; 8192
|
||||
(sidekick 14) ; 16384
|
||||
(crate 15) ; 32768
|
||||
(collectable 16) ; 65536
|
||||
(enemy 17) ; 131072
|
||||
(camera 18) ; 262144
|
||||
(platform 19) ; 524288
|
||||
(ambient 20) ; 1048576
|
||||
(entity 21) ; 2097152
|
||||
(projectile 22) ; 4194304
|
||||
(attackable 23) ; 8388608
|
||||
(death 24) ; 16777216
|
||||
)
|
||||
|
||||
;; -961
|
||||
(defconstant PROCESS_CLEAR_MASK
|
||||
(lognot (process-mask sleep sleep-code process-tree heap-shrunk)))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; MACROS
|
||||
|
||||
@@ -29,7 +29,6 @@ add_library(compiler
|
||||
data_compiler/game_count.cpp
|
||||
debugger/Debugger.cpp
|
||||
debugger/DebugInfo.cpp
|
||||
logger/Logger.cpp
|
||||
listener/Listener.cpp
|
||||
listener/MemoryMap.cpp
|
||||
regalloc/IRegister.cpp
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "Compiler.h"
|
||||
#include "goalc/logger/Logger.h"
|
||||
#include "common/link_types.h"
|
||||
#include "IR.h"
|
||||
#include "goalc/regalloc/allocate.h"
|
||||
@@ -11,8 +10,6 @@
|
||||
using namespace goos;
|
||||
|
||||
Compiler::Compiler() : m_debugger(&m_listener) {
|
||||
init_logger();
|
||||
init_settings();
|
||||
m_listener.add_debugger(&m_debugger);
|
||||
m_ts.add_builtin_types();
|
||||
m_global_env = std::make_unique<GlobalEnv>();
|
||||
@@ -61,36 +58,19 @@ void Compiler::execute_repl() {
|
||||
if (m_listener.is_connected()) {
|
||||
m_listener.send_code(data);
|
||||
if (!m_listener.most_recent_send_was_acked()) {
|
||||
gLogger.log(MSG_ERR, "Runtime is not responding. Did it crash?\n");
|
||||
print_compiler_warning("Runtime is not responding. Did it crash?\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (std::exception& e) {
|
||||
gLogger.log(MSG_WARN, "REPL Error: %s\n", e.what());
|
||||
print_compiler_warning("REPL Error: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
m_listener.disconnect();
|
||||
}
|
||||
|
||||
Compiler::~Compiler() {
|
||||
gLogger.close();
|
||||
}
|
||||
|
||||
void Compiler::init_logger() {
|
||||
gLogger.set_file("compiler.txt"); // todo, a better file than this...
|
||||
gLogger.config[MSG_COLOR].kind = LOG_FILE;
|
||||
gLogger.config[MSG_DEBUG].kind = LOG_IGNORE;
|
||||
gLogger.config[MSG_TGT].color = COLOR_GREEN;
|
||||
gLogger.config[MSG_TGT_INFO].color = COLOR_BLUE;
|
||||
gLogger.config[MSG_WARN].color = COLOR_RED;
|
||||
gLogger.config[MSG_ICE].color = COLOR_RED;
|
||||
gLogger.config[MSG_ERR].color = COLOR_RED;
|
||||
}
|
||||
|
||||
void Compiler::init_settings() {}
|
||||
|
||||
FileEnv* Compiler::compile_object_file(const std::string& name,
|
||||
goos::Object code,
|
||||
bool allow_emit) {
|
||||
@@ -169,11 +149,6 @@ Val* Compiler::compile_error_guard(const goos::Object& code, Env* env) {
|
||||
}
|
||||
}
|
||||
|
||||
void Compiler::ice(const std::string& error) {
|
||||
gLogger.log(MSG_ICE, "[ICE] %s\n", error.c_str());
|
||||
throw std::runtime_error("ICE");
|
||||
}
|
||||
|
||||
void Compiler::color_object_file(FileEnv* env) {
|
||||
for (auto& f : env->functions()) {
|
||||
AllocationInput input;
|
||||
@@ -232,7 +207,7 @@ std::vector<std::string> Compiler::run_test_from_file(const std::string& source_
|
||||
m_listener.record_messages(ListenerMessageKind::MSG_PRINT);
|
||||
m_listener.send_code(data);
|
||||
if (!m_listener.most_recent_send_was_acked()) {
|
||||
gLogger.log(MSG_ERR, "Runtime is not responding after sending test code. Did it crash?\n");
|
||||
print_compiler_warning("Runtime is not responding after sending test code. Did it crash?\n");
|
||||
}
|
||||
return m_listener.stop_recording_messages();
|
||||
} catch (std::exception& e) {
|
||||
@@ -258,7 +233,7 @@ std::vector<std::string> Compiler::run_test_from_string(const std::string& src,
|
||||
m_listener.record_messages(ListenerMessageKind::MSG_PRINT);
|
||||
m_listener.send_code(data);
|
||||
if (!m_listener.most_recent_send_was_acked()) {
|
||||
gLogger.log(MSG_ERR, "Runtime is not responding after sending test code. Did it crash?\n");
|
||||
print_compiler_warning("Runtime is not responding after sending test code. Did it crash?\n");
|
||||
}
|
||||
return m_listener.stop_recording_messages();
|
||||
} catch (std::exception& e) {
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "third-party/fmt/color.h"
|
||||
#include "CompilerException.h"
|
||||
#include "Enum.h"
|
||||
|
||||
enum MathMode { MATH_INT, MATH_BINT, MATH_FLOAT, MATH_INVALID };
|
||||
|
||||
class Compiler {
|
||||
public:
|
||||
Compiler();
|
||||
~Compiler();
|
||||
void execute_repl();
|
||||
goos::Interpreter& get_goos() { return m_goos; }
|
||||
FileEnv* compile_object_file(const std::string& name, goos::Object code, bool allow_emit);
|
||||
@@ -30,9 +30,7 @@ class Compiler {
|
||||
Env* env);
|
||||
Val* compile(const goos::Object& code, Env* env);
|
||||
Val* compile_error_guard(const goos::Object& code, Env* env);
|
||||
void ice(const std::string& err);
|
||||
None* get_none() { return m_none.get(); }
|
||||
|
||||
std::vector<std::string> run_test_from_file(const std::string& source_code);
|
||||
std::vector<std::string> run_test_from_string(const std::string& src,
|
||||
const std::string& obj_name = "*listener*");
|
||||
@@ -42,14 +40,10 @@ class Compiler {
|
||||
void enable_throw_on_redefines() { m_throw_on_define_extern_redefinition = true; }
|
||||
Debugger& get_debugger() { return m_debugger; }
|
||||
listener::Listener& listener() { return m_listener; }
|
||||
|
||||
void poke_target() { m_listener.send_poke(); }
|
||||
|
||||
bool connect_to_target();
|
||||
|
||||
private:
|
||||
void init_logger();
|
||||
void init_settings();
|
||||
bool try_getting_macro_from_goos(const goos::Object& macro_name, goos::Object* dest);
|
||||
void set_bitfield(const goos::Object& form, BitFieldVal* dst, RegVal* src, Env* env);
|
||||
Val* do_set(const goos::Object& form, Val* dst, RegVal* src, Env* env);
|
||||
@@ -125,6 +119,7 @@ class Compiler {
|
||||
Debugger m_debugger;
|
||||
goos::Interpreter m_goos;
|
||||
std::unordered_map<std::string, TypeSpec> m_symbol_types;
|
||||
std::unordered_map<std::string, GoalEnum> m_enums;
|
||||
std::unordered_map<std::shared_ptr<goos::SymbolObject>, goos::Object> m_global_constants;
|
||||
std::unordered_map<std::shared_ptr<goos::SymbolObject>, LambdaVal*> m_inlineable_functions;
|
||||
CompilerSettings m_settings;
|
||||
@@ -140,6 +135,10 @@ class Compiler {
|
||||
Val* number_to_binteger(const goos::Object& form, Val* in, Env* env);
|
||||
Val* to_math_type(const goos::Object& form, Val* in, MathMode mode, Env* env);
|
||||
bool is_none(Val* in);
|
||||
Val* compile_enum_lookup(const goos::Object& form,
|
||||
const GoalEnum& e,
|
||||
const goos::Object& rest,
|
||||
Env* env);
|
||||
|
||||
Val* compile_variable_shift(const goos::Object& form,
|
||||
const RegVal* in,
|
||||
@@ -200,6 +199,16 @@ class Compiler {
|
||||
throw CompilerException("Compilation Error");
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void print_compiler_warning(const std::string& str, Args&&... args) {
|
||||
fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "[Warning] ");
|
||||
if (!str.empty() && str.back() == '\n') {
|
||||
fmt::print(str, std::forward<Args>(args)...);
|
||||
} else {
|
||||
fmt::print(str + '\n', std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// Atoms
|
||||
|
||||
@@ -295,6 +304,7 @@ class Compiler {
|
||||
Val* compile_addr_of(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_declare_type(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_none(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_defenum(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
};
|
||||
|
||||
#endif // JAK_COMPILER_H
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include "common/common_types.h"
|
||||
#include "common/type_system/TypeSpec.h"
|
||||
|
||||
struct GoalEnum {
|
||||
TypeSpec base_type;
|
||||
bool is_bitfield = false;
|
||||
std::unordered_map<std::string, s64> entries;
|
||||
|
||||
bool operator==(const GoalEnum& other) const;
|
||||
bool operator!=(const GoalEnum& other) const;
|
||||
};
|
||||
@@ -20,6 +20,7 @@ class IR {
|
||||
(void)constraints;
|
||||
(void)my_id;
|
||||
}
|
||||
virtual ~IR() = default;
|
||||
};
|
||||
|
||||
// class IR_Set : public IR {
|
||||
|
||||
@@ -21,6 +21,7 @@ class StaticObject {
|
||||
virtual LoadInfo get_load_info() const = 0;
|
||||
virtual void generate(emitter::ObjectGenerator* gen) = 0;
|
||||
virtual int get_addr_offset() const = 0;
|
||||
virtual ~StaticObject() = default;
|
||||
|
||||
emitter::StaticRecord rec;
|
||||
};
|
||||
|
||||
@@ -45,6 +45,7 @@ class Val {
|
||||
void set_type(TypeSpec ts) { m_ts = std::move(ts); }
|
||||
bool settable() const { return m_is_settable; }
|
||||
void mark_as_settable() { m_is_settable = true; }
|
||||
virtual ~Val() = default;
|
||||
|
||||
protected:
|
||||
TypeSpec m_ts;
|
||||
|
||||
@@ -68,7 +68,7 @@ static const std::unordered_map<
|
||||
// TYPE
|
||||
{"deftype", &Compiler::compile_deftype},
|
||||
{"defmethod", &Compiler::compile_defmethod},
|
||||
// {"defenum", &Compiler::compile_defenum},
|
||||
{"defenum", &Compiler::compile_defenum},
|
||||
{"->", &Compiler::compile_deref},
|
||||
{"&", &Compiler::compile_addr_of},
|
||||
{"the-as", &Compiler::compile_the_as},
|
||||
@@ -152,7 +152,7 @@ Val* Compiler::compile(const goos::Object& code, Env* env) {
|
||||
case goos::ObjectType::FLOAT:
|
||||
return compile_float(code, env);
|
||||
default:
|
||||
ice("Don't know how to compile " + code.print());
|
||||
throw_compiler_error(code, "Cannot compile {}.", code.print());
|
||||
}
|
||||
return get_none();
|
||||
}
|
||||
@@ -161,7 +161,6 @@ Val* Compiler::compile(const goos::Object& code, Env* env) {
|
||||
* Compile a pair/list.
|
||||
* Can be a compiler form, function call (possibly inlined), method call, immediate application of a
|
||||
* lambda, or a goos macro.
|
||||
* TODO - enums.
|
||||
*/
|
||||
Val* Compiler::compile_pair(const goos::Object& code, Env* env) {
|
||||
auto pair = code.as_pair();
|
||||
@@ -182,7 +181,10 @@ Val* Compiler::compile_pair(const goos::Object& code, Env* env) {
|
||||
return compile_goos_macro(code, macro_obj, rest, env);
|
||||
}
|
||||
|
||||
// try as an enum (not yet implemented)
|
||||
auto enum_kv = m_enums.find(head_sym->name);
|
||||
if (enum_kv != m_enums.end()) {
|
||||
return compile_enum_lookup(code, enum_kv->second, rest, env);
|
||||
}
|
||||
}
|
||||
|
||||
// if none of the above cases worked, then treat it like a function/method call.
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
|
||||
#include "goalc/compiler/Compiler.h"
|
||||
#include "goalc/logger/Logger.h"
|
||||
|
||||
/*!
|
||||
* Define or set a global value. Has some special magic to store data for functions which may be
|
||||
@@ -73,10 +72,8 @@ Val* Compiler::compile_define_extern(const goos::Object& form, const goos::Objec
|
||||
"define-extern would redefine the type of symbol {} from {} to {}.",
|
||||
symbol_string(sym), existing_type->second.print(), new_type.print());
|
||||
} else {
|
||||
// todo nicer warning message.
|
||||
gLogger.log(
|
||||
MSG_WARN,
|
||||
"[Warning] define-extern has redefined the type of symbol %s\npreviously: %s\nnow: %s\n",
|
||||
print_compiler_warning(
|
||||
"[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());
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
|
||||
#include "goalc/compiler/Compiler.h"
|
||||
#include "goalc/logger/Logger.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "goalc/compiler/Compiler.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "common/type_system/deftype.h"
|
||||
#include "goalc/compiler/Enum.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -785,4 +786,124 @@ Val* Compiler::compile_none(const goos::Object& form, const goos::Object& rest,
|
||||
auto args = get_va(form, rest);
|
||||
va_check(form, args, {}, {});
|
||||
return get_none();
|
||||
}
|
||||
|
||||
Val* Compiler::compile_defenum(const goos::Object& form, const goos::Object& _rest, Env* env) {
|
||||
// format is (defenum name [options] [entries])
|
||||
(void)env;
|
||||
auto* rest = &_rest;
|
||||
|
||||
// name
|
||||
auto enum_name = symbol_string(pair_car(*rest));
|
||||
rest = &pair_cdr(*rest);
|
||||
|
||||
// default enum type will be int32.
|
||||
auto enum_type = m_ts.make_typespec("int32");
|
||||
bool is_bitfield = false;
|
||||
|
||||
auto current = pair_car(*rest);
|
||||
while (current.is_symbol() && symbol_string(current).at(0) == ':') {
|
||||
auto option_name = symbol_string(current);
|
||||
rest = &pair_cdr(*rest);
|
||||
auto option_value = pair_car(*rest);
|
||||
rest = &pair_cdr(*rest);
|
||||
current = pair_car(*rest);
|
||||
|
||||
if (option_name == ":type") {
|
||||
enum_type = parse_typespec(option_value);
|
||||
} else if (option_name == ":bitfield") {
|
||||
if (symbol_string(option_value) == "#t") {
|
||||
is_bitfield = true;
|
||||
} else if (symbol_string(option_value) == "#f") {
|
||||
is_bitfield = false;
|
||||
} else {
|
||||
throw_compiler_error(form, "Invalid option {} to :bitfield option.", option_value.print());
|
||||
}
|
||||
} else {
|
||||
throw_compiler_error(form, "Unknown option {} for defenum.", option_name);
|
||||
}
|
||||
}
|
||||
|
||||
GoalEnum new_enum;
|
||||
new_enum.base_type = enum_type;
|
||||
new_enum.is_bitfield = is_bitfield;
|
||||
|
||||
while (!rest->is_empty_list()) {
|
||||
auto def = pair_car(*rest);
|
||||
auto name = symbol_string(pair_car(def));
|
||||
def = pair_cdr(def);
|
||||
auto value = pair_car(def);
|
||||
if (!value.is_int()) {
|
||||
throw_compiler_error(def, "Expected integer for enum value, got {}", value.print());
|
||||
}
|
||||
|
||||
def = pair_cdr(def);
|
||||
if (!def.is_empty_list()) {
|
||||
throw_compiler_error(def, "Got too many items in defenum defintion.");
|
||||
}
|
||||
|
||||
new_enum.entries[name] = value.integer_obj.value;
|
||||
rest = &pair_cdr(*rest);
|
||||
}
|
||||
|
||||
auto existing_kv = m_enums.find(enum_name);
|
||||
if (existing_kv != m_enums.end() && existing_kv->second != new_enum) {
|
||||
print_compiler_warning("defenum changes the definition of existing enum {}", enum_name.c_str());
|
||||
}
|
||||
m_enums[enum_name] = new_enum;
|
||||
|
||||
return get_none();
|
||||
}
|
||||
|
||||
Val* Compiler::compile_enum_lookup(const goos::Object& form,
|
||||
const GoalEnum& e,
|
||||
const goos::Object& rest,
|
||||
Env* env) {
|
||||
if (e.is_bitfield) {
|
||||
int64_t value = 0;
|
||||
for_each_in_list(rest, [&](const goos::Object& o) {
|
||||
auto kv = e.entries.find(symbol_string(o));
|
||||
if (kv == e.entries.end()) {
|
||||
throw_compiler_error(form, "The value {} was not found in enum.", o.print());
|
||||
}
|
||||
value |= (1 << kv->second);
|
||||
});
|
||||
|
||||
auto result = compile_integer(value, env);
|
||||
result->set_type(e.base_type);
|
||||
return result;
|
||||
} else {
|
||||
int64_t value = 0;
|
||||
bool got = false;
|
||||
for_each_in_list(rest, [&](const goos::Object& o) {
|
||||
if (got) {
|
||||
throw_compiler_error(form, "Invalid enum lookup.");
|
||||
}
|
||||
auto kv = e.entries.find(symbol_string(o));
|
||||
if (kv == e.entries.end()) {
|
||||
throw_compiler_error(form, "The value {} was not found in enum.", o.print());
|
||||
}
|
||||
value = kv->second;
|
||||
got = true;
|
||||
});
|
||||
|
||||
if (!got) {
|
||||
throw_compiler_error(form, "Invalid enum lookup.");
|
||||
}
|
||||
|
||||
auto result = compile_integer(value, env);
|
||||
result->set_type(e.base_type);
|
||||
return result;
|
||||
}
|
||||
|
||||
return get_none();
|
||||
}
|
||||
|
||||
bool GoalEnum::operator==(const GoalEnum& other) const {
|
||||
return base_type == other.base_type && is_bitfield == other.is_bitfield &&
|
||||
entries == other.entries;
|
||||
}
|
||||
|
||||
bool GoalEnum::operator!=(const GoalEnum& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
#include <stdexcept>
|
||||
#include "Logger.h"
|
||||
|
||||
void Logger::close() {
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
fp = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::set_file(std::string filename) {
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
fp = fopen(filename.c_str(), "w");
|
||||
if (!fp) {
|
||||
throw std::runtime_error("invalid file name " + filename + " in logger");
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::log(LoggerMessageKind kind, const char* format, ...) {
|
||||
FILE* dest = nullptr;
|
||||
auto& settings = config[kind];
|
||||
switch (settings.kind) {
|
||||
case LOG_STDERR:
|
||||
dest = stderr;
|
||||
break;
|
||||
case LOG_STDOUT:
|
||||
dest = stdout;
|
||||
break;
|
||||
case LOG_IGNORE:
|
||||
dest = nullptr;
|
||||
break;
|
||||
case LOG_FILE:
|
||||
dest = fp;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("unknown log destination in log");
|
||||
}
|
||||
|
||||
if (!dest)
|
||||
return;
|
||||
|
||||
if (!settings.prefix.empty()) {
|
||||
fprintf(dest, "%s", settings.prefix.c_str());
|
||||
}
|
||||
|
||||
if (settings.color != COLOR_NORMAL) {
|
||||
const char* color_codes[] = {"", "[0;31m", "[0;32m", "[0;36m"};
|
||||
printf("\033%s", color_codes[settings.color]);
|
||||
}
|
||||
|
||||
va_list arglist;
|
||||
va_start(arglist, format);
|
||||
vfprintf(dest, format, arglist);
|
||||
va_end(arglist);
|
||||
|
||||
if (settings.color != COLOR_NORMAL) {
|
||||
printf("\033[0m");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
// todo, does this make things slow?
|
||||
if (settings.kind == LOG_FILE) {
|
||||
fflush(fp);
|
||||
}
|
||||
}
|
||||
|
||||
Logger gLogger;
|
||||
@@ -1,45 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef JAK_LOGGER_H
|
||||
#define JAK_LOGGER_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdarg>
|
||||
#include <unordered_map>
|
||||
|
||||
enum LoggerColor { COLOR_NORMAL, COLOR_RED, COLOR_GREEN, COLOR_BLUE };
|
||||
|
||||
enum LoggerDestKind { LOG_STDOUT, LOG_STDERR, LOG_FILE, LOG_IGNORE };
|
||||
|
||||
struct LoggerDest {
|
||||
LoggerDestKind kind = LOG_STDOUT;
|
||||
LoggerColor color = COLOR_NORMAL;
|
||||
std::string prefix;
|
||||
};
|
||||
|
||||
enum LoggerMessageKind {
|
||||
MSG_GOAL,
|
||||
MSG_ICE,
|
||||
MSG_ERR,
|
||||
MSG_COLOR,
|
||||
MSG_EMIT,
|
||||
MSG_DEBUG,
|
||||
MSG_WARN,
|
||||
MSG_TGT,
|
||||
MSG_TGT_INFO,
|
||||
};
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
void set_file(std::string filename);
|
||||
void log(LoggerMessageKind kind, const char* format, ...);
|
||||
std::unordered_map<LoggerMessageKind, LoggerDest> config;
|
||||
void close();
|
||||
|
||||
private:
|
||||
FILE* fp = nullptr;
|
||||
};
|
||||
|
||||
extern Logger gLogger;
|
||||
|
||||
#endif // JAK_LOGGER_H
|
||||
+1
-1
@@ -30,7 +30,7 @@ ELSE()
|
||||
target_link_libraries(goalc-test cross_sockets goos common_util runtime compiler type_system gtest Zydis)
|
||||
ENDIF()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX AND CODE_COVERAGE)
|
||||
if(UNIX AND CODE_COVERAGE)
|
||||
include(CodeCoverage)
|
||||
append_coverage_compiler_flags()
|
||||
setup_target_for_coverage_lcov(NAME goalc-test_coverage
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
(defenum test-bitfield :bitfield #t
|
||||
(four 2)
|
||||
(one 0)
|
||||
(two 1)
|
||||
)
|
||||
|
||||
(deftype type-with-bitfield (basic)
|
||||
((name basic)
|
||||
(thing int32)
|
||||
)
|
||||
)
|
||||
|
||||
(let ((obj (new 'global 'type-with-bitfield)))
|
||||
(set! (-> obj thing) (test-bitfield one four))
|
||||
(the uint (-> obj thing))
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
(defenum test-int-enum :bitfield #f
|
||||
(four 4)
|
||||
(one 1)
|
||||
(seven 7)
|
||||
(two 2)
|
||||
)
|
||||
|
||||
(deftype type-with-bitfield2 (basic)
|
||||
((name basic)
|
||||
(thing1 int32)
|
||||
(thing2 int32)
|
||||
)
|
||||
)
|
||||
|
||||
(let ((obj (new 'global 'type-with-bitfield2)))
|
||||
(set! (-> obj thing1) (test-int-enum four))
|
||||
(set! (-> obj thing2) (test-int-enum seven))
|
||||
(+ (-> obj thing1) (-> obj thing2))
|
||||
)
|
||||
@@ -72,4 +72,9 @@ TEST_F(VariableTests, Let) {
|
||||
TEST_F(VariableTests, StackVars) {
|
||||
runner.run_static_test(env, testCategory, "stack-ints.gc", {"12\n"});
|
||||
runner.run_static_test(env, testCategory, "stack-ints-2.gc", {"1\n"});
|
||||
}
|
||||
|
||||
TEST_F(VariableTests, Bitfields) {
|
||||
runner.run_static_test(env, testCategory, "bitfield-enums.gc", {"5\n"});
|
||||
runner.run_static_test(env, testCategory, "integer-enums.gc", {"11\n"});
|
||||
}
|
||||
Vendored
+2
-2
@@ -1,8 +1,8 @@
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
if (UNIX)
|
||||
set(CMAKE_CXX_FLAGS "-O3")
|
||||
else ()
|
||||
set(CMAKE_CXX_FLAGS "/EHsc")
|
||||
endif (CMAKE_COMPILER_IS_GNUCXX)
|
||||
endif (UNIX)
|
||||
|
||||
include_directories(../)
|
||||
add_library(fmt SHARED format.cc)
|
||||
Reference in New Issue
Block a user