mirror of
https://github.com/open-goal/jak-project
synced 2026-08-11 11:33:51 -04:00
[Compiler] Add get-info (#306)
* wip symbol info * finish implementation
This commit is contained in:
+17
-2
@@ -108,7 +108,7 @@ void TextDb::link(const Object& o, std::shared_ptr<SourceText> frag, int offset)
|
||||
/*!
|
||||
* Given an object, get a string representing where it's from. Or "?" if we can't find it.
|
||||
*/
|
||||
std::string TextDb::get_info_for(const Object& o, bool* terminate_compiler_error) {
|
||||
std::string TextDb::get_info_for(const Object& o, bool* terminate_compiler_error) const {
|
||||
if (o.is_pair()) {
|
||||
auto kv = map.find(o.heap_obj);
|
||||
if (kv != map.end()) {
|
||||
@@ -133,10 +133,25 @@ std::string TextDb::get_info_for(const Object& o, bool* terminate_compiler_error
|
||||
/*!
|
||||
* Given a source text and an offset, print a description of where it is.
|
||||
*/
|
||||
std::string TextDb::get_info_for(const std::shared_ptr<SourceText>& frag, int offset) {
|
||||
std::string TextDb::get_info_for(const std::shared_ptr<SourceText>& frag, int offset) const {
|
||||
std::string result = "text from " + frag->get_description() +
|
||||
", line: " + std::to_string(frag->get_line_idx(offset) + 1) + "\n";
|
||||
result += frag->get_line_containing_offset(offset) + "\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Make child have the same location in the source as parent. For example, if parent generates
|
||||
* code that we want to be associated with the parent's location in source.
|
||||
*
|
||||
* Note: this only has an effect if both parent and child are pair/list. Otherwise it does nothing.
|
||||
*/
|
||||
void TextDb::inherit_info(const Object& parent, const Object& child) {
|
||||
if (parent.is_pair() && child.is_pair()) {
|
||||
auto parent_kv = map.find(parent.heap_obj);
|
||||
if (parent_kv != map.end()) {
|
||||
map[child.heap_obj] = parent_kv->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace goos
|
||||
|
||||
@@ -91,8 +91,9 @@ class TextDb {
|
||||
public:
|
||||
void insert(const std::shared_ptr<SourceText>& frag);
|
||||
void link(const Object& o, std::shared_ptr<SourceText> frag, int offset);
|
||||
std::string get_info_for(const Object& o, bool* terminate_compiler_error = nullptr);
|
||||
std::string get_info_for(const std::shared_ptr<SourceText>& frag, int offset);
|
||||
std::string get_info_for(const Object& o, bool* terminate_compiler_error = nullptr) const;
|
||||
std::string get_info_for(const std::shared_ptr<SourceText>& frag, int offset) const;
|
||||
void inherit_info(const Object& parent, const Object& child);
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<SourceText>> fragments;
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
/*!
|
||||
* A simple prefix tree. It works similarly to a map, but also supports fast lookups by prefix with
|
||||
* the ability to lookup all entries with keys that begin with a given prefix.
|
||||
*
|
||||
* It owns the memory for the objects it stores.
|
||||
* Doing an insert will create a copy of your object.
|
||||
*
|
||||
* Other that deleting the whole thing, there is no support for removing a node.
|
||||
*/
|
||||
template <typename T>
|
||||
class Trie {
|
||||
public:
|
||||
Trie() = default;
|
||||
Trie(const Trie&) = delete;
|
||||
Trie& operator=(const Trie&) = delete;
|
||||
|
||||
// Insert an object, replacing an existing one if it exists
|
||||
void insert(const std::string& str, const T& obj);
|
||||
|
||||
// Get the object at the string. Default construct a new one if none exists.
|
||||
T* operator[](const std::string& str);
|
||||
|
||||
// Lookup an existing object. If none exists, return nullptr.
|
||||
T* lookup(const std::string& str);
|
||||
|
||||
// return the number of entries.
|
||||
int size() const { return m_size; }
|
||||
|
||||
// Get all objects starting with the given prefix.
|
||||
std::vector<T*> lookup_prefix(const std::string& str);
|
||||
~Trie();
|
||||
|
||||
private:
|
||||
static constexpr int CHAR_START = ' ';
|
||||
static constexpr int CHAR_END = '~' + 1;
|
||||
static constexpr int CHAR_SIZE = CHAR_END - CHAR_START;
|
||||
|
||||
static int idx(char c) {
|
||||
assert(c >= CHAR_START);
|
||||
assert(c < CHAR_END);
|
||||
return c - CHAR_START;
|
||||
}
|
||||
|
||||
struct Node {
|
||||
T* value = nullptr;
|
||||
Node* children[CHAR_SIZE] = {0};
|
||||
|
||||
void delete_children() {
|
||||
if (value) {
|
||||
delete value;
|
||||
value = nullptr;
|
||||
}
|
||||
for (auto child : children) {
|
||||
if (child) {
|
||||
child->delete_children();
|
||||
delete child;
|
||||
child = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Return true if a new object was inserted.
|
||||
*/
|
||||
bool insert(const char* str, const T* obj) {
|
||||
if (!*str) {
|
||||
// we are the child!
|
||||
if (value) {
|
||||
delete value;
|
||||
value = new T(*obj);
|
||||
return false; // didn't change the count.
|
||||
} else {
|
||||
value = new T(*obj);
|
||||
return true; // did change the count
|
||||
}
|
||||
|
||||
} else {
|
||||
// still more to go
|
||||
char first = *str;
|
||||
if (!children[idx(first)]) {
|
||||
children[idx(first)] = new Node();
|
||||
}
|
||||
return children[idx(first)]->insert(str + 1, obj);
|
||||
}
|
||||
}
|
||||
|
||||
T* bracket_operator(const char* str, bool* inserted) {
|
||||
if (!*str) {
|
||||
// we are the child!
|
||||
if (!value) {
|
||||
value = new T();
|
||||
*inserted = true;
|
||||
} else {
|
||||
*inserted = false;
|
||||
}
|
||||
|
||||
return value;
|
||||
} else {
|
||||
// still more to go
|
||||
char first = *str;
|
||||
if (!children[idx(first)]) {
|
||||
children[idx(first)] = new Node();
|
||||
}
|
||||
return children[idx(first)]->bracket_operator(str + 1, inserted);
|
||||
}
|
||||
}
|
||||
|
||||
T* lookup(const char* str) {
|
||||
if (!*str) {
|
||||
return value;
|
||||
}
|
||||
if (children[idx(*str)]) {
|
||||
return children[idx(*str)]->lookup(str + 1);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void get_all_children(std::vector<T*>& result) {
|
||||
if (value) {
|
||||
result.push_back(value);
|
||||
}
|
||||
for (auto child : children) {
|
||||
if (child) {
|
||||
child->get_all_children(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<T*> lookup_prefix(const char* str) {
|
||||
if (!*str) {
|
||||
std::vector<T*> result;
|
||||
get_all_children(result);
|
||||
return result;
|
||||
} else {
|
||||
if (children[idx(*str)]) {
|
||||
return children[idx(*str)]->lookup_prefix(str + 1);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Node m_root;
|
||||
int m_size = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
Trie<T>::~Trie<T>() {
|
||||
m_root.delete_children();
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Trie<T>::insert(const std::string& str, const T& obj) {
|
||||
if (m_root.insert(str.c_str(), &obj)) {
|
||||
m_size++;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* Trie<T>::lookup(const std::string& str) {
|
||||
return m_root.lookup(str.c_str());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* Trie<T>::operator[](const std::string& str) {
|
||||
bool added = false;
|
||||
auto result = m_root.bracket_operator(str.c_str(), &added);
|
||||
if (added) {
|
||||
m_size++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T*> Trie<T>::lookup_prefix(const std::string& str) {
|
||||
return m_root.lookup_prefix(str.c_str());
|
||||
}
|
||||
+3
-1
@@ -116,4 +116,6 @@
|
||||
|
||||
## V0.6
|
||||
- There is no longer a separate compiler form for variable vs. constant shifts. Instead the compiler will pick the constant shift automatically when possible. The shifts are called `sar`, `shl` and `shr`, like the x86 instructions.
|
||||
- Static type reference link data now has the correct number of methods. This prevents errors like `dkernel: trying to redefine a type 'game-info' with 29 methods when it had 12, try restarting` when you did not actually redefine the number of methods.
|
||||
- Static type reference link data now has the correct number of methods. This prevents errors like `dkernel: trying to redefine a type 'game-info' with 29 methods when it had 12, try restarting` when you did not actually redefine the number of methods.
|
||||
- Added `get-info` to figure out what something is and where it's defined.
|
||||
- Added `autocomplete` to get auto-completions for a prefix.
|
||||
@@ -625,6 +625,72 @@ Reload the GOAL compiler
|
||||
```
|
||||
Disconnect from the target and reset all compiler state. This is equivalent to exiting the compiler and opening it again.
|
||||
|
||||
## `get-info`
|
||||
Get information about something.
|
||||
```lisp
|
||||
(get-info <something>)
|
||||
```
|
||||
Use `get-info` to see what something is and where it is defined.
|
||||
|
||||
For example:
|
||||
```lisp
|
||||
;; get info about a global variable:
|
||||
g > (get-info *kernel-context*)
|
||||
[Global Variable] Type: kernel-context Defined: text from goal_src/kernel/gkernel.gc, line: 88
|
||||
(define *kernel-context* (new 'static 'kernel-context
|
||||
|
||||
;; get info about a function. This particular function is forward declared, so there's an entry for that too.
|
||||
;; global functions are also global variables, so there's a global variable entry as well.
|
||||
g > (get-info fact)
|
||||
[Forward-Declared] Name: fact Defined: text from goal_src/kernel/gcommon.gc, line: 1098
|
||||
(define-extern fact (function int int))
|
||||
|
||||
[Function] Name: fact Defined: text from kernel/gcommon.gc, line: 1099
|
||||
(defun fact ((x int))
|
||||
|
||||
[Global Variable] Type: (function int int) Defined: text from goal_src/kernel/gcommon.gc, line: 1099
|
||||
(defun fact ((x int))
|
||||
|
||||
;; get info about a type
|
||||
g > (get-info kernel-context)
|
||||
[Type] Name: kernel-context Defined: text from goal_src/kernel/gkernel-h.gc, line: 114
|
||||
(deftype kernel-context (basic)
|
||||
|
||||
;; get info about a method
|
||||
g > (get-info reset!)
|
||||
[Method] Type: collide-sticky-rider-group Method Name: reset! Defined: text from goal_src/engine/collide/collide-shape-h.gc, line: 48
|
||||
(defmethod reset! collide-sticky-rider-group ((obj collide-sticky-rider-group))
|
||||
[Method] Type: collide-overlap-result Method Name: reset! Defined: text from goal_src/engine/collide/collide-shape-h.gc, line: 94
|
||||
(defmethod reset! collide-overlap-result ((obj collide-overlap-result))
|
||||
[Method] Type: load-state Method Name: reset! Defined: text from goal_src/engine/level/load-boundary.gc, line: 9
|
||||
(defmethod reset! load-state ((obj load-state))
|
||||
|
||||
;; get info about a constant
|
||||
g > (get-info TWO_PI)
|
||||
[Constant] Name: TWO_PI Value: (the-as float #x40c90fda) Defined: text from goal_src/engine/math/trigonometry.gc, line: 34
|
||||
(defconstant TWO_PI (the-as float #x40c90fda))
|
||||
|
||||
;; get info about a built-in form
|
||||
g > (get-info asm-file)
|
||||
[Built-in Form] asm-file
|
||||
```
|
||||
|
||||
## `autocomplete`
|
||||
Preview the results of the REPL autocomplete:
|
||||
```lisp
|
||||
(autcomplete <sym>)
|
||||
```
|
||||
|
||||
For example:
|
||||
```lisp
|
||||
g > (autocomplete *)
|
||||
*
|
||||
*16k-dead-pool*
|
||||
*4k-dead-pool*
|
||||
...
|
||||
Autocomplete: 326/1474 symbols matched, took 1.29 ms
|
||||
```
|
||||
|
||||
## `seval`
|
||||
Execute GOOS code.
|
||||
```lisp
|
||||
|
||||
@@ -15,9 +15,14 @@ Compiler::Compiler() : m_debugger(&m_listener) {
|
||||
m_global_env = std::make_unique<GlobalEnv>();
|
||||
m_none = std::make_unique<None>(m_ts.make_typespec("none"));
|
||||
|
||||
// todo - compile library
|
||||
// compile GOAL library
|
||||
Object library_code = m_goos.reader.read_from_file({"goal_src", "goal-lib.gc"});
|
||||
compile_object_file("goal-lib", library_code, false);
|
||||
|
||||
// add built-in forms to symbol info
|
||||
for (auto& builtin : g_goal_forms) {
|
||||
m_symbol_info.add_builtin(builtin.first);
|
||||
}
|
||||
}
|
||||
|
||||
ReplStatus Compiler::execute_repl() {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "third-party/fmt/color.h"
|
||||
#include "CompilerException.h"
|
||||
#include "goalc/compiler/SymbolInfo.h"
|
||||
#include "Enum.h"
|
||||
|
||||
enum MathMode { MATH_INT, MATH_BINT, MATH_FLOAT, MATH_INVALID };
|
||||
@@ -185,6 +186,8 @@ class Compiler {
|
||||
int offset,
|
||||
Env* env);
|
||||
|
||||
std::string make_symbol_info_description(const SymbolInfo& info);
|
||||
|
||||
TypeSystem m_ts;
|
||||
std::unique_ptr<GlobalEnv> m_global_env = nullptr;
|
||||
std::unique_ptr<None> m_none = nullptr;
|
||||
@@ -199,6 +202,8 @@ class Compiler {
|
||||
std::unordered_map<std::shared_ptr<goos::SymbolObject>, LambdaVal*> m_inlineable_functions;
|
||||
CompilerSettings m_settings;
|
||||
bool m_throw_on_define_extern_redefinition = false;
|
||||
SymbolInfoMap m_symbol_info;
|
||||
|
||||
MathMode get_math_mode(const TypeSpec& ts);
|
||||
bool is_number(const TypeSpec& ts);
|
||||
bool is_float(const TypeSpec& ts);
|
||||
@@ -427,6 +432,8 @@ class Compiler {
|
||||
Val* compile_in_package(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_build_dgo(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_reload(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_get_info(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_autocomplete(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
|
||||
// ControlFlow
|
||||
Condition compile_condition(const goos::Object& condition, Env* env, bool invert);
|
||||
@@ -503,4 +510,9 @@ class Compiler {
|
||||
Val* compile_defenum(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
};
|
||||
|
||||
extern const std::unordered_map<
|
||||
std::string,
|
||||
Val* (Compiler::*)(const goos::Object& form, const goos::Object& rest, Env* env)>
|
||||
g_goal_forms;
|
||||
|
||||
#endif // JAK_COMPILER_H
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include "common/util/Trie.h"
|
||||
#include "common/goos/Object.h"
|
||||
|
||||
/*!
|
||||
* Info about a single symbol, representing one of:
|
||||
* - Global variable
|
||||
* - Global function
|
||||
* - Type
|
||||
* - Constant
|
||||
* - Macro
|
||||
* - Builtin keyword of the OpenGOAL language
|
||||
*/
|
||||
class SymbolInfo {
|
||||
public:
|
||||
enum class Kind {
|
||||
GLOBAL_VAR,
|
||||
FWD_DECLARED_SYM,
|
||||
FUNCTION,
|
||||
TYPE,
|
||||
CONSTANT,
|
||||
MACRO,
|
||||
LANGUAGE_BUILTIN,
|
||||
METHOD,
|
||||
INVALID
|
||||
};
|
||||
|
||||
static SymbolInfo make_global(const std::string& name, const goos::Object& defining_form) {
|
||||
SymbolInfo info;
|
||||
info.m_kind = Kind::GLOBAL_VAR;
|
||||
info.m_name = name;
|
||||
info.m_def_form = defining_form;
|
||||
return info;
|
||||
}
|
||||
|
||||
static SymbolInfo make_fwd_declared_sym(const std::string& name,
|
||||
const goos::Object& defining_form) {
|
||||
SymbolInfo info;
|
||||
info.m_kind = Kind::FWD_DECLARED_SYM;
|
||||
info.m_name = name;
|
||||
info.m_def_form = defining_form;
|
||||
return info;
|
||||
}
|
||||
|
||||
static SymbolInfo make_function(const std::string& name, const goos::Object& defining_form) {
|
||||
SymbolInfo info;
|
||||
info.m_kind = Kind::FUNCTION;
|
||||
info.m_name = name;
|
||||
info.m_def_form = defining_form;
|
||||
return info;
|
||||
}
|
||||
|
||||
static SymbolInfo make_type(const std::string& name, const goos::Object& defining_form) {
|
||||
SymbolInfo info;
|
||||
info.m_kind = Kind::TYPE;
|
||||
info.m_name = name;
|
||||
info.m_def_form = defining_form;
|
||||
return info;
|
||||
}
|
||||
|
||||
static SymbolInfo make_constant(const std::string& name, const goos::Object& defining_form) {
|
||||
SymbolInfo info;
|
||||
info.m_kind = Kind::CONSTANT;
|
||||
info.m_name = name;
|
||||
info.m_def_form = defining_form;
|
||||
return info;
|
||||
}
|
||||
|
||||
static SymbolInfo make_macro(const std::string& name, const goos::Object& defining_form) {
|
||||
SymbolInfo info;
|
||||
info.m_kind = Kind::MACRO;
|
||||
info.m_name = name;
|
||||
info.m_def_form = defining_form;
|
||||
return info;
|
||||
}
|
||||
|
||||
static SymbolInfo make_builtin(const std::string& name) {
|
||||
SymbolInfo info;
|
||||
info.m_kind = Kind::LANGUAGE_BUILTIN;
|
||||
info.m_name = name;
|
||||
return info;
|
||||
}
|
||||
|
||||
static SymbolInfo make_method(const std::string& method_name,
|
||||
const std::string& type_name,
|
||||
const goos::Object& defining_form) {
|
||||
SymbolInfo info;
|
||||
info.m_kind = Kind::METHOD;
|
||||
info.m_name = method_name;
|
||||
info.m_type_of_method = type_name;
|
||||
info.m_def_form = defining_form;
|
||||
return info;
|
||||
}
|
||||
|
||||
const std::string& name() const { return m_name; }
|
||||
const std::string& type() const { return m_type_of_method; }
|
||||
Kind kind() const { return m_kind; }
|
||||
const goos::Object& src_form() const { return m_def_form; }
|
||||
|
||||
private:
|
||||
Kind m_kind = Kind::INVALID;
|
||||
goos::Object m_def_form;
|
||||
std::string m_name;
|
||||
std::string m_type_of_method;
|
||||
};
|
||||
|
||||
/*!
|
||||
* A map of symbol info. It internally stores the info in a prefix tree so you can quickly get
|
||||
* a list of all symbols starting with a given prefix.
|
||||
*/
|
||||
class SymbolInfoMap {
|
||||
public:
|
||||
SymbolInfoMap() = default;
|
||||
void add_global(const std::string& name, const goos::Object& defining_form) {
|
||||
m_map[name]->push_back(SymbolInfo::make_global(name, defining_form));
|
||||
}
|
||||
|
||||
void add_fwd_dec(const std::string& name, const goos::Object& defining_form) {
|
||||
m_map[name]->push_back(SymbolInfo::make_fwd_declared_sym(name, defining_form));
|
||||
}
|
||||
|
||||
void add_function(const std::string& name, const goos::Object& defining_form) {
|
||||
m_map[name]->push_back(SymbolInfo::make_function(name, defining_form));
|
||||
}
|
||||
|
||||
void add_type(const std::string& name, const goos::Object& defining_form) {
|
||||
m_map[name]->push_back(SymbolInfo::make_type(name, defining_form));
|
||||
}
|
||||
|
||||
void add_constant(const std::string& name, const goos::Object& defining_form) {
|
||||
m_map[name]->push_back(SymbolInfo::make_constant(name, defining_form));
|
||||
}
|
||||
|
||||
void add_macro(const std::string& name, const goos::Object& defining_form) {
|
||||
m_map[name]->push_back(SymbolInfo::make_macro(name, defining_form));
|
||||
}
|
||||
|
||||
void add_builtin(const std::string& name) {
|
||||
m_map[name]->push_back(SymbolInfo::make_builtin(name));
|
||||
}
|
||||
|
||||
void add_method(const std::string& method_name,
|
||||
const std::string& type_name,
|
||||
const goos::Object& defining_form) {
|
||||
m_map[method_name]->push_back(SymbolInfo::make_method(method_name, type_name, defining_form));
|
||||
}
|
||||
|
||||
std::vector<SymbolInfo>* lookup_exact_name(const std::string& name) { return m_map.lookup(name); }
|
||||
|
||||
std::set<std::string> lookup_symbols_starting_with(const std::string& prefix) {
|
||||
std::set<std::string> result;
|
||||
auto lookup = m_map.lookup_prefix(prefix);
|
||||
for (auto& x : lookup) {
|
||||
for (auto& y : *x) {
|
||||
result.insert(y.name());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int symbol_count() const { return m_map.size(); }
|
||||
|
||||
private:
|
||||
Trie<std::vector<SymbolInfo>> m_map;
|
||||
};
|
||||
@@ -9,10 +9,10 @@
|
||||
/*!
|
||||
* Main table for compiler forms
|
||||
*/
|
||||
static const std::unordered_map<
|
||||
const std::unordered_map<
|
||||
std::string,
|
||||
Val* (Compiler::*)(const goos::Object& form, const goos::Object& rest, Env* env)>
|
||||
goal_forms = {
|
||||
g_goal_forms = {
|
||||
// INLINE ASM
|
||||
{".nop", &Compiler::compile_nop},
|
||||
{".ret", &Compiler::compile_asm_ret},
|
||||
@@ -114,6 +114,8 @@ static const std::unordered_map<
|
||||
{":status", &Compiler::compile_poke},
|
||||
{"in-package", &Compiler::compile_in_package},
|
||||
{"reload", &Compiler::compile_reload},
|
||||
{"get-info", &Compiler::compile_get_info},
|
||||
{"autocomplete", &Compiler::compile_autocomplete},
|
||||
|
||||
// CONDITIONAL COMPILATION
|
||||
{"#cond", &Compiler::compile_gscond},
|
||||
@@ -247,8 +249,8 @@ Val* Compiler::compile_pair(const goos::Object& code, Env* env) {
|
||||
if (head.is_symbol()) {
|
||||
auto head_sym = head.as_symbol();
|
||||
// first try as a goal compiler form
|
||||
auto kv_gfs = goal_forms.find(head_sym->name);
|
||||
if (kv_gfs != goal_forms.end()) {
|
||||
auto kv_gfs = g_goal_forms.find(head_sym->name);
|
||||
if (kv_gfs != g_goal_forms.end()) {
|
||||
return ((*this).*(kv_gfs->second))(code, rest, env);
|
||||
}
|
||||
|
||||
|
||||
@@ -391,3 +391,72 @@ Val* Compiler::compile_reload(const goos::Object& form, const goos::Object& rest
|
||||
m_want_reload = true;
|
||||
return get_none();
|
||||
}
|
||||
|
||||
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_goos.reader.db.get_info_for(info.src_form()));
|
||||
case SymbolInfo::Kind::LANGUAGE_BUILTIN:
|
||||
return fmt::format("[Built-in Form] {}\n", info.name());
|
||||
case SymbolInfo::Kind::METHOD:
|
||||
return fmt::format("[Method] Type: {} Method Name: {} Defined: {}", info.type(), info.name(),
|
||||
m_goos.reader.db.get_info_for(info.src_form()));
|
||||
case SymbolInfo::Kind::TYPE:
|
||||
return fmt::format("[Type] Name: {} Defined: {}", info.name(),
|
||||
m_goos.reader.db.get_info_for(info.src_form()));
|
||||
case SymbolInfo::Kind::MACRO:
|
||||
return fmt::format("[Macro] Name: {} Defined: {}", info.name(),
|
||||
m_goos.reader.db.get_info_for(info.src_form()));
|
||||
case SymbolInfo::Kind::CONSTANT:
|
||||
return fmt::format(
|
||||
"[Constant] Name: {} Value: {} Defined: {}", info.name(),
|
||||
m_global_constants.at(m_goos.reader.symbolTable.intern(info.name())).print(),
|
||||
m_goos.reader.db.get_info_for(info.src_form()));
|
||||
case SymbolInfo::Kind::FUNCTION:
|
||||
return fmt::format("[Function] Name: {} Defined: {}", info.name(),
|
||||
m_goos.reader.db.get_info_for(info.src_form()));
|
||||
case SymbolInfo::Kind::FWD_DECLARED_SYM:
|
||||
return fmt::format("[Forward-Declared] Name: {} Defined: {}", info.name(),
|
||||
m_goos.reader.db.get_info_for(info.src_form()));
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
Val* Compiler::compile_get_info(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
(void)env;
|
||||
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);
|
||||
if (!result) {
|
||||
fmt::print("No results found.\n");
|
||||
} else {
|
||||
for (auto& info : *result) {
|
||||
fmt::print("{}", make_symbol_info_description(info));
|
||||
}
|
||||
}
|
||||
|
||||
return get_none();
|
||||
}
|
||||
|
||||
Val* Compiler::compile_autocomplete(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
(void)env;
|
||||
auto args = get_va(form, rest);
|
||||
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 time = timer.getMs();
|
||||
|
||||
for (auto& x : result) {
|
||||
fmt::print(" {}\n", x);
|
||||
}
|
||||
|
||||
fmt::print("Autocomplete: {}/{} symbols matched, took {:.2f} ms\n", result.size(),
|
||||
m_symbol_info.symbol_count(), time);
|
||||
|
||||
return get_none();
|
||||
}
|
||||
@@ -37,6 +37,11 @@ Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest
|
||||
if ((as_lambda->func && as_lambda->func->settings.allow_inline) || !as_lambda->func) {
|
||||
m_inlineable_functions[sym.as_symbol()] = as_lambda;
|
||||
}
|
||||
m_symbol_info.add_function(symbol_string(sym), form);
|
||||
}
|
||||
|
||||
if (!sym_val->settable()) {
|
||||
throw_compiler_error(form, "Cannot define {} because it cannot be set.", sym_val->print());
|
||||
}
|
||||
|
||||
auto in_gpr = compiled_val->to_gpr(fe);
|
||||
@@ -53,9 +58,8 @@ Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest
|
||||
}
|
||||
}
|
||||
|
||||
if (!sym_val->settable()) {
|
||||
throw_compiler_error(form, "Cannot define {} because it cannot be set.", sym_val->print());
|
||||
}
|
||||
m_symbol_info.add_global(symbol_string(sym), form);
|
||||
|
||||
fe->emit(std::make_unique<IR_SetSymbolValue>(sym_val, in_gpr));
|
||||
return in_gpr;
|
||||
}
|
||||
@@ -91,6 +95,7 @@ Val* Compiler::compile_define_extern(const goos::Object& form, const goos::Objec
|
||||
}
|
||||
|
||||
m_symbol_types[symbol_string(sym)] = new_type;
|
||||
m_symbol_info.add_fwd_dec(symbol_string(sym), form);
|
||||
return get_none();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ Val* Compiler::compile_goos_macro(const goos::Object& o,
|
||||
m_goos.goal_to_goos.enclosing_method_type =
|
||||
get_parent_env_of_type<FunctionEnv>(env)->method_of_type_name;
|
||||
auto goos_result = m_goos.eval_list_return_last(macro->body, macro->body, mac_env);
|
||||
// make the macro expanded form point to the source where the macro was used for error messages.
|
||||
m_goos.reader.db.inherit_info(o, goos_result);
|
||||
m_goos.goal_to_goos.reset();
|
||||
return compile_error_guard(goos_result, env);
|
||||
}
|
||||
@@ -146,6 +148,8 @@ Val* Compiler::compile_define_constant(const goos::Object& form,
|
||||
m_goos.global_environment.as_env()->vars[sym] = value;
|
||||
}
|
||||
|
||||
m_symbol_info.add_constant(sym->name, form);
|
||||
|
||||
return get_none();
|
||||
}
|
||||
|
||||
|
||||
@@ -251,6 +251,8 @@ Val* Compiler::compile_deftype(const goos::Object& form, const goos::Object& res
|
||||
// Auto-generate (inspect) method
|
||||
generate_inspector_for_type(form, env, result.type_info);
|
||||
|
||||
m_symbol_info.add_type(result.type.base_type(), form);
|
||||
|
||||
// return none, making the value of (deftype..) unusable
|
||||
return get_none();
|
||||
}
|
||||
@@ -382,6 +384,8 @@ Val* Compiler::compile_defmethod(const goos::Object& form, const goos::Object& _
|
||||
}
|
||||
place->set_type(lambda_ts);
|
||||
|
||||
m_symbol_info.add_method(symbol_string(method_name), symbol_string(type_name), form);
|
||||
|
||||
auto info =
|
||||
m_ts.add_method(symbol_string(type_name), symbol_string(method_name), lambda_ts, false);
|
||||
auto type_obj = compile_get_symbol_value(form, symbol_string(type_name), env)->to_gpr(env);
|
||||
|
||||
@@ -1,12 +1,41 @@
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "common/util/Trie.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/all_jak1_symbols.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
TEST(FileUtil, valid_path) {
|
||||
TEST(CommonUtil, get_file_path) {
|
||||
std::vector<std::string> test = {"cabbage", "banana", "apple"};
|
||||
std::string sampleString = file_util::get_file_path(test);
|
||||
// std::cout << sampleString << std::endl;
|
||||
|
||||
EXPECT_TRUE(true);
|
||||
}
|
||||
|
||||
TEST(CommonUtil, Trie) {
|
||||
Trie<std::string> test;
|
||||
|
||||
std::vector<std::string> strings;
|
||||
|
||||
for (auto x : all_syms) {
|
||||
strings.push_back(x);
|
||||
test.insert(strings.back(), strings.back());
|
||||
}
|
||||
|
||||
auto cam_prefix = test.lookup_prefix("cam");
|
||||
EXPECT_EQ(cam_prefix.size(), 184);
|
||||
EXPECT_EQ(test.lookup("not-in-the-list"), nullptr);
|
||||
EXPECT_EQ(test.lookup("cam"), nullptr);
|
||||
EXPECT_NE(test.lookup("energydoor-closed-till-near"), nullptr);
|
||||
EXPECT_EQ(7941, test.lookup_prefix("").size());
|
||||
|
||||
EXPECT_TRUE(test.lookup("") == nullptr);
|
||||
EXPECT_TRUE(test.lookup("p") == nullptr);
|
||||
EXPECT_TRUE(test.lookup("pa") == nullptr);
|
||||
EXPECT_TRUE(test.lookup("pat") == nullptr);
|
||||
EXPECT_FALSE(test.lookup("path") == nullptr);
|
||||
EXPECT_FALSE(test.lookup("path1") == nullptr);
|
||||
EXPECT_TRUE(test.lookup("path-") == nullptr);
|
||||
EXPECT_FALSE(test.lookup("path1-k") == nullptr);
|
||||
}
|
||||
Reference in New Issue
Block a user