Merge branch 'master' of github.com:water111/jak-project into w/jak3-boot2

This commit is contained in:
water
2024-03-31 11:20:15 -04:00
388 changed files with 54705 additions and 10264 deletions
@@ -61,7 +61,6 @@ jobs:
run: cmake --build build --parallel %NUMBER_OF_PROCESSORS%
- name: Run Tests
timeout-minutes: 10
env:
GTEST_OUTPUT: "xml:opengoal-test-report.xml"
run: ./build/bin/goalc-test.exe --gtest_color=yes --gtest_brief=0 --gtest_filter="-*MANUAL_TEST*"
-7
View File
@@ -143,13 +143,6 @@
"name": "Game - Jak 2 - Runtime (release)",
"args": ["-v", "--game", "jak2", "--", "-boot", "-fakeiso"]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc.exe (bin\\goalc.exe)",
"name": "REPL",
"args": ["--user-auto"]
},
{
"type": "default",
"project": "CMakeLists.txt",
+2 -1
View File
@@ -7,5 +7,6 @@
},
"editor.wordBasedSuggestions": "matchingDocuments",
"editor.snippetSuggestions": "top"
}
},
"cmake.configureOnOpen": false
}
+2 -1
View File
@@ -66,6 +66,7 @@ add_library(common
type_system/TypeSpec.cpp
type_system/TypeSystem.cpp
util/Assert.cpp
util/ast_util.cpp
util/BitUtils.cpp
util/compress.cpp
util/crc32.cpp
@@ -87,7 +88,7 @@ add_library(common
util/Timer.cpp
util/unicode_util.cpp
versions/versions.cpp
)
"util/trie_map.h")
target_link_libraries(common fmt lzokay replxx libzstd_static tree-sitter sqlite3 libtinyfiledialogs)
+3 -2
View File
@@ -2,8 +2,11 @@
#include "formatter_tree.h"
#include "common/formatter/rules/formatting_rules.h"
#include "common/formatter/rules/rule_config.h"
#include "common/log/log.h"
#include "common/util/FileUtil.h"
#include "common/util/ast_util.h"
#include "common/util/string_util.h"
#include "tree_sitter/api.h"
@@ -400,8 +403,6 @@ std::string join_formatted_lines(const std::vector<std::string>& lines,
std::optional<std::string> formatter::format_code(const std::string& source) {
// Create a parser.
std::shared_ptr<TSParser> parser(ts_parser_new(), TreeSitterParserDeleter());
// Set the parser's language (JSON in this case).
ts_parser_set_language(parser.get(), tree_sitter_opengoal());
// Build a syntax tree based on source code stored in a string.
-5
View File
@@ -3,13 +3,8 @@
#include <optional>
#include <string>
#include "common/formatter/rules/formatting_rules.h"
#include "common/formatter/rules/rule_config.h"
#include "tree_sitter/api.h"
// TODO:
// - Considering _eventually_ adding line-length heuristics
namespace formatter {
struct TreeSitterParserDeleter {
+15
View File
@@ -1442,6 +1442,21 @@ std::vector<std::string> TypeSystem::search_types_by_parent_type(
return results;
}
std::vector<std::string> TypeSystem::search_types_by_parent_type_strict(
const std::string& parent_type) {
std::vector<std::string> results = {};
for (const auto& [type_name, type_info] : m_types) {
// Only NullType's have no parent
if (!type_info->has_parent()) {
continue;
}
if (type_info->get_parent() == parent_type) {
results.push_back(type_name);
}
}
return results;
}
std::vector<std::string> TypeSystem::search_types_by_minimum_method_id(
const int minimum_method_id,
const std::optional<std::vector<std::string>>& existing_matches) {
+1
View File
@@ -278,6 +278,7 @@ class TypeSystem {
std::vector<std::string> search_types_by_parent_type(
const std::string& parent_type,
const std::optional<std::vector<std::string>>& existing_matches = {});
std::vector<std::string> search_types_by_parent_type_strict(const std::string& parent_type);
std::vector<std::string> search_types_by_minimum_method_id(
const int minimum_method_id,
+21
View File
@@ -736,4 +736,25 @@ std::string get_majority_file_line_endings(const std::string& file_contents) {
return "\n";
}
std::pair<int, std::string> get_majority_file_line_endings_and_count(
const std::string& file_contents) {
size_t lf_count = 0;
size_t crlf_count = 0;
for (size_t i = 0; i < file_contents.size(); ++i) {
if (file_contents[i] == '\n') {
if (i > 0 && file_contents[i - 1] == '\r') {
crlf_count++;
} else {
lf_count++;
}
}
}
if (crlf_count > lf_count) {
return {lf_count + crlf_count, "\r\n"};
}
return {lf_count + crlf_count, "\n"};
}
} // namespace file_util
+2
View File
@@ -72,4 +72,6 @@ std::vector<fs::path> sort_filepaths(const std::vector<fs::path>& paths, const b
void copy_file(const fs::path& src, const fs::path& dst);
std::string make_screenshot_filepath(const GameVersion game_version, const std::string& name = "");
std::string get_majority_file_line_endings(const std::string& file_contents);
std::pair<int, std::string> get_majority_file_line_endings_and_count(
const std::string& file_contents);
} // namespace file_util
+1 -1
View File
@@ -67,4 +67,4 @@ class Range {
private:
T m_start = {};
T m_end = {};
};
};
+1 -1
View File
@@ -12,7 +12,7 @@
* 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.
* Other than deleting the whole thing, there is no support for removing a node.
*/
template <typename T>
class Trie {
+31
View File
@@ -0,0 +1,31 @@
#include "ast_util.h"
namespace ast_util {
std::string get_source_code(const std::string& source, const TSNode& node) {
uint32_t start = ts_node_start_byte(node);
uint32_t end = ts_node_end_byte(node);
return source.substr(start, end - start);
}
void search_for_forms_that_begin_with(const std::string& source,
const TSNode curr_node,
const std::vector<std::string>& prefix,
std::vector<TSNode>& results) {
if (ts_node_child_count(curr_node) == 0) {
return;
}
std::vector<std::string> node_elements;
bool added = false;
for (size_t i = 0; i < ts_node_child_count(curr_node); i++) {
const auto child_node = ts_node_child(curr_node, i);
const auto contents = get_source_code(source, child_node);
node_elements.push_back(contents);
// Check for a match
if (node_elements == prefix && !added) {
results.push_back(curr_node);
added = true;
}
search_for_forms_that_begin_with(source, child_node, prefix, results);
}
}
} // namespace ast_util
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <string>
#include <vector>
#include "tree_sitter/api.h"
namespace ast_util {
std::string get_source_code(const std::string& source, const TSNode& node);
void search_for_forms_that_begin_with(const std::string& source,
const TSNode curr_node,
const std::vector<std::string>& prefix,
std::vector<TSNode>& results);
} // namespace ast_util
+160
View File
@@ -0,0 +1,160 @@
#pragma once
#include <algorithm>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
// TrieMap class
template <typename T>
class TrieMap {
private:
// TrieNode structure
struct TrieNode {
std::unordered_map<char, std::shared_ptr<TrieNode>> children;
std::vector<std::shared_ptr<T>> elements;
};
std::shared_ptr<TrieNode> root;
public:
TrieMap() : root(std::make_shared<TrieNode>()) {}
// Insert an element with a key into the TrieMap and return the inserted element
std::shared_ptr<T> insert(const std::string& key, const T& element) {
std::shared_ptr<T> shared_element = std::make_shared<T>(element);
std::shared_ptr<TrieNode> node = root;
for (char c : key) {
if (node->children.find(c) == node->children.end()) {
node->children[c] = std::make_shared<TrieNode>();
}
node = node->children[c];
}
// Store element at the leaf node
node->elements.push_back(shared_element);
return shared_element;
}
// Retrieve elements with a given prefix
std::vector<std::shared_ptr<T>> retrieve_with_prefix(const std::string& prefix) const {
std::vector<std::shared_ptr<T>> result;
std::shared_ptr<TrieNode> node = root;
// Traverse to the node representing the prefix
for (char c : prefix) {
if (node->children.find(c) == node->children.end()) {
return result; // No elements with the given prefix
}
node = node->children[c];
}
// Gather all elements stored at or below this node
retrieve_elements(node, result);
return result;
}
// Retrieve elements with an exact key match
std::vector<std::shared_ptr<T>> retrieve_with_exact(const std::string& key) const {
std::vector<std::shared_ptr<T>> result;
std::shared_ptr<TrieNode> node = root;
// Traverse to the node representing the key
for (char c : key) {
if (node->children.find(c) == node->children.end()) {
return result; // No elements with the given key
}
node = node->children[c];
}
// Return elements stored at this node
return node->elements;
}
// Remove the specified element from the TrieMap
void remove(const std::shared_ptr<T>& element) { remove_element(root, element); }
// Return the total number of elements stored in the TrieMap
int size() const {
int count = 0;
count_elements(root, count);
return count;
}
// Return a vector containing shared pointers to all elements stored in the TrieMap
std::vector<std::shared_ptr<T>> get_all_elements() const {
std::vector<std::shared_ptr<T>> result;
get_all_elements_helper(root, result);
return result;
}
private:
// Recursive function to retrieve elements stored at or below the given node
void retrieve_elements(std::shared_ptr<TrieNode> node,
std::vector<std::shared_ptr<T>>& result) const {
// Add elements stored at this node to the result
for (const auto& element : node->elements) {
result.push_back(element);
}
// Recursively traverse children
for (const auto& child : node->children) {
retrieve_elements(child.second, result);
}
}
// Recursive function to remove the specified element from the TrieMap
bool remove_element(std::shared_ptr<TrieNode> node, const std::shared_ptr<T>& element) {
// Remove the element if it exists at this node
auto& elements = node->elements;
auto it = std::find(elements.begin(), elements.end(), element);
if (it != elements.end()) {
elements.erase(it);
return true;
}
// Recursively search children
for (auto& child : node->children) {
if (remove_element(child.second, element)) {
// Remove child node if it's empty after removal
if (child.second->elements.empty() && child.second->children.empty()) {
node->children.erase(child.first);
}
return true;
}
}
return false;
}
// Recursive function to count elements stored at or below the given node
void count_elements(std::shared_ptr<TrieNode> node, int& count) const {
// Increment count by the number of elements stored at this node
count += node->elements.size();
// Recursively traverse children
for (const auto& child : node->children) {
count_elements(child.second, count);
}
}
// Recursive helper function to collect all elements stored in the TrieMap
void get_all_elements_helper(std::shared_ptr<TrieNode> node,
std::vector<std::shared_ptr<T>>& result) const {
// Add elements stored at this node to the result
for (const auto& element : node->elements) {
result.push_back(element);
}
// Recursively traverse children
for (const auto& child : node->children) {
get_all_elements_helper(child.second, result);
}
}
};
// TrieMap<std::string> trie_map;
//
//// Insert elements
// std::shared_ptr<std::string> inserted_element_1 = trie_map.insert("apple", "A fruit");
// std::shared_ptr<std::string> inserted_element_2 = trie_map.insert("app", "An application");
// std::shared_ptr<std::string> inserted_element_3 = trie_map.insert("banana", "Another fruit");
// std::shared_ptr<std::string> inserted_element_4 = trie_map.insert("apple", "Another apple");
//
//// Remove an element
// trie_map.remove(inserted_element_1);
//
//// Retrieve elements with a prefix
// std::vector<std::shared_ptr<std::string>> prefix_results = trie_map.retrieve_with_prefix("app");
+31 -6
View File
@@ -355,6 +355,21 @@ FormElement* rewrite_virtual_defstate(
inherit_info = {{mot_mr.maps.strings.at(0), mot_mr.maps.strings.at(1)}};
}
// jak 3: some virtual states set their parent here and inherit from their own type's states...
std::string maybe_parent_state;
std::string maybe_state_type;
auto maybe_parent = elt->body()->at(body_idx);
auto maybe_parent_matcher =
Matcher::set(Matcher::deref(Matcher::any_reg(), false, {DerefTokenMatcher::string("parent")}),
Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::METHOD_OF_TYPE),
{Matcher::any_symbol(0), Matcher::any_constant_token(1)}));
auto maybe_parent_mr = match(maybe_parent_matcher, maybe_parent);
if (maybe_parent_mr.matched) {
maybe_state_type = maybe_parent_mr.maps.strings.at(0);
maybe_parent_state = maybe_parent_mr.maps.strings.at(1);
body_idx++;
}
// checks to check: method type is a state
// if inherit matches expected.
@@ -411,7 +426,14 @@ FormElement* rewrite_virtual_defstate(
// expected_state_name, type_name);
}
} else {
if (inherit_info) {
// if we set our parent state, check that that state's type and this type are the same
if (inherit_info && maybe_parent_mr.matched && maybe_state_type == type_name) {
env.func->warnings.warning(
"Virtual defstate {} is inheriting from state {} which is one of its own type's "
"states.",
expected_state_name, maybe_parent_state);
}
if (inherit_info && !maybe_parent_mr.matched) {
env.func->warnings.error_and_throw(
"Virtual defstate for state {} in type {}: the state wasn't defined in the "
"parent but was inherited.",
@@ -421,7 +443,7 @@ FormElement* rewrite_virtual_defstate(
}
// checks: parent_type_name is the parent
if (inherit_info) {
if (inherit_info && !maybe_parent_mr.matched) {
auto child_type_info = env.dts->ts.lookup_type(type_name);
if (child_type_info->get_parent() != inherit_info->parent_type_name) {
env.func->warnings.error_and_throw(
@@ -451,8 +473,13 @@ FormElement* rewrite_virtual_defstate(
elt->body(), body_idx + 1, env, expected_state_name, elt->entries().at(0).dest,
method_info.type.substitute_for_method_call(type_name), pool, type_name, skip_states);
return pool.alloc_element<DefstateElement>(type_name, expected_state_name, "", entries, true,
state_override);
std::string parent_str;
if (!maybe_parent_state.empty()) {
parent_str = fmt::format("({} {})", type_name, maybe_parent_state);
}
return pool.alloc_element<DefstateElement>(type_name, expected_state_name, parent_str, entries,
true, state_override);
}
FormElement* rewrite_virtual_defstate_with_nonvirtual_inherit(
@@ -481,8 +508,6 @@ FormElement* rewrite_virtual_defstate_with_nonvirtual_inherit(
// (set! (-> gp-6 exit) (the-as (function object) L251))
// (set! (-> gp-6 trans) (the-as (function object) L253))
// )
// ASSERT(elt->body()->size() > 1);
env.func->warnings.warning("Encountered virtual defstate {} with non-virtual inherit.",
expected_state_name);
// variable at the top of let, contains the static state with name exptected_state_name
+241 -268
View File
@@ -2265,16 +2265,16 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern matrix-fur-compose (function matrix vector vector vector matrix))
(define-extern matrix-fu-compose (function matrix vector vector vector matrix))
(define-extern matrix-fu-compose (function matrix vector vector matrix))
(define-extern matrix-fr-compose (function matrix vector vector vector matrix))
(define-extern matrix-ur-compose (function matrix vector vector vector matrix))
(define-extern matrix-f-u-compose (function matrix vector vector vector matrix))
(define-extern matrix-f-u-compose (function matrix vector vector matrix))
(define-extern matrix-f-r-compose (function matrix vector vector vector matrix))
(define-extern matrix-u-f-compose (function matrix vector vector matrix))
(define-extern matrix-u-r-compose (function matrix vector vector vector matrix))
(define-extern matrix-r-f-compose (function matrix vector vector vector matrix))
(define-extern matrix-r-u-compose (function matrix vector vector vector matrix))
(define-extern matrix-f-compose (function matrix vector vector vector matrix))
(define-extern matrix-f-compose (function matrix vector float matrix))
(define-extern matrix-u-compose (function matrix vector vector vector matrix))
(define-extern matrix-r-compose (function matrix vector vector vector matrix))
@@ -7452,6 +7452,19 @@
(movie0 16)
(movie1 17)
(movie2 18)
(tm19 19)
(tm20 20)
(tm21 21)
(tm22 22)
(tm23 23)
(tm24 24)
(tm25 25)
(tm26 26)
(tm27 27)
(tm28 28)
(tm29 29)
(tm30 30)
(tm31 31)
)
;; ---level-h:task-mask
@@ -7818,7 +7831,7 @@
it will kick out levels as needed to make a free slot, and set up a new level, and start
the load. This should only be used when you might want to start a load." (_type_ symbol symbol) level) ;; 12
(activate-levels! "Make all levels 'active!" (_type_) int) ;; 13
(level-group-method-14 () none) ;; 14 ;; (debug-print-entities (_type_ symbol type) none)
(debug-print-entities (_type_ symbol type string) none) ;; 14
(debug-draw-actors (_type_ symbol) none) ;; 15
(assign-draw-indices "Assign the order for levels to be drawn." (_type_) none) ;; 16
(actors-update (_type_) none) ;; 17
@@ -7827,11 +7840,11 @@
(level-get-target-inside "Get the level that the player is 'in'." (_type_) level) ;; 20
(init-level-system "If needed, initialize the level system by loading common/art packages and allocating level heaps." (_type_ symbol) none) ;; 21
(art-group-get-by-name "Check all levels for an art group with the given name." (_type_ string (pointer level)) art-group) ;; 22 ;; (load-commands-set! (_type_ pair) none)
(level-group-method-23 () none) ;; 23 ;; (art-group-get-by-name (_type_ string (pointer uint32)) art-group)
(level-group-method-24 () none) ;; 24 ;; (alt-load-command-get-index (_type_ symbol int) pair)
(level-group-method-25 () none) ;; 25 ;; (update-vis-volumes (_type_) none)
(update-vis-volumes (_type_) none) ;; 23 ;; (art-group-get-by-name (_type_ string (pointer uint32)) art-group)
(level-group-method-24 (_type_) none) ;; 24 ;; (alt-load-command-get-index (_type_ symbol int) pair)
(print-volume-sizes (_type_) none) ;; 25
(status-of-level-and-borrows "Get the combined status of a level and borrow levels." (_type_ symbol symbol) symbol) ;; 26 ;; (update-vis-volumes-from-nav-mesh (_type_) none)
(do-nothing "Empty method." (_type_) none) ;; 27 ;; (print-volume-sizes (_type_) none)
(do-nothing "Empty method." (_type_) none) ;; 27
(load-in-progress? "Is there a load happening now?" (_type_) symbol) ;; 28 ;; (level-status (_type_ symbol) symbol)
(is-load-allowed? "Does the exclusive-load setting allow us to load this level?" (_type_ (pointer symbol)) symbol) ;; 29
(level-get-most-disposable "Get the level inside this level-group that should
@@ -17968,7 +17981,7 @@
(radius float :offset-assert 56)
(duration float :offset-assert 60)
(duration-rand float :offset-assert 64)
(sound symbol :offset-assert 68)
(sound sound-spec :offset-assert 68)
(delay float :offset-assert 72)
(delay-rand float :offset-assert 76)
)
@@ -20566,7 +20579,7 @@
(send-shoves (_type_ process touching-shapes-entry float float float) symbol) ;; 50
(above-ground? (_type_ collide-query vector collide-spec float float float) symbol) ;; 51
(water-info-init! (_type_ water-info collide-action) water-info) ;; 52
(collide-shape-method-53 () none) ;; 53 ;; (iterate-prims (_type_ (function collide-shape-prim none)) none)
(iterate-prims (_type_ (function collide-shape-prim none)) none) ;; 53
(collide-shape-method-54 () none) ;; 54 ;; (pusher-init (_type_) none)
)
)
@@ -23212,6 +23225,7 @@
(declare-type entity-camera entity)
(declare-type entity-nav-mesh structure)
(declare-type entity-race-mesh entity)
(declare-type city-level-info structure)
(deftype bsp-node (structure)
@@ -23263,11 +23277,11 @@
; (ambients symbol :offset-assert 156) ;; now just #t?
(subdivide-close float :offset 160)
(subdivide-far float :offset-assert 164)
; (race-meshes (array entity-race-mesh) :offset-assert 168)
(race-meshes (array entity-race-mesh) :offset-assert 168)
(actor-birth-order (pointer uint32) :offset 172)
(light-hash light-hash :offset-assert 176)
(nav-meshes (array entity-nav-mesh) :offset-assert 180)
; (actor-groups (array actor-group) :offset-assert 184)
(actor-groups (array actor-group) :offset-assert 184)
(region-trees (array drawable-tree-region-prim) :offset 188)
; (region-array region-array :offset-assert 192)
(collide-hash collide-hash :offset 196)
@@ -25104,7 +25118,7 @@
:size-assert #x40
:flag-assert #xa00000040
(:methods
(entity-links-method-9 () none) ;; 9 ;; (birth? (_type_ vector) symbol)
(birth? (_type_ vector) symbol) ;; 9
)
)
@@ -25258,7 +25272,7 @@
(sx float :offset 12)
(sy float :offset 28)
(rot float :offset 24)
(flag int32 :offset 16)
(flag int32 :offset 16 :score 1)
(matrix int32 :offset 20)
(warp-turns int32 :offset 16)
(r float :offset 32)
@@ -28105,9 +28119,9 @@
(nav-mesh-method-19 () none) ;; 19 ;; (clamp-vector-to-mesh-no-gaps (_type_ vector nav-poly vector clamp-travel-vector-to-mesh-return-info) none)
(nav-mesh-method-20 () none) ;; 20 ;; (set-normals-from-adjacent-bounds (_type_ clamp-travel-vector-to-mesh-return-info) none)
(nav-mesh-method-21 () none) ;; 21 ;; (find-adjacent-bounds-one (_type_ vector nav-poly int int) none)
(nav-mesh-method-22 () none) ;; 22 ;; (compute-bounding-box-from-vertices (_type_ vector vector) none)
(nav-mesh-method-22 () none) ;; 22
(nav-mesh-method-23 () none) ;; 23 ;; (init-from-entity (_type_ entity-nav-mesh) none)
(nav-mesh-method-24 () none) ;; 24 ;; (handle-birth (_type_) none)
(compute-bounding-box-from-vertices (_type_ vector vector) none) ;; 24 ;; (handle-birth (_type_) none)
(nav-mesh-method-25 () none) ;; 25 ;; (handle-kill (_type_) none)
(nav-mesh-method-26 () none) ;; 26 ;; (update-navigation (_type_) none)
(nav-mesh-method-27 () none) ;; 27 ;; (new-nav-control (_type_ process-drawable) nav-control)
@@ -28331,7 +28345,7 @@
:size-assert #x120
:flag-assert #x2f00000120
(:methods
(nav-control-method-9 () none) ;; 9 ;; (debug-draw (_type_) none)
(debug-draw (_type_) none) ;; 9
(nav-control-method-10 () none) ;; 10 ;; (point-in-bsphere? (_type_ vector) symbol)
(find-poly-containing-point-1 (_type_ vector) nav-poly) ;; 11
(cloest-point-on-mesh (_type_ vector vector nav-poly) nav-poly) ;; 12
@@ -30954,10 +30968,10 @@
(define-extern *particle-vel* vector)
;; (define-extern birth-func-set-vel function) ;; (function object sparticle-cpuinfo sparticle-launchinfo none)
;; (define-extern birth-func-texture-group function) ;; (function int sparticle-cpuinfo sparticle-launchinfo none)
;; (define-extern rot-to-particle function)
(define-extern rot-to-particle (function degrees sprite-vec-data-2d matrix none))
;; (define-extern birth-func-flip-based-on-scale function)
;; (define-extern sparticle-2d-spline-align function)
;; (define-extern sparticle-2d-spline-align-instant function)
(define-extern sparticle-2d-spline-align-instant (function object sparticle-cpuinfo sprite-vec-data-2d object none))
;; (define-extern birth-func-inherit-size function)
;; (define-extern birth-func-texture-group-2d function)
;; (define-extern birth-func-set-vel-2d function)
@@ -33211,7 +33225,7 @@
(define-extern slave-los-state->string (function slave-los-state string))
;; (define-extern cam-line-dma function) ;; (function pointer)
;; (define-extern camera-line2d function) ;; (function vector4w vector4w pointer)
;; (define-extern camera-plot-float-func function) ;; (function float float float float (function float float) vector4w none)
(define-extern camera-plot-float-func (function float float float float (function float float) vector4w none))
(define-extern camera-line-setup (function vector4w none))
(define-extern camera-line-draw (function vector vector none))
(define-extern camera-line (function vector vector vector4w none))
@@ -33606,7 +33620,7 @@
:size-assert #x10
:flag-assert #xc00000010
(:methods
(curve2d-piecewise-method-10 (_type_ int symbol uint) none) ;; 10
(curve2d-piecewise-method-10 (_type_ int symbol int) none) ;; 10
(curve2d-piecewise-method-11 (_type_) none) ;; 11
)
)
@@ -35383,7 +35397,7 @@
;; (define-extern spt-birth-func-part-jump-droppings-for function)
(define-extern process-drawable-burn-effect (function time-frame rgbaf :behavior target))
(define-extern lightning-probe-callback (function lightning-tracker none))
;; (define-extern process-drawable-shock-effect-replace function)
(define-extern process-drawable-shock-effect-replace (function process-drawable lightning-spec (function lightning-tracker none) int int float none))
(define-extern process-drawable-shock-effect (function process-drawable lightning-spec (function lightning-tracker none) sparticle-launcher int int float object))
;; (define-extern process-drawable-shock-wall-effect function) ;; (function process-drawable lightning-spec (function lightning-tracker none) sparticle-launcher symbol)
(define-extern process-drawable2-shock-effect (function process-drawable process-drawable lightning-spec (function lightning-tracker none) sparticle-launcher none))
@@ -35395,28 +35409,28 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (define-extern sparticle-track-gun-joint function)
;; (define-extern *red-shot-colors* object) ;; (pointer rgba)
;; (define-extern *range-explo-dust-color* curve-color-fast)
;; (define-extern *range-explo-dust-alpha* curve2d-fast)
;; (define-extern *range-explo-dust-scale-x* curve2d-fast)
;; (define-extern *range-explo-dust-scale-y* curve2d-fast)
;; (define-extern *curve-explo-dust-alpha* curve2d-fast)
;; (define-extern *curve-explo-dust-scale-x* curve2d-fast)
;; (define-extern *curve-explo-dust-scale-y* curve2d-fast)
;; (define-extern *part-gun-red3-explosion-dust-in-curve-settings* object)
;; (define-extern *range-explo-color* curve-color-fast)
;; (define-extern *range-explo-alpha* curve2d-fast)
;; (define-extern *range-explo-scale-x* curve2d-fast)
;; (define-extern *range-explo-scale-y* curve2d-fast)
;; (define-extern *curve-explo-alpha* curve2d-fast)
;; (define-extern *curve-explo-scale-x* curve2d-fast)
;; (define-extern *curve-explo-scale-y* curve2d-fast)
;; (define-extern *part-gun-red3-explosion-texture-curve-settings* object)
;; (define-extern *curve-linear-up-red* object)
(define-extern *red-shot-colors* (pointer rgba))
(define-extern *range-explo-dust-color* curve-color-fast)
(define-extern *range-explo-dust-alpha* curve2d-fast)
(define-extern *range-explo-dust-scale-x* curve2d-fast)
(define-extern *range-explo-dust-scale-y* curve2d-fast)
(define-extern *curve-explo-dust-alpha* curve2d-fast)
(define-extern *curve-explo-dust-scale-x* curve2d-fast)
(define-extern *curve-explo-dust-scale-y* curve2d-fast)
(define-extern *part-gun-red3-explosion-dust-in-curve-settings* particle-curve-settings)
(define-extern *range-explo-color* curve-color-fast)
(define-extern *range-explo-alpha* curve2d-fast)
(define-extern *range-explo-scale-x* curve2d-fast)
(define-extern *range-explo-scale-y* curve2d-fast)
(define-extern *curve-explo-alpha* curve2d-fast)
(define-extern *curve-explo-scale-x* curve2d-fast)
(define-extern *curve-explo-scale-y* curve2d-fast)
(define-extern *part-gun-red3-explosion-texture-curve-settings* particle-curve-settings)
(define-extern *curve-linear-up-red* curve2d-piecewise)
(define-extern *red-shot-3-trail* light-trail-composition)
;; (define-extern *curve-yellow2-shot-alpha* object)
;; (define-extern *curve-yellow2-shot-color* curve-color-fast)
;; (define-extern *curve-linear-down-long* curve2d-fast)
(define-extern *curve-yellow2-shot-alpha* curve2d-piecewise)
(define-extern *curve-yellow2-shot-color* curve-color-fast)
(define-extern *curve-linear-down-long* curve2d-fast)
(define-extern *yellow-shot-2-trail* light-trail-composition)
;; (define-extern check-shell-level1 function) ;; (function sparticle-system sparticle-cpuinfo vector none)
;; (define-extern check-shell-level2 function) ;; (function sparticle-system sparticle-cpuinfo vector none)
@@ -35427,20 +35441,20 @@
;; (define-extern birth-func-converge function)
;; (define-extern sparticle-red-2-converge function)
;; (define-extern sparticle-red-2-glow-trail-halt function)
;; (define-extern *gun-dark-3-nuke-fade-time* object)
;; (define-extern *gun-dark-3-nuke-fade-curve* object)
;; (define-extern *gun-dark-3-nuke-blur-segs* object)
;; (define-extern *gun-dark-3-nuke-blur-time* object)
;; (define-extern *gun-dark-3-nuke-blur-curve* object)
;; (define-extern *gun-dark-3-mushroom-speed* object)
;; (define-extern *gun-dark-3-mushroom-size-time* object)
;; (define-extern *gun-dark-3-nuke-mushroom-size-curve-x* object)
;; (define-extern *gun-dark-3-nuke-mushroom-size-curve-y* object)
;; (define-extern *gun-dark-3-nuke-fade-time-small* object)
;; (define-extern *gun-dark-3-nuke-fade-curve-small* object)
;; (define-extern *gun-dark-3-nuke-blur-segs-small* object)
;; (define-extern *gun-dark-3-nuke-blur-time-small* object)
;; (define-extern *gun-dark-3-nuke-blur-curve-small* object)
(define-extern *gun-dark-3-nuke-fade-time* time-frame)
(define-extern *gun-dark-3-nuke-fade-curve* curve-color-piecewise)
(define-extern *gun-dark-3-nuke-blur-segs* uint)
(define-extern *gun-dark-3-nuke-blur-time* time-frame)
(define-extern *gun-dark-3-nuke-blur-curve* curve2d-piecewise)
(define-extern *gun-dark-3-mushroom-speed* float)
(define-extern *gun-dark-3-mushroom-size-time* time-frame)
(define-extern *gun-dark-3-nuke-mushroom-size-curve-x* curve2d-piecewise)
(define-extern *gun-dark-3-nuke-mushroom-size-curve-y* curve2d-piecewise)
(define-extern *gun-dark-3-nuke-fade-time-small* time-frame)
(define-extern *gun-dark-3-nuke-fade-curve-small* curve-color-piecewise)
(define-extern *gun-dark-3-nuke-blur-segs-small* uint)
(define-extern *gun-dark-3-nuke-blur-time-small* time-frame)
(define-extern *gun-dark-3-nuke-blur-curve-small* curve2d-piecewise)
;; (define-extern spt-func-part-gun-dark-1-upgrade-shot-edges function)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -36094,9 +36108,8 @@
;; gun-blue-shot ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#|
(deftype gun-blue-shot-3 (projectile)
((hit-actor? basic :offset-assert 512)
((hit-actor? symbol :offset-assert 512)
(start-pos vector :inline :offset-assert 528)
(track-mode uint64 :offset-assert 544)
(random-travel-distance float :offset-assert 552)
@@ -36109,9 +36122,7 @@
dissipate ;; 21
)
)
|#
#|
(deftype dist-dot-val (structure)
((dot float :offset-assert 0)
(dist float :offset-assert 4)
@@ -36122,54 +36133,44 @@
:size-assert #x30
:flag-assert #x900000030
)
|#
#|
(deftype light-trail-tracker-blue-3 (light-trail-tracker-projectile)
()
:method-count-assert 22
:size-assert #xb8
:flag-assert #x16004000b8
)
|#
#|
(deftype target-quality-info (structure)
((targ uint64 :offset-assert 0)
((targ handle :offset-assert 0)
(value float :offset-assert 8)
)
:method-count-assert 9
:size-assert #xc
:flag-assert #x90000000c
)
|#
#|
(deftype timeframe-wrapper (structure)
((time uint64 :offset-assert 0)
((time time-frame :offset-assert 0)
)
:method-count-assert 9
:size-assert #x8
:flag-assert #x900000008
)
|#
#|
(deftype gun-blue-2-lightning-info (structure)
((pts UNKNOWN 32 :offset-assert 0)
((pts vector 32 :inline :offset-assert 0)
(num-pts int8 :offset-assert 512)
(should-draw-terminal-sparks? basic :offset-assert 516)
(should-draw-terminal-sparks? symbol :offset-assert 516)
(terminal-spark-pos vector :inline :offset-assert 528)
(should-draw-extension? basic :offset-assert 544)
(should-draw-extension? symbol :offset-assert 544)
(extension-end-point vector :inline :offset-assert 560)
)
:method-count-assert 9
:size-assert #x240
:flag-assert #x900000240
)
|#
#|
(deftype gun-blue-lightning-command (structure)
((msg uint64 :offset-assert 0)
(lightning-info gun-blue-2-lightning-info :inline :offset-assert 16)
@@ -36178,20 +36179,18 @@
:size-assert #x250
:flag-assert #x900000250
)
|#
#|
(deftype gun-blue-2-lightning-tracker (process-drawable)
((lt-array basic :offset-assert 200)
(should-draw-this-frame? basic :offset-assert 204)
(last-spark-time uint64 :offset-assert 216)
(spark-time-interval uint64 :offset-assert 224)
(last-deduct-ammo-time uint64 :offset-assert 232)
(snd-lightning uint32 :offset-assert 240)
(active-enter-time uint64 :offset-assert 248)
((lt-array (array gun-blue-2-lightning-info) :offset-assert 200)
(should-draw-this-frame? symbol :offset-assert 204)
(last-spark-time time-frame :offset 216)
(spark-time-interval time-frame :offset-assert 224)
(last-deduct-ammo-time time-frame :offset-assert 232)
(snd-lightning sound-id :offset-assert 240)
(active-enter-time time-frame :offset-assert 248)
(revolve-angle float :offset-assert 256)
(sway-angle float :offset-assert 260)
(snd-spin uint32 :offset-assert 264)
(snd-spin sound-id :offset-assert 264)
(spin-intensity float :offset-assert 268)
(prev-targ-pos vector :inline :offset-assert 272)
(last-probe-index int16 :offset-assert 288)
@@ -36199,32 +36198,28 @@
:method-count-assert 27
:size-assert #x122
:flag-assert #x1b00b00122
(:state-methods
active ;; 20
inactive ;; 21
die ;; 22
test ;; 23
)
(:methods
(gun-blue-2-lightning-tracker-method-24 () none) ;; 24
(gun-blue-2-lightning-tracker-method-25 () none) ;; 25
(gun-blue-2-lightning-tracker-method-26 () none) ;; 26
)
(:state-methods
test ;; 23
active ;; 20
inactive ;; 21
die ;; 22
)
)
|#
#|
(deftype gun-blue-2-target-info (structure)
((target uint64 :offset-assert 0)
(start-time uint64 :offset-assert 8)
((target handle :offset-assert 0)
(start-time time-frame :offset-assert 8)
)
:method-count-assert 9
:size-assert #x10
:flag-assert #x900000010
)
|#
#|
(deftype constraint-knot (structure)
((pt vector :inline :offset-assert 0)
(dir vector :inline :offset-assert 16)
@@ -36234,11 +36229,9 @@
:size-assert #x24
:flag-assert #x900000024
)
|#
#|
(deftype rope-constraint (structure)
((constraints UNKNOWN 12 :offset-assert 0)
((constraints constraint-knot 12 :inline :offset-assert 0)
(num-knots uint8 :offset-assert 576)
)
:method-count-assert 10
@@ -36248,9 +36241,7 @@
(rope-constraint-method-9 () none) ;; 9
)
)
|#
#|
(deftype gun-blue-2-lightning-init-params (structure)
((num-beams int8 :offset-assert 0)
)
@@ -36258,9 +36249,7 @@
:size-assert #x1
:flag-assert #x900000001
)
|#
#|
(deftype gun-blue-shot (projectile)
((init-pos vector :inline :offset-assert 512)
(init-dir vector :inline :offset-assert 528)
@@ -36270,23 +36259,20 @@
:size-assert #x230
:flag-assert #x2901b00230
)
|#
#|
(deftype gun-blue-shot-2 (gun-blue-shot)
()
:method-count-assert 41
:size-assert #x230
:flag-assert #x2901b00230
)
|#
;; (define-extern sparticle-fade-alpha-dist function)
;; (define-extern gun-fire-blue-1 function)
;; (define-extern fmod-2 function)
;; (define-extern get-dist-and-dot function)
;; (define-extern gun-blue-shot-3-move function)
;; (define-extern *blue-shot-trail* object)
(define-extern *blue-shot-trail* light-trail-composition)
;; (define-extern gun-fire-blue-3 function)
;; (define-extern draw-beam-segment function)
;; (define-extern *found-objects* object)
@@ -36295,7 +36281,7 @@
;; (define-extern fire-projectile-if-necessary function)
;; (define-extern *gun-blue-2-targets* object)
;; (define-extern *blue-2-lightning-shape* object)
;; (define-extern *uv-loop-curve* object)
(define-extern *uv-loop-curve* curve2d-piecewise)
;; (define-extern *blue-light-test* object)
;; (define-extern *blue-light-test-end* object)
;; (define-extern *blue-light-test-big* object)
@@ -36307,13 +36293,13 @@
;; (define-extern find-gun-blue-2-target function)
;; (define-extern find-gun-blue-2-target-old function)
;; (define-extern *lightning-pts-cache* object)
;; (define-extern gun-fire-blue-2 function)
;; (define-extern gun-fire-blue-2-old function)
(define-extern gun-fire-blue-2 (function object :behavior target))
(define-extern gun-fire-blue-2-old (function object :behavior target))
(define-extern target-gun-can-fire-blue? (function pickup-type symbol :behavior target))
;; (define-extern *last-fire-blue-time* object)
(define-extern *last-fire-blue-time* time-frame)
(define-extern target-gun-fire-blue (function pickup-type (pointer process) :behavior target))
;; (define-extern gun-blue-shot-move function) ;; (function gun-blue-shot none)
;; (define-extern cshape-reaction-blue-shot function) ;; (function control-info collide-query vector vector collide-status)
(define-extern gun-blue-shot-move (function gun-blue-shot none))
(define-extern cshape-reaction-blue-shot (function control-info collide-query vector vector collide-status))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; gun-yellow-shot ;;
@@ -36486,12 +36472,12 @@
)
(:methods
(init-probes! (_type_ collide-shape) none) ;; 23
(gun-red-shot-method-24 (_type_) none) ;; 24 ;; (gun-red-shot-method-24 (_type_) symbol)
(check-blocked? (_type_) symbol) ;; 24
(stub (_type_) none) ;; 25
(do-collision (_type_) none) ;; 26 ;; (gun-red-shot-method-26 (_type_) none)
(gun-red-shot-method-27 (_type_) none) ;; 27 ;; (gun-red-shot-method-27 (_type_) none)
(gun-red-shot-method-28 (_type_ vector) none) ;; 28 ;; (gun-red-shot-method-28 (_type_ vector) sound-id)
(gun-red-shot-method-29 (_type_ process-drawable touching-shapes-entry) none) ;; 29 ;; (fire! (_type_ process-drawable int) object)
(find-targets (_type_) none) ;; 26
(setup-probes (_type_) none) ;; 27
(do-collision (_type_ vector) none) ;; 28
(send-attack! (_type_ process-drawable touching-shapes-entry) none) ;; 29
)
)
@@ -36580,17 +36566,16 @@
die ;; 16
)
(:methods
(gun-red-2-shockwave-method-17 (_type_) none) ;; 17
(find-targets-and-attack! (_type_) none) ;; 17
(send-attack! (_type_ process-focusable symbol) none) ;; 18
;; adding _type_ here causes decompiler hang
(gun-red-2-shockwave-method-19 () none) ;; 19
(gun-red-2-shockwave-method-20 (_type_) none) ;; 20
(gun-red-2-shockwave-method-21 (_type_) none) ;; 21
(find-collision-point! (_type_) int) ;; 19
(generate-collision-points! (_type_) none) ;; 20
(adjust-height-and-radius (_type_) none) ;; 21
(gun-red-2-shockwave-method-22 (_type_ int int int int) none) ;; 22
(generate-shockwave-particles (_type_) none) ;; 23
(adjust-warp-radius-and-alpha (_type_) object) ;; 24
(adjust-ring-radius-and-alpha (_type_) none) ;; 25
(generate-collision-points (_type_) none) ;; 26
(generate-order-array (_type_) none) ;; 26
(spawn-ring (_type_) none) ;; 27
)
)
@@ -36674,7 +36659,7 @@
(define-extern gun-fire-red-2 (function object :behavior target))
(define-extern red-3-sphere-init-by-other (function red-3-sphere-init-params object :behavior red-3-sphere))
(define-extern gun-fire-red-3 (function gun-red-3-grenade :behavior target))
(define-extern gun-fire-red-1 (function gun-red-shot :behavior target))
(define-extern gun-fire-red-1 (function object :behavior target))
(define-extern target-gun-can-fire-red? (function pickup-type symbol :behavior target))
(define-extern target-gun-fire-red (function pickup-type (pointer process) :behavior target))
(define-extern gun-red-shot-event-handler (function process int symbol event-message-block object :behavior gun-red-shot))
@@ -36684,36 +36669,33 @@
;; gun-dark-shot ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#|
(deftype gun-dark-shot (projectile)
((blast-radius float :offset-assert 512)
(core-position vector :inline :offset-assert 528)
(core-velocity vector :inline :offset-assert 544)
(spin-vector vector :inline :offset-assert 560)
(track-target uint64 :offset-assert 576) ;; handle
(track-target handle :offset-assert 576)
(size-t float :offset-assert 584)
(result-array handle 16 :offset-assert 592) ;; guessed by decompiler
(result-array handle 16 :offset-assert 592)
(result-count int8 :offset-assert 720)
(charge-sound sound-id :offset-assert 724) ;; guessed by decompiler
(fire-sound sound-id :offset-assert 728) ;; guessed by decompiler
(trail-sound sound-id :offset-assert 732) ;; guessed by decompiler
(explode-sound sound-id :offset-assert 736) ;; guessed by decompiler
(start-pilot? basic :offset-assert 740)
(spread-timer uint64 :offset-assert 744)
(charge-sound sound-id :offset-assert 724)
(fire-sound sound-id :offset-assert 728)
(trail-sound sound-id :offset-assert 732)
(explode-sound sound-id :offset-assert 736)
(start-pilot? symbol :offset-assert 740)
(spread-timer time-frame :offset-assert 744)
)
:method-count-assert 43
:size-assert #x2f0
:flag-assert #x2b027002f0
(:state-methods
impact ;; 22
fizzle ;; 42
moving ;; 23
startup ;; 41, old: (fizzle () _type_ :state)
startup ;; 41
fizzle ;; 42
)
)
|#
#|
(deftype gun-dark-3-sphere (process-drawable)
((alpha-val float :offset-assert 200)
)
@@ -36724,9 +36706,7 @@
active ;; 20
)
)
|#
#|
(deftype gun-dark-3-sphere-init-params (structure)
((pos vector :inline :offset-assert 0)
(size-x float :offset-assert 16)
@@ -36737,122 +36717,114 @@
:size-assert #x1c
:flag-assert #x90000001c
)
|#
#|
(deftype last-active-nuke-info (structure)
((last-active-nuke uint64 :offset-assert 0)
((last-active-nuke handle :offset-assert 0)
)
:method-count-assert 9
:size-assert #x8
:flag-assert #x900000008
)
|#
#|
(deftype gun-dark-3-nuke (projectile)
((flash-time uint64 :offset-assert 512)
(blur-time uint64 :offset-assert 520)
(spawned-mushroom-cloud? basic :offset-assert 528)
(strip basic :offset-assert 532)
((flash-time time-frame :offset-assert 512)
(blur-time time-frame :offset-assert 520)
(spawned-mushroom-cloud? symbol :offset-assert 528)
(strip prim-strip :offset-assert 532)
(mushroom-top-pos vector :inline :offset-assert 544)
(warp uint64 :offset-assert 560)
(warp handle :offset-assert 560)
(initial-velocity vector :inline :offset-assert 576)
(start-y float :offset-assert 592)
(y-vel-adjust float :offset-assert 596)
(launch-speed float :offset-assert 600)
(launch-sin-region-start float :offset-assert 604)
(launch-sin-region-end float :offset-assert 608)
(launch-stay-state-time uint64 :offset-assert 616)
(launch-next-state basic :offset-assert 624)
(launch-impact-state basic :offset-assert 628)
(launch-stay-state-time time-frame :offset-assert 616)
(launch-next-state (state gun-dark-3-nuke) :offset-assert 624)
(launch-impact-state (state gun-dark-3-nuke) :offset-assert 628)
(launch-y-scale float :offset-assert 632)
(launch-height-t float :offset-assert 636)
(expected-height float :offset-assert 640)
(total-fly-time uint64 :offset-assert 648)
(total-fly-time time-frame :offset-assert 648)
(num-dying-vehicles uint8 :offset-assert 656)
(num-dying-guards uint8 :offset-assert 657)
(num-dying-civilians uint8 :offset-assert 658)
(last-death-sound-play-time uint64 :offset-assert 664)
(blur-curve basic :offset-assert 672)
(fade-curve basic :offset-assert 676)
(last-death-sound-play-time time-frame :offset-assert 664)
(blur-curve curve2d-piecewise :offset-assert 672)
(fade-curve curve-color-piecewise :offset-assert 676)
(num-blur-segments uint8 :offset-assert 680)
(shook-camera? basic :offset-assert 684)
(hit-wall? basic :offset-assert 688)
(killed-everything? basic :offset-assert 696)
(explode-sound uint32 :offset-assert 700)
(explode-wall-sound uint32 :offset-assert 704)
(played-trail? basic :offset-assert 708)
(smoke-trail basic :offset-assert 712)
(killed-objects UNKNOWN 64 :offset-assert 720)
(shook-camera? symbol :offset-assert 684)
(hit-wall? symbol :offset-assert 688)
(killed-everything? symbol :offset 696)
(explode-sound sound-id :offset-assert 700)
(explode-wall-sound sound-id :offset-assert 704)
(played-trail? symbol :offset-assert 708)
(smoke-trail sparticle-subsampler :offset-assert 712)
(killed-objects handle 64 :offset-assert 720)
(num-killed-objects int32 :offset-assert 1232)
(last-kill-time uint64 :offset-assert 1240)
(last-kill-time time-frame :offset-assert 1240)
)
:method-count-assert 60
:size-assert #x4e0
:flag-assert #x3c046004e0
(:methods
(gun-dark-3-nuke-method-41 () none) ;; 41
(gun-dark-3-nuke-method-51 () none) ;; 51
(gun-dark-3-nuke-method-52 () none) ;; 52
(gun-dark-3-nuke-method-53 () none) ;; 53
(gun-dark-3-nuke-method-54 () none) ;; 54
(gun-dark-3-nuke-method-55 () none) ;; 55
(gun-dark-3-nuke-method-56 () none) ;; 56
(gun-dark-3-nuke-method-57 () none) ;; 57
(gun-dark-3-nuke-method-58 () none) ;; 58
(gun-dark-3-nuke-method-59 () none) ;; 59
)
(:state-methods
wait-for-alive ;; 50
impact-small ;; 47
impact-embedded ;; 49
impact ;; 22
impact-dud ;; 48
launch-3 ;; 46
launch-2 ;; 45
launch-1 ;; 44
launch-0 ;; 43
undefined ;; 41, not defined
launching-base-state ;; 42
launch-0 ;; 43
launch-1 ;; 44
launch-2 ;; 45
launch-3 ;; 46
impact-small ;; 47
impact-dud ;; 48
impact-embedded ;; 49
wait-for-alive ;; 50
)
(:methods
(set-launch-height! (_type_) none) ;; 51
(do-blur-effect (_type_) none) ;; 52
(do-white-screen-effect (_type_) none) ;; 53
(count-casualties (_type_) none) ;; 54
(send-attack! (_type_ process-focusable) none) ;; 55
(play-death-sounds (_type_) none) ;; 56
(do-camera-shake (_type_) none) ;; 57
(do-vibration (_type_) none) ;; 58
(check-for-impact (_type_) none) ;; 59
)
)
|#
#|
(deftype gravity-spinner (process)
((cached-damage float :offset-assert 128)
(end-time uint64 :offset-assert 136)
(time-subtract uint64 :offset-assert 144)
(parent-hand uint64 :offset-assert 152)
(end-time time-frame :offset-assert 136)
(time-subtract time-frame :offset-assert 144)
(parent-hand handle :offset-assert 152)
(rotation-accel vector :inline :offset-assert 160)
(original-sphere-offset sphere :inline :offset-assert 176)
(obj-radius float :offset-assert 192)
(was-hit-previously? basic :offset-assert 196)
(was-hit-previously? symbol :offset-assert 196)
(ground-height float :offset-assert 200)
(next-ground-probe-time uint64 :offset-assert 208)
(next-ground-probe-time time-frame :offset-assert 208)
)
:method-count-assert 25
:size-assert #xd8
:flag-assert #x19006000d8
(:methods
(gravity-spinner-method-16 () none) ;; 16
(gravity-spinner-method-17 () none) ;; 17
(gravity-spinner-method-18 () none) ;; 18
(gravity-spinner-method-19 () none) ;; 19
(gravity-spinner-method-20 () none) ;; 20
(gravity-spinner-method-21 () none) ;; 21
(gravity-spinner-method-22 () none) ;; 22
(gravity-spinner-method-23 () none) ;; 23
(gravity-spinner-method-24 () none) ;; 24
)
(:state-methods
zero-g ;; 14
zero-g-vehicle ;; 15
)
(:methods
(gravity-spinner-method-16 (_type_ vector vector) none) ;; 16
(update-rotation (_type_ symbol) none) ;; 17
(gravity-spinner-method-18 (_type_ process) float) ;; 18
(handle-impact (_type_ symbol) vector) ;; 19
(probe-ground (_type_) none) ;; 20
(get-float-speed (_type_) float) ;; 21
(gravity-spinner-method-22 (_type_) none) ;; 22
(spawn-part (_type_) none) ;; 23
(rotate! (_type_ quaternion) none) ;; 24
)
)
|#
#|
(deftype gravity-ring (process-drawable)
((start-pos vector :inline :offset-assert 208)
(jmod-outer joint-mod-add-local :inline :offset-assert 224)
@@ -36860,67 +36832,68 @@
(ring-scale-t float :offset-assert 352)
(current-radius float :offset-assert 356)
(max-radius float :offset-assert 360)
(reverse? basic :offset-assert 364)
(reverse? symbol :offset-assert 364)
(total-time float :offset-assert 368)
(ring-width float :offset-assert 372)
(stop-time uint64 :offset-assert 376)
(stop-time time-frame :offset-assert 376)
)
:method-count-assert 22
:size-assert #x180
:flag-assert #x1601000180
(:methods
(gravity-ring-method-21 () none) ;; 21
)
(:state-methods
expand ;; 20
)
(:methods
(gravity-ring-method-21 (_type_) none) ;; 21
)
)
|#
#|
(deftype gun-gravity (process-drawable)
((current-radius float :offset-assert 200)
(max-radius float :offset-assert 204)
(lowest-y float :offset-assert 208)
(start-pos vector :inline :offset-assert 224)
(total-time float :offset-assert 240)
(ring-closest uint64 :offset-assert 248)
(ring-furthest uint64 :offset-assert 256)
(gravity-sound uint32 :offset-assert 264)
(ring-closest handle :offset-assert 248)
(ring-furthest handle :offset-assert 256)
(gravity-sound sound-id :offset-assert 264)
)
:method-count-assert 25
:size-assert #x10c
:flag-assert #x190090010c
(:methods
(gun-gravity-method-21 () none) ;; 21
(gun-gravity-method-22 () none) ;; 22
(gun-gravity-method-23 () none) ;; 23
(gun-gravity-method-24 () none) ;; 24
)
(:state-methods
expand ;; 20
)
(:methods
(gun-gravity-method-21 (_type_) none) ;; 21
(gun-gravity-method-22 (_type_ symbol) none) ;; 22
(spawn-gravity-spinner (_type_ process) (pointer gravity-spinner)) ;; 23
(gun-gravity-method-24 (_type_) none) ;; 24
)
)
|#
;; (define-extern sparticle-lightning-2d-spline-align-plus-rotz function)
;; (define-extern gun-fire-dark-1 function)
;; (define-extern gun-dark-3-sphere-init-by-other function)
;; (define-extern *last-active-nuke* object)
;; (define-extern gun-dark-reaction function)
;; (define-extern nuke-move function)
(define-extern market-object type)
(define-extern fruit-stand type)
(define-extern missile-bot type)
(define-extern sparticle-lightning-2d-spline-align-plus-rotz (function object sparticle-cpuinfo sprite-vec-data-2d object none))
(define-extern gun-fire-dark-1 (function (pointer process) :behavior target))
(define-extern gun-dark-3-sphere-init-by-other (function gun-dark-3-sphere-init-params object :behavior gun-dark-3-sphere))
(define-extern *last-active-nuke* last-active-nuke-info)
(define-extern gun-dark-reaction (function control-info collide-query vector vector collide-status))
(define-extern nuke-move (function object :behavior gun-dark-3-nuke))
(define-extern target-gun-can-fire-dark? (function pickup-type symbol :behavior target))
;; (define-extern gun-fire-dark-3 function)
;; (define-extern process-drawable-shock-effect-bullseye function) ;; (function process-focusable process-focusable matrix int sparticle-launcher sparticle-launcher sparticle-launcher none)
;; (define-extern gun-dark-shot-init-fizzle function) ;; (function vector none :behavior gun-dark-shot)
;; (define-extern *gravity-origin-pos* object)
;; (define-extern gravity-spinner-init-by-other function)
;; (define-extern zero-g-wait-for-land function)
;; (define-extern *zero-g-fake-attack-vec* object)
;; (define-extern *gun-gravity-shadow-control* shadow-control)
;; (define-extern gravity-ring-init-by-other function)
;; (define-extern gun-gravity-init-by-other function)
;; (define-extern gun-fire-dark-2 function)
(define-extern gun-fire-dark-3 (function (pointer process) :behavior target))
(define-extern process-drawable-shock-effect-bullseye (function process-focusable process-focusable lightning-spec (function lightning-tracker none) sparticle-launcher sparticle-launcher sparticle-launcher none))
(define-extern gun-dark-shot-init-fizzle (function vector none :behavior gun-dark-shot))
(define-extern *gravity-origin-pos* vector)
(define-extern gravity-spinner-init-by-other (function handle object time-frame object :behavior gravity-spinner))
(define-extern zero-g-wait-for-land (function object :behavior gravity-spinner))
(define-extern *zero-g-fake-attack-vec* vector)
(define-extern *gun-gravity-shadow-control* shadow-control)
(define-extern gravity-ring-init-by-other (function vector symbol float float float time-frame object :behavior gravity-ring))
(define-extern gun-gravity-init-by-other (function vector vector object :behavior gun-gravity))
(define-extern gun-fire-dark-2 (function (pointer process) :behavior target))
(define-extern target-gun-fire-dark (function pickup-type (pointer process) :behavior target))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -37469,45 +37442,45 @@
)
(define-extern *spawn-actors* symbol)
;; (define-extern *compact-actors* object) ;; symbol
;; (define-extern *vis-actors* object) ;; symbol
(define-extern *compact-actors* symbol)
(define-extern *vis-actors* symbol)
(define-extern entity-by-name (function string entity))
(define-extern entity-by-type (function type entity-actor))
(define-extern entity-by-aid (function uint entity))
(define-extern entity-actor-from-level-name (function symbol entity-actor))
;; (define-extern entity-nav-mesh-by-aid function) ;; (function actor-id entity-nav-mesh)
;; (define-extern nav-mesh-from-res-tag function) ;; (function entity symbol int nav-mesh)
;; (define-extern entity-by-meters function) ;; (function float float float entity-actor)
;; (define-extern process-by-ename function) ;; (function string process)
;; (define-extern entity-process-count function) ;; (function symbol int)
;; (define-extern entity-count function) ;; (function int)
;; (define-extern entity-remap-names function) ;; (function pair none)
;; (define-extern process-status-bits function) ;; (function process symbol none)
(define-extern entity-nav-mesh-by-aid (function actor-id entity-nav-mesh))
(define-extern nav-mesh-from-res-tag (function entity symbol int nav-mesh))
(define-extern entity-by-meters (function float float float entity-actor))
(define-extern process-by-ename (function string process))
(define-extern entity-process-count (function symbol int))
(define-extern entity-count (function int))
(define-extern entity-remap-names (function pair none))
(define-extern process-status-bits (function process symbol none))
(define-extern process-entity-set! (function process entity entity))
(define-extern process-task-mask (function process task-mask))
;; (define-extern update-actor-vis-box function) ;; (function process-drawable vector vector none)
;; (define-extern expand-bounding-box function) ;; (function vector vector vector vector none)
;; (define-extern expand-bounding-box-from-nav-meshes function)
;; (define-extern expand-vis-box-with-point function) ;; (function entity vector none)
;; (define-extern *debug-actor-info* debug-actor-info) ;; debug-actor-info
;; (define-extern *pid-string* object) ;; string
;; (define-extern debug-actor function) ;; (function string none)
;; (define-extern debug-actor-process function)
;; (define-extern draw-actor-marks function) ;; (function process none)
(define-extern update-actor-vis-box (function process-drawable vector vector none))
(define-extern expand-bounding-box (function vector vector vector vector none))
(define-extern expand-bounding-box-from-nav-meshes (function entity vector vector object))
(define-extern expand-vis-box-with-point (function entity vector none))
(define-extern *debug-actor-info* debug-actor-info)
(define-extern *pid-string* string)
(define-extern debug-actor (function string none))
(define-extern debug-actor-process (function process none))
(define-extern draw-actor-marks (function process none))
(define-extern init-entity (function process entity-actor type none))
;; (define-extern entity-deactivate-handler function) ;; (function process entity-actor none)
;; (define-extern check-for-rougue-process function) ;; (function process int int level none)
;; (define-extern process-drawable-scale-from-entity! function) ;; (function process-drawable entity none)
(define-extern entity-deactivate-handler (function process entity-actor none))
(define-extern check-for-rougue-process (function process int int level none))
(define-extern process-drawable-scale-from-entity! (function process-drawable entity none))
(define-extern process-drawable-from-entity! (function process-drawable entity-actor none))
(define-extern reset-actors (function symbol none))
(define-extern reset-cameras (function none))
(define-extern entity-birth-no-kill (function entity process))
;; (define-extern entity-task-complete-on function) ;; (function entity none)
;; (define-extern entity-task-complete-off function) ;; (function entity none)
(define-extern entity-task-complete-on (function entity none))
(define-extern entity-task-complete-off (function entity none))
(define-extern process-entity-status! (function process entity-perm-status symbol entity-perm-status))
(define-extern find-nearest-entity (function vector type entity))
;; (define-extern entity-speed-test function) ;; (function string entity)
;; (define-extern dump-entity-remap function) ;; (function object object none)
(define-extern entity-speed-test (function string entity))
(define-extern dump-entity-remap (function object object none))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; path ;;
@@ -210,6 +210,16 @@
[12, "(function object :behavior target)"]
],
"gun-yellow-shot": [[59, "(function handle object :behavior process)"]],
"gun-dark-shot": [
[25, "(function collide-shape-prim none :behavior gravity-spinner)"],
[34, "(function handle float object :behavior process)"]
],
"entity": [
[11, "(function process object)"],
[16, "(function process object)"],
[57, "(function process object)"],
[61, "(function process object)"]
],
"memory-usage": [
[2, "(function process-drawable symbol)"],
[3, "(function basic symbol)"]
@@ -14,7 +14,8 @@
"wings": "jakb-ag",
"lightjak-shield": "jakb-ag",
"freeze-screen": "collectables-ag",
"red-3-sphere": "gun-ag"
"red-3-sphere": "gun-ag",
"gun-dark-3-sphere": "gun-ag"
},
// remap names for types in an entire file (higher priority)
+3 -2
View File
@@ -114,7 +114,6 @@
"(method 33 rub-tower)",
"(method 261 crimson-guard)",
"(anon-function 25 volcanox-obs)",
"find-nearest-entity",
"foreground-draw-hud"
],
@@ -354,7 +353,9 @@
"(method 11 rigid-body-queue)": [0, 6, 7, 9],
"(method 10 rigid-body-queue)": [10, 34, 37],
"(method 9 los-control)": [0, 43],
"load-game-text-info": [19, 20, 21]
"load-game-text-info": [19, 20, 21],
"draw-actor-marks": [8],
"find-nearest-entity": [7, 9]
},
// Sometimes the game might use format strings that are fetched dynamically,
@@ -457,5 +457,38 @@
["L443", "uint64", true],
["L405", "attack-info"],
["L450", "uint64", true]
]
],
"gun-dark-shot": [
["L824", "uint64", true],
["L827", "uint64", true],
["L823", "uint64", true],
["L826", "uint64", true],
["L828", "uint64", true],
["L829", "uint64", true],
["L825", "uint64", true],
["L830", "uint64", true],
["L707", "uint64", true],
["L704", "uint64", true],
["L702", "uint64", true],
["L701", "uint64", true],
["L700", "uint64", true],
["L710", "uint64", true],
["L648", "attack-info"],
["L647", "attack-info"],
["L638", "attack-info"],
["L637", "attack-info"],
["L639", "attack-info"],
["L708", "uint64", true],
["L643", "attack-info"],
["L644", "attack-info"],
["L712", "uint64", true],
["L711", "uint64", true],
["L709", "uint64", true],
["L664", "attack-info"],
["L703", "uint64", true],
["L699", "uint64", true],
["L705", "uint64", true],
["L706", "uint64", true]
],
"gun-part": [["L537", "(pointer rgba)", 36]]
}
@@ -487,7 +487,12 @@
[16, "vector"],
[1584, "collide-query"]
],
"(method 19 gun-red-2-shockwave)": [[16, "collide-query"]],
"(method 19 gun-red-2-shockwave)": [
[16, "collide-query"],
[576, "vector"],
[624, "vector"],
[592, "vector"]
],
"(method 23 gun-red-2-shockwave)": [[32, "vector"]],
"(method 24 gun-red-2-shockwave)": [[16, "vector"]],
"gun-fire-red-2": [[16, "gun-red-2-shockwave-init-params"]],
@@ -497,5 +502,48 @@
[128, "vector"],
[1696, "vector"]
],
"(method 26 gun-red-shot)": [[16, "bounding-box"]]
"(method 26 gun-red-shot)": [[16, "bounding-box"]],
"gun-dark-reaction": [[112, "vector"]],
"gun-fire-red-1": [
[16, "vector"],
[32, "event-message-block"],
[112, "vector"]
],
"(trans expand gun-gravity)": [
[16, "vector"],
[32, "vector"],
[48, "vector"],
[80, "collide-query"],
[624, "matrix"]
],
"gun-fire-dark-3": [[16, "projectile-init-by-other-params"]],
"(trans moving gun-dark-shot)": [[16, "vector"]],
"(enter impact gun-dark-shot)": [
[192, ["array", "collide-shape", 384]],
[96, "vector"]
],
"gravity-spinner-init-by-other": [[32, "vector"]],
"(code zero-g gravity-spinner)": [[112, "vector"]],
"(method 25 gun-dark-3-nuke)": [[16, "matrix"]],
"(code impact-dud gun-dark-3-nuke)": [[16, "explosion-init-params"]],
"(method 54 gun-dark-3-nuke)": [
[32, ["array", "collide-shape", 384]],
[16, "vector"]
],
"(trans impact gun-dark-3-nuke)": [
[96, "gun-dark-3-sphere-init-params"],
[128, "gun-dark-3-sphere-init-params"]
],
"(method 19 gravity-spinner)": [
[176, ["array", "collide-shape", 384]],
[128, "vector"],
[112, "vector"],
[1712, "vector"],
[2288, "vector"]
],
"(method 16 gravity-spinner)": [[32, "vector"]],
"(method 22 gun-gravity)": [
[112, ["array", "collide-shape", 384]],
[16, "vector"]
]
}
+266 -14
View File
@@ -3090,7 +3090,10 @@
[707, "v0", "sound-rpc-set-param"],
[586, "v0", "sound-rpc-set-param"]
],
"(trans play-anim scene-player)": [[66, "a0", "process-drawable"]],
"(trans play-anim scene-player)": [
[71, "v1", "process-drawable"],
[78, "v1", "process-drawable"]
],
"(event play-anim scene-player)": [
[11, "t9", "(function scene-player none)"]
],
@@ -3379,8 +3382,8 @@
[20, "a0", "process-focusable"]
],
"scene-player-init": [
[44, "a0", "(array scene)"],
[37, "s5", "(array scene)"]
[[37, 44], "s5", "(array scene)"],
[83, "v0", "(array scene)"]
],
"(method 34 process-taskable)": [
[58, "v0", "joint"],
@@ -3486,12 +3489,15 @@
[52, "v1", "collide-shape-prim"],
[62, "s2", "gun-yellow-shot-2"],
[58, "v1", "gun-yellow-shot-2"],
[68, "s2", "gun-yellow-shot-2"]
[68, "s2", "gun-yellow-shot-2"],
[[9, 66], "s3", "handle"]
],
"gun-yellow-shot-do-deflect": [
[134, "s1", "process-focusable"],
[178, "s1", "process-focusable"],
["_stack_", 136, "handle"]
["_stack_", 136, "handle"],
["_stack_", 1716, "float"],
["_stack_", 1748, "float"]
],
"gun-fire-yellow-1": [[33, "v0", "process"]],
"gun-fire-yellow-2": [[33, "v0", "process"]],
@@ -3523,7 +3529,11 @@
[59, "a0", "process-focusable"],
[63, "a0", "process-focusable"],
[82, "a0", "process-focusable"],
[85, "a0", "process-focusable"]
[85, "a0", "process-focusable"],
["_stack_", 1688, "float"],
["_stack_", 1692, "float"],
["_stack_", 1752, "float"],
["_stack_", 1756, "float"]
],
"(method 47 gun-red-3-grenade)": [
[53, "s1", "process-focusable"],
@@ -3541,18 +3551,15 @@
[246, "s1", "process-focusable"],
[436, "gp", "process-focusable"],
[440, "a0", "process-focusable"],
["_stack_", 28, "float"]
["_stack_", 28, "float"],
[168, "gp", "process-focusable"],
[314, "s1", "process-focusable"]
],
"gun-fire-red-1": [
[147, "v1", "manipy"],
[191, "v1", "manipy"],
[194, "v1", "manipy"]
// decompiler hang
// [
// 197,
// "v1",
// "manipy"
// ]
[194, "v1", "manipy"],
[197, "v1", "manipy"]
],
"(method 23 gun-red-shot)": [[10, "s4", "process-focusable"]],
"(method 26 gun-red-shot)": [
@@ -3562,6 +3569,251 @@
[93, "a0", "collide-shape"]
],
"(trans charging gun-red-2-shockwave)": [[6, "a1", "process-drawable"]],
"gun-fire-dark-1": [[38, "v0", "process"]],
"(event active gun-dark-3-sphere)": [
[[3, 35], "v1", "gun-dark-3-sphere-init-params"]
],
"gun-fire-dark-3": [[64, "v0", "process"]],
"(exit startup gun-dark-shot)": [[20, "v0", "sound-rpc-set-param"]],
"(code startup gun-dark-shot)": [[88, "a1", "process-focusable"]],
"(enter moving gun-dark-shot)": [[22, "a1", "process-focusable"]],
"(trans moving gun-dark-shot)": [
[27, "s2", "process-focusable"],
[39, "a0", "process-focusable"],
[42, "a0", "process-focusable"]
],
"(enter impact gun-dark-shot)": [
[245, "s1", "process-focusable"],
[256, "s1", "process-focusable"],
[262, "s1", "process-focusable"],
[201, "v0", "(array float)"]
],
"(method 20 gravity-spinner)": [
[19, "s5", "process-focusable"],
[63, "s5", "process-focusable"]
],
"(method 21 gravity-spinner)": [
[19, "s5", "process-focusable"],
[26, "s5", "process-focusable"]
],
"(anon-function 34 gun-dark-shot)": [
[134, "s5", "process-focusable"],
[137, "s5", "process-focusable"],
[141, "s5", "process-focusable"],
[144, "s5", "process-focusable"],
[162, "s5", "process-focusable"],
[167, "s5", "process-focusable"],
[170, "s5", "process-focusable"]
],
"gravity-spinner-init-by-other": [
[33, "gp", "process-focusable"],
[39, "gp", "process-focusable"],
[47, "gp", "process-focusable"],
[54, "gp", "process-focusable"],
[69, "gp", "process-focusable"],
[73, "gp", "process-focusable"],
[77, "gp", "process-focusable"],
[94, "gp", "process-focusable"],
[100, "gp", "process-focusable"],
[113, "gp", "process-focusable"],
[144, "v1", "float"],
[182, "v1", "float"]
],
"(code zero-g gravity-spinner)": [
[71, "gp", "process-focusable"],
[100, "gp", "process-focusable"],
[104, "gp", "process-focusable"],
[137, "gp", "process-focusable"],
[144, "gp", "process-focusable"],
[165, "gp", "process-focusable"],
[174, "v1", "collide-shape-moving"],
[262, "gp", "process-focusable"],
[270, "gp", "process-focusable"],
[285, "gp", "process-focusable"],
[176, "v1", "collide-shape-moving"]
],
"(enter zero-g gravity-spinner)": [[17, "v1", "float"]],
"(event zero-g gravity-spinner)": [
[105, "a0", "attack-info"],
[109, "v1", "attack-info"],
[168, "s4", "process-drawable"],
[170, "s4", "process-drawable"],
[182, "s4", "process-drawable"],
[184, "s4", "process-drawable"],
[177, "s4", "process-drawable"],
["_stack_", 36, "float"]
],
"zero-g-wait-for-land": [
[22, "s5", "process-focusable"],
[26, "s5", "process-focusable"],
[33, "s5", "process-focusable"],
[42, "s5", "process-focusable"],
[52, "s5", "process-focusable"],
[53, "a0", "collide-shape-moving"],
[61, "s5", "process-focusable"],
[72, "s5", "process-focusable"],
[84, "s5", "process-focusable"],
[99, "s5", "process-focusable"],
[108, "s5", "process-focusable"]
],
"(enter zero-g-vehicle gravity-spinner)": [[17, "v1", "float"]],
"(enter launch-0 gun-dark-3-nuke)": [[15, "t9", "(function none)"]],
"(enter launch-1 gun-dark-3-nuke)": [[12, "t9", "(function none)"]],
"(enter launch-2 gun-dark-3-nuke)": [[18, "t9", "(function none)"]],
"(code impact-dud gun-dark-3-nuke)": [[39, "a0", "process"]],
"(method 54 gun-dark-3-nuke)": [[47, "s1", "process-focusable"]],
"(method 22 gravity-spinner)": [
[18, "s3", "process-focusable"],
[24, "s3", "process-focusable"],
[29, "s3", "process-focusable"]
],
"(method 23 gravity-spinner)": [
[25, "gp", "process-focusable"],
[29, "gp", "process-focusable"],
[35, "gp", "process-focusable"],
[44, "gp", "process-focusable"]
],
"(method 19 gravity-spinner)": [
[40, "s5", "process-focusable"],
[68, "s5", "process-focusable"],
[377, "s5", "process-focusable"],
[435, "s5", "process-focusable"],
[113, "a0", "process-focusable"],
[124, "a0", "process-focusable"],
[131, "a0", "process-focusable"],
[134, "a0", "process-focusable"],
[200, "s5", "process-focusable"],
["_stack_", 148, "process"],
["_stack_", 156, "float"],
["_stack_", 160, "float"],
["_stack_", 172, "float"],
["_stack_", 1736, "float"],
["_stack_", 2312, "float"]
],
"(method 16 gravity-spinner)": [
[22, "s4", "process-focusable"],
[43, "s4", "process-focusable"]
],
"(method 17 gravity-spinner)": [
[101, "s4", "process-focusable"],
[127, "s4", "process-focusable"],
[149, "s4", "process-focusable"]
],
"(method 24 gravity-spinner)": [
[19, "s5", "process-focusable"],
[26, "s5", "process-focusable"],
[42, "s5", "process-focusable"],
[47, "s5", "process-focusable"],
[52, "s5", "process-focusable"],
[55, "s5", "process-focusable"],
[66, "s5", "process-focusable"],
[59, "s5", "process-focusable"],
[61, "s5", "process-focusable"]
],
"(trans expand gun-gravity)": [
[116, "v1", "float"],
[149, "v1", "float"]
],
"(method 22 gun-gravity)": [
[14, "v0", "process"],
[35, "v1", "gravity-ring"],
[36, "v1", "gravity-ring"],
[[51, 53], "v1", "gravity-ring"],
[101, "s1", "process-focusable"],
[113, "s1", "process-focusable"]
],
"process-drawable-shock-effect-bullseye": [[85, "a0", "lightning-tracker"]],
"(method 14 level-group)": [
[62, "a0", "entity-actor"],
[66, "a0", "entity-actor"]
],
"(method 23 level-group)": [[28, "v0", "(inline-array vector)"]],
"expand-bounding-box-from-nav-meshes": [["_stack_", 16, "res-tag"]],
"expand-vis-box-with-point": [[10, "v0", "(inline-array vector)"]],
"(method 25 level-group)": [
[24, "s3", "entity-actor"],
[112, "s3", "entity-actor"],
[120, "s3", "entity-actor"],
[143, "v0", "string"],
[56, "v0", "string"],
[99, "v0", "(inline-array vector)"]
],
"process-drawable-scale-from-entity!": [[11, "v0", "vector"]],
"reset-actors": [
[174, "t9", "(function level none)"],
[162, "v0", "(function level none)"]
],
"process-status-bits": [[8, "s5", "process-drawable"]],
"(method 24 level-group)": [
[127, "v0", "(pointer actor-group)"],
[28, "v0", "(inline-array vector)"],
["_stack_", 28, "float"],
["_stack_", 32, "float"]
],
"(method 15 level-group)": [
[262, "s0", "process-drawable"],
[268, "s0", "process-drawable"],
[275, "s0", "process-drawable"],
[277, "s0", "process-drawable"],
[308, "s4", "process-drawable"],
[663, "a0", "drawable-region-prim"],
[666, "a0", "drawable-region-prim"],
[726, "a0", "drawable-region-prim"],
[729, "a0", "drawable-region-prim"]
],
"check-for-rougue-process": [
[133, "gp", "part-tracker"],
[157, "gp", "part-spawner"],
[184, "v1", "process-drawable"],
[187, "v1", "process-drawable"],
[192, "v1", "process-drawable"],
[199, "v1", "process-drawable"],
[209, "v1", "process-drawable"],
[212, "v1", "process-drawable"],
[217, "v1", "process-drawable"],
[224, "v1", "process-drawable"]
],
"draw-actor-marks": [
[20, "gp", "process-drawable"],
[29, "gp", "process-drawable"],
[33, "gp", "process-drawable"],
[40, "gp", "process-drawable"],
[45, "gp", "process-drawable"],
[47, "gp", "process-drawable"],
[52, "gp", "process-drawable"],
[54, "gp", "process-drawable"],
[59, "gp", "process-drawable"],
[67, "gp", "process-drawable"],
[69, "gp", "process-drawable"],
[78, "gp", "process-drawable"],
[106, "gp", "process-drawable"],
[105, "v0", "string"],
[131, "v0", "(pointer int32)"],
[155, "gp", "process-drawable"],
[174, "v0", "string"],
[187, "gp", "process-drawable"],
[271, "gp", "process-drawable"],
[250, "gp", "process-drawable"],
[208, "v0", "(inline-array vector)"],
[120, "a2", "string"]
],
"(anon-function 57 entity)": [
[6, "gp", "process-drawable"],
[8, "gp", "process-drawable"],
[13, "gp", "process-drawable"],
[15, "gp", "process-drawable"]
],
"draw-subtitle-image": [
[[163, 194], "v1", "(pointer uint128)"],
[[195, 199], "t0", "vector4w"],
[[199, 206], "t0", "vector4w"],
[[206, 213], "a2", "vector4w"],
[[214, 220], "v1", "vector4w"],
[[223, 254], "v1", "(pointer uint128)"],
[[255, 266], "t0", "vector4w"],
[[266, 273], "a1", "vector4w"],
[[274, 280], "v1", "vector4w"]
],
"command-get-float": [
[20, "gp", "bfloat"]
],
@@ -1968,5 +1968,20 @@
"s4-0": "i",
"v1-7": "debris"
}
},
"(enter burnt-husk gun-yellow-3-saucer)": {
"vars": {
"s5-0": ["name", "sound-name"]
}
},
"reset-actors": {
"vars": {
"s5-0": ["perm", "entity-perm-status"]
}
},
"(method 24 level-group)": {
"vars": {
"a0-9": ["enemy-option", "enemy-option"]
}
}
}
+3 -23
View File
@@ -153,18 +153,8 @@
(new 'static 'game-option :option-type (game-option-type on-off) :name (text-id vsync) :scale #t)
(new 'static 'game-option :option-type (game-option-type menu) :name (text-id aspect-ratio) :scale #t :param3 (game-option-menu aspect-ratio))
(new 'static 'game-option :option-type (game-option-type msaa) :name (text-id msaa) :scale #t)
(new 'static 'game-option :option-type (game-option-type frame-rate) :name (text-id frame-rate) :scale #t)
(new 'static 'game-option :option-type (game-option-type menu) :name (text-id ps2-options) :scale #t :param3 (game-option-menu gfx-ps2-options))
(new 'static 'game-option :option-type (game-option-type button) :name (text-id back) :scale #t)
)
)
(define *graphic-options-no-frame-rate-pc* (new 'static 'boxed-array :type game-option
(new 'static 'game-option :option-type (game-option-type menu) :name (text-id game-resolution) :scale #t :param3 (game-option-menu resolution))
(new 'static 'game-option :option-type (game-option-type display-mode) :name (text-id display-mode) :scale #t)
(new 'static 'game-option :option-type (game-option-type on-off) :name (text-id vsync) :scale #t)
(new 'static 'game-option :option-type (game-option-type menu) :name (text-id aspect-ratio) :scale #t :param3 (game-option-menu aspect-ratio))
(new 'static 'game-option :option-type (game-option-type msaa) :name (text-id msaa) :scale #t)
(new 'static 'game-option :option-type (game-option-type frame-rate) :name (text-id frame-rate) :scale #t
:option-disabled-func (lambda () (or (-> *pc-settings* speedrunner-mode?) (<= (pc-get-active-display-refresh-rate) 60))))
(new 'static 'game-option :option-type (game-option-type menu) :name (text-id ps2-options) :scale #t :param3 (game-option-menu gfx-ps2-options))
(new 'static 'game-option :option-type (game-option-type button) :name (text-id back) :scale #t)
)
@@ -884,9 +874,6 @@
(set! (-> *options-remap* (progress-screen graphic-settings)) *graphic-options-pc*)
(set! *carousell-frame-rate* *carousell-frame-rate-100fps*)
)
(else
(set! (-> *options-remap* (progress-screen graphic-settings)) *graphic-options-no-frame-rate-pc*)
)
))
(set! (-> *options-remap* (progress-screen sound-settings)) *sound-options-pc*)
@@ -975,13 +962,6 @@
(set! (-> *graphic-options-pc* 3 value-to-modify) (&-> *pc-settings* vsync?))
(set! (-> *graphic-options-pc* 5 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-pc* 6 value-to-modify) (&-> *progress-carousell* int-backup))
;; disable changes to frame-rate while in speedrunner mode
;; todo move this to the creation
(set! (-> *graphic-options-pc* 6 option-disabled-func) (lambda () (-> *pc-settings* speedrunner-mode?)))
(set! (-> *graphic-options-no-frame-rate-pc* 1 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-no-frame-rate-pc* 2 value-to-modify) (&-> *pc-settings* vsync?))
(set! (-> *graphic-options-no-frame-rate-pc* 4 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *misc-options* 0 value-to-modify) (&-> *pc-settings* money-starburst?))
(set! (-> *misc-options* 1 value-to-modify) (&-> *pc-settings* discord-rpc?))
@@ -2442,7 +2422,7 @@
)
)
(else
;; this option is not selected :-(
;; this option is not selected
(case (-> options index option-type)
(((game-option-type slider)
(game-option-type aspect-ratio)
+2
View File
@@ -5,5 +5,7 @@
;; name in dgo: cam-debug
;; dgos: GAME
(define-extern camera-plot-float-func (function float float float float (function float float) vector4w none))
;; DECOMP BEGINS
@@ -341,7 +341,7 @@ Most [[process-drawable]]s have a [[collide-shape]] that represents their root t
(send-shoves (_type_ process touching-shapes-entry float float float) symbol)
(above-ground? (_type_ collide-query vector collide-spec float float float) symbol)
(water-info-init! (_type_ water-info collide-action) water-info)
(collide-shape-method-53 () none)
(iterate-prims (_type_ (function collide-shape-prim none)) none)
(collide-shape-method-54 () none)
)
)
+3 -3
View File
@@ -60,7 +60,7 @@
(default-loop-behavior uint64)
)
(:methods
(curve2d-piecewise-method-10 (_type_ int symbol uint) none)
(curve2d-piecewise-method-10 (_type_ int symbol int) none)
(curve2d-piecewise-method-11 (_type_) none)
)
)
@@ -115,7 +115,7 @@
)
(defmethod curve2d-piecewise-method-10 ((this curve2d-piecewise) (arg0 int) (arg1 symbol) (arg2 uint))
(defmethod curve2d-piecewise-method-10 ((this curve2d-piecewise) (arg0 int) (arg1 symbol) (arg2 int))
(set! (-> this pts) ((method-of-type float-pair-array new) arg1 float-pair-array arg0))
(set! (-> this default-loop-behavior) (the-as uint (if arg2
0
@@ -456,7 +456,7 @@
(when (or (zero? *curve-linear-up-hold*) (!= loading-level global))
(set! *curve-linear-up-hold* (new 'loading-level 'curve2d-piecewise))
(curve2d-piecewise-method-10 *curve-linear-up-hold* 2 'loading-level (the-as uint #f))
(curve2d-piecewise-method-10 *curve-linear-up-hold* 2 'loading-level (the-as int #f))
)
(set! (-> *curve-linear-up-hold* pts data 0 first) 0.0)
@@ -1696,7 +1696,7 @@
)
)
)
(set! (-> self sound) (sound-play-by-spec (the-as sound-spec gp-1) (new-sound-id) s5-1))
(set! (-> self sound) (sound-play-by-spec gp-1 (new-sound-id) s5-1))
)
)
)
+3 -3
View File
@@ -67,7 +67,7 @@
(when (or (zero? *water-simple-alpha-curve-in*) (!= loading-level global))
(set! *water-simple-alpha-curve-in* (new 'loading-level 'curve2d-piecewise))
(curve2d-piecewise-method-10 *water-simple-alpha-curve-in* 2 'loading-level (the-as uint #f))
(curve2d-piecewise-method-10 *water-simple-alpha-curve-in* 2 'loading-level (the-as int #f))
)
(set! (-> *water-simple-alpha-curve-in* pts data 0 first) 0.0)
@@ -80,7 +80,7 @@
(when (or (zero? *growing-curve*) (!= loading-level global))
(set! *growing-curve* (new 'loading-level 'curve2d-piecewise))
(curve2d-piecewise-method-10 *growing-curve* 2 'loading-level (the-as uint #f))
(curve2d-piecewise-method-10 *growing-curve* 2 'loading-level (the-as int #f))
)
(set! (-> *growing-curve* pts data 0 first) 0.0)
@@ -93,7 +93,7 @@
(when (or (zero? *water-simple-alpha-curve-fade-out*) (!= loading-level global))
(set! *water-simple-alpha-curve-fade-out* (new 'loading-level 'curve2d-piecewise))
(curve2d-piecewise-method-10 *water-simple-alpha-curve-fade-out* 2 'loading-level (the-as uint #f))
(curve2d-piecewise-method-10 *water-simple-alpha-curve-fade-out* 2 'loading-level (the-as int #f))
)
(set! (-> *water-simple-alpha-curve-fade-out* pts data 0 first) 0.0)
+2 -1
View File
@@ -40,6 +40,7 @@
(define-extern init-entity (function process entity-actor type none))
(define-extern entity-by-type (function type entity-actor))
(define-extern entity-actor-from-level-name (function symbol entity-actor))
(define-extern birth-viewer (function process entity-actor object))
(define-extern *spawn-actors* symbol)
@@ -91,7 +92,7 @@
(task game-task :overlay-at (-> perm task))
)
(:methods
(entity-links-method-9 () none)
(birth? (_type_ vector) symbol)
)
)
+305
View File
@@ -7,3 +7,308 @@
;; DECOMP BEGINS
;; TODO stub
(define *entity-info* (new 'static 'boxed-array :type entity-info
(new 'static 'entity-info
:ptype (type-ref factory-boss :method-count 31)
:pool '*16k-dead-pool*
:heap-size #x8000
)
(new 'static 'entity-info
:ptype (type-ref flitter-spawner :method-count 22)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref bubbles-path :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x8000
)
(new 'static 'entity-info
:ptype (type-ref desert-chase-ring :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref bt-grunt :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref bt-roboguard :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref w-parking-spot :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref min-elevator :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref tpl-bouncer :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref veger-npc :method-count 40)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref seem-npc :method-count 40)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref krimson-wall :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref kleever-catch-lizards :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref kleever-npc :method-count 40)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref damus-npc :method-count 40)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref nav-graph :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref tizard :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref ladder :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mh-centipede :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref dark-tower :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref curve-bubbles-Shape :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-tower-door :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-grunt-egg-d :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-grunt-egg-c :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref a :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-grunt-egg-b :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-grund-egg-a :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-de-tower-undervines :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-vine-wriggler-big :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-vine-wriggler :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-twitch-blade :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-claw-finger-small :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-vein-writhing-small :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-vein-writhing-large :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-dark-eco-nodule :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-dark-eco-door :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-puffer-large :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref mhcity-puffer :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref a :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref searchlight :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref ctyn-lamp :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref burning-bush :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref sail-boat-a :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref barge :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref boat-manager :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref propa :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref city-window-a :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref cty-window-a :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref parking-spot :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref security-wall :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref cty-guard-turret :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref cty-fruit-stand :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref fruit-stand :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref torn :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
(new 'static 'entity-info
:ptype (type-ref neon-baron :method-count 0)
:pool '*16k-dead-pool*
:heap-size #x4000
)
)
)
(defun entity-info-lookup ((arg0 type))
(the-as entity-info (cond
((nonzero? (-> arg0 method-table 13))
(-> arg0 method-table 13)
)
(else
(let ((v1-1 *entity-info*))
(dotimes (a1-0 (-> v1-1 length))
(let ((a2-3 (-> v1-1 a1-0 ptype)))
(when (if (logtest? (the-as int a2-3) 1)
(= (-> arg0 symbol) a2-3)
(= arg0 a2-3)
)
(set! (-> arg0 method-table 13) (the-as function (-> v1-1 a1-0)))
(return (the-as entity-info (-> v1-1 a1-0)))
)
)
)
)
(set! (-> arg0 method-table 13) #f)
(the-as basic #f)
)
)
)
)
File diff suppressed because it is too large Load Diff
@@ -68,7 +68,7 @@
(radius float)
(duration float)
(duration-rand float)
(sound symbol)
(sound sound-spec)
(delay float)
(delay-rand float)
)
@@ -33,6 +33,9 @@
)
)
(define-extern sparticle-2d-spline-align-instant (function object sparticle-cpuinfo sprite-vec-data-2d object none))
(define-extern rot-to-particle (function degrees sprite-vec-data-2d matrix none))
;; DECOMP BEGINS
;; TODO: stub
+3
View File
@@ -9,6 +9,7 @@
(declare-type bsp-node structure)
(declare-type entity-camera entity)
(declare-type entity-nav-mesh structure)
(declare-type entity-race-mesh entity)
(declare-type city-level-info structure)
(define-extern inspect-bsp-tree (function bsp-header bsp-node none))
@@ -67,9 +68,11 @@ This probably started as a very simple structure, but now it is extremely compli
(cam-box-idx uint16)
(subdivide-close float :offset 160)
(subdivide-far float)
(race-meshes (array entity-race-mesh))
(actor-birth-order (pointer uint32) :offset 172)
(light-hash light-hash)
(nav-meshes (array entity-nav-mesh))
(actor-groups (array actor-group))
(region-trees (array drawable-tree-region-prim) :offset 188)
(collide-hash collide-hash :offset 196)
(wind-array uint32 :offset 200)
+17 -4
View File
@@ -114,6 +114,19 @@
(movie0 16)
(movie1 17)
(movie2 18)
(tm19 19)
(tm20 20)
(tm21 21)
(tm22 22)
(tm23 23)
(tm24 24)
(tm25 25)
(tm26 26)
(tm27 27)
(tm28 28)
(tm29 29)
(tm30 30)
(tm31 31)
)
;; ---task-mask
@@ -475,7 +488,7 @@
(get-level-by-heap-ptr-and-status (_type_ pointer symbol) level)
(level-get-for-use (_type_ symbol symbol) level)
(activate-levels! (_type_) int)
(level-group-method-14 () none)
(debug-print-entities (_type_ symbol type string) none)
(debug-draw-actors (_type_ symbol) none)
(assign-draw-indices (_type_) none)
(actors-update (_type_) none)
@@ -484,9 +497,9 @@
(level-get-target-inside (_type_) level)
(init-level-system (_type_ symbol) none)
(art-group-get-by-name (_type_ string (pointer level)) art-group)
(level-group-method-23 () none)
(level-group-method-24 () none)
(level-group-method-25 () none)
(update-vis-volumes (_type_) none)
(level-group-method-24 (_type_) none)
(print-volume-sizes (_type_) none)
(status-of-level-and-borrows (_type_ symbol symbol) symbol)
(do-nothing (_type_) none)
(load-in-progress? (_type_) symbol)
+4 -4
View File
@@ -14,7 +14,7 @@
arg0
)
(defun matrix-fu-compose ((arg0 matrix) (arg1 vector) (arg2 vector) (arg3 vector))
(defun matrix-fu-compose ((arg0 matrix) (arg1 vector) (arg2 vector))
(set! (-> arg0 fvec quad) (-> arg1 quad))
(set! (-> arg0 uvec quad) (-> arg2 quad))
(vector-cross! (-> arg0 rvec) arg2 arg1)
@@ -35,7 +35,7 @@
arg0
)
(defun matrix-f-u-compose ((arg0 matrix) (arg1 vector) (arg2 vector) (arg3 vector))
(defun matrix-f-u-compose ((arg0 matrix) (arg1 vector) (arg2 vector))
(set! (-> arg0 fvec quad) (-> arg1 quad))
(vector-cross! (-> arg0 rvec) arg2 arg1)
(vector-normalize! (-> arg0 rvec) 1.0)
@@ -83,10 +83,10 @@
arg0
)
(defun matrix-f-compose ((arg0 matrix) (arg1 vector) (arg2 vector) (arg3 vector))
(defun matrix-f-compose ((arg0 matrix) (arg1 vector) (arg2 float))
(set! (-> arg0 fvec quad) (-> arg1 quad))
(let ((a2-1 (vector-get-unique! (new 'stack-no-clear 'vector) arg1)))
(matrix-f-u-compose arg0 arg1 a2-1 arg3)
(matrix-f-u-compose arg0 arg1 a2-1)
)
arg0
)
+1 -1
View File
@@ -177,7 +177,7 @@
(mesh basic :overlay-at (-> state mesh))
)
(:methods
(nav-control-method-9 () none)
(debug-draw (_type_) none)
(nav-control-method-10 () none)
(find-poly-containing-point-1 (_type_ vector) nav-poly)
(cloest-point-on-mesh (_type_ vector vector nav-poly) nav-poly)
+1 -1
View File
@@ -210,7 +210,7 @@ Based on the implementation of point-poly-intersection?, these should likely be
(nav-mesh-method-21 () none)
(nav-mesh-method-22 () none)
(nav-mesh-method-23 () none)
(nav-mesh-method-24 () none)
(compute-bounding-box-from-vertices (_type_ vector vector) none)
(nav-mesh-method-25 () none)
(nav-mesh-method-26 () none)
(nav-mesh-method-27 () none)
@@ -71,6 +71,8 @@
;; ---rigid-body-h:rigid-body-object-flag
(declare-type rigid-body-object basic)
(declare-type rigid-body-queue-manager process)
(define-extern *rigid-body-queue-manager* rigid-body-queue-manager)
;; DECOMP BEGINS
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -5,5 +5,23 @@
;; name in dgo: gun-part
;; dgos: GAME
(define-extern *yellow-shot-2-trail* light-trail-composition)
(define-extern *red-shot-3-trail* light-trail-composition)
(define-extern *last-player-pos* vector)
(define-extern *gun-dark-3-nuke-fade-time-small* time-frame)
(define-extern *gun-dark-3-nuke-blur-time-small* time-frame)
(define-extern *gun-dark-3-nuke-blur-curve-small* curve2d-piecewise)
(define-extern *gun-dark-3-nuke-fade-curve-small* curve-color-piecewise)
(define-extern *gun-dark-3-nuke-blur-segs-small* uint)
(define-extern *gun-dark-3-mushroom-speed* float)
(define-extern *gun-dark-3-mushroom-size-time* time-frame)
(define-extern *gun-dark-3-nuke-mushroom-size-curve-x* curve2d-piecewise)
(define-extern *gun-dark-3-nuke-mushroom-size-curve-y* curve2d-piecewise)
(define-extern *gun-dark-3-nuke-fade-time* time-frame)
(define-extern *gun-dark-3-nuke-blur-time* time-frame)
(define-extern *gun-dark-3-nuke-blur-curve* curve2d-piecewise)
(define-extern *gun-dark-3-nuke-fade-curve* curve-color-piecewise)
(define-extern *gun-dark-3-nuke-blur-segs* uint)
;; DECOMP BEGINS
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -6,6 +6,7 @@
;; dgos: GAME
(define-extern process-drawable2-shock-effect (function process-drawable process-drawable lightning-spec (function lightning-tracker none) sparticle-launcher none))
(define-extern process-drawable-shock-effect-replace (function process-drawable lightning-spec (function lightning-tracker none) int int float none))
;; DECOMP BEGINS
+3 -3
View File
@@ -187,9 +187,9 @@
,(cond
((and virtual parent)
`(begin
(inherit-state ,new-state (the state ,parent))
(set! (-> ,new-state parent) (the state ,parent))
`(define-virtual-state-hook ,state-name ,defstate-type ,new-state ,(eq? virtual 'override) :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
(inherit-state ,new-state ,(if (pair? parent) `(method-of-type ,(car parent) ,(cadr parent)) `(the state ,parent)))
(set! (-> ,new-state parent) ,(if (pair? parent) `(method-of-type ,(car parent) ,(cadr parent)) `(the state ,parent)))
(define-virtual-state-hook ,state-name ,defstate-type ,new-state ,(eq? virtual 'override) :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
)
)
(virtual
+1
View File
@@ -32,6 +32,7 @@ add_library(compiler
compiler/CompilerSettings.cpp
compiler/CodeGenerator.cpp
compiler/StaticObject.cpp
compiler/symbol_info.cpp
compiler/compilation/Asm.cpp
compiler/compilation/Atoms.cpp
compiler/compilation/CompilerControl.cpp
+12 -9
View File
@@ -25,8 +25,9 @@ Compiler::Compiler(GameVersion version,
: m_version(version),
m_goos(user_profile),
m_debugger(&m_listener, &m_goos.reader, version),
m_make(repl_config, user_profile),
m_repl(std::move(repl)),
m_make(repl_config, user_profile) {
m_symbol_info(&m_goos.reader.db) {
m_listener.add_debugger(&m_debugger);
m_listener.set_default_port(version);
m_ts.add_builtin_types(m_version);
@@ -57,9 +58,7 @@ Compiler::Compiler(GameVersion version,
// add built-in forms to symbol info
for (const auto& [builtin_name, builtin_info] : g_goal_forms) {
SymbolInfo::Metadata sym_meta;
sym_meta.docstring = builtin_info.first;
m_symbol_info.add_builtin(builtin_name, sym_meta);
m_symbol_info.add_builtin(builtin_name, builtin_info.first);
}
// load auto-complete history, only if we are running in the interactive mode.
@@ -463,6 +462,10 @@ void Compiler::asm_file(const CompilationOptions& options) {
file_path = candidate_paths.at(0).string();
}
// Evict any symbols we have indexed for this file, this is what
// helps to ensure we have an up to date and accurate symbol index
m_symbol_info.evict_symbols_using_file_index(file_path);
auto code = m_goos.reader.read_from_file({file_path});
std::string obj_file_name = file_path;
@@ -489,7 +492,7 @@ void Compiler::asm_file(const CompilationOptions& options) {
if (options.disassemble) {
codegen_and_disassemble_object_file(obj_file, &data, &disasm, options.disasm_code_only);
if (options.disassembly_output_file.empty()) {
printf("%s\n", disasm.c_str());
lg::print("{}\n", disasm);
} else {
file_util::write_text_file(options.disassembly_output_file, disasm);
}
@@ -502,7 +505,7 @@ void Compiler::asm_file(const CompilationOptions& options) {
if (m_listener.is_connected()) {
m_listener.send_code(data, obj_file_name);
} else {
printf("WARNING - couldn't load because listener isn't connected\n"); // todo log warn
lg::print("WARNING - couldn't load because listener isn't connected\n"); // todo log warn
}
}
@@ -515,15 +518,15 @@ void Compiler::asm_file(const CompilationOptions& options) {
}
} else {
if (options.load) {
printf("WARNING - couldn't load because coloring is not enabled\n");
lg::print("WARNING - couldn't load because coloring is not enabled\n");
}
if (options.write) {
printf("WARNING - couldn't write because coloring is not enabled\n");
lg::print("WARNING - couldn't write because coloring is not enabled\n");
}
if (options.disassemble) {
printf("WARNING - couldn't disassemble because coloring is not enabled\n");
lg::print("WARNING - couldn't disassemble because coloring is not enabled\n");
}
}
}
+20 -7
View File
@@ -12,7 +12,8 @@
#include "goalc/compiler/CompilerSettings.h"
#include "goalc/compiler/Env.h"
#include "goalc/compiler/IR.h"
#include "goalc/compiler/SymbolInfo.h"
#include "goalc/compiler/docs/DocTypes.h"
#include "goalc/compiler/symbol_info.h"
#include "goalc/data_compiler/game_text_common.h"
#include "goalc/debugger/Debugger.h"
#include "goalc/emitter/Register.h"
@@ -96,10 +97,20 @@ class Compiler {
std::vector<std::pair<std::string, replxx::Replxx::Color>> const& user_data);
bool knows_object_file(const std::string& name);
MakeSystem& make_system() { return m_make; }
std::set<std::string> lookup_symbol_infos_starting_with(const std::string& prefix,
int max_count) const;
std::vector<SymbolInfo>* lookup_exact_name_info(const std::string& name) const;
std::vector<std::shared_ptr<symbol_info::SymbolInfo>> lookup_symbol_info_by_file(
const std::string& file_path) const;
std::vector<std::shared_ptr<symbol_info::SymbolInfo>> lookup_symbol_info_by_prefix(
const std::string& prefix) const;
std::set<std::string> lookup_symbol_names_starting_with(const std::string& prefix) const;
std::vector<std::shared_ptr<symbol_info::SymbolInfo>> lookup_exact_name_info(
const std::string& name) const;
std::optional<TypeSpec> lookup_typespec(const std::string& symbol_name);
TypeSystem& type_system() { return m_ts; };
// TODO - rename these types / namespaces -- consolidate with SymbolInfo and whatever else tries
// to also do this work
std::tuple<std::unordered_map<std::string, Docs::SymbolDocumentation>,
std::unordered_map<std::string, Docs::FileDocumentation>>
generate_per_file_symbol_info();
private:
GameVersion m_version;
@@ -111,7 +122,9 @@ class Compiler {
listener::Listener m_listener;
goos::Interpreter m_goos;
Debugger m_debugger;
// 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>
@@ -121,9 +134,9 @@ class Compiler {
CompilerSettings m_settings;
bool m_throw_on_define_extern_redefinition = false;
std::unordered_set<std::string> m_allow_inconsistent_definition_symbols;
SymbolInfoMap m_symbol_info;
std::unique_ptr<REPL::Wrapper> m_repl;
MakeSystem m_make;
std::unique_ptr<REPL::Wrapper> m_repl;
symbol_info::SymbolInfoMap m_symbol_info;
struct DebugStats {
int num_spills = 0;
@@ -308,7 +321,7 @@ class Compiler {
int offset,
Env* env);
std::string make_symbol_info_description(const SymbolInfo& info);
std::string make_symbol_info_description(const std::shared_ptr<symbol_info::SymbolInfo> info);
MathMode get_math_mode(const TypeSpec& ts);
bool is_number(const TypeSpec& ts);
-250
View File
@@ -1,250 +0,0 @@
#pragma once
#include <set>
#include <string>
#include <vector>
#include "common/goos/Object.h"
#include "common/util/Assert.h"
#include "common/util/Trie.h"
#include "goalc/compiler/Val.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:
struct Metadata {
std::string docstring = "";
};
// TODO - states
// TODO - enums
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,
const std::optional<Metadata> meta = {}) {
SymbolInfo info;
info.m_kind = Kind::GLOBAL_VAR;
info.m_name = name;
info.m_def_form = defining_form;
if (meta) {
info.m_meta = *meta;
}
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 std::vector<GoalArg> args,
const goos::Object& defining_form,
const std::optional<Metadata> meta = {}) {
SymbolInfo info;
info.m_kind = Kind::FUNCTION;
info.m_name = name;
info.m_def_form = defining_form;
if (meta) {
info.m_meta = *meta;
}
info.m_args = args;
return info;
}
static SymbolInfo make_type(const std::string& name,
const goos::Object& defining_form,
const std::optional<Metadata> meta = {}) {
SymbolInfo info;
info.m_kind = Kind::TYPE;
info.m_name = name;
info.m_def_form = defining_form;
if (meta) {
info.m_meta = *meta;
}
return info;
}
static SymbolInfo make_constant(const std::string& name,
const goos::Object& defining_form,
const std::optional<Metadata> meta = {}) {
SymbolInfo info;
info.m_kind = Kind::CONSTANT;
info.m_name = name;
info.m_def_form = defining_form;
if (meta) {
info.m_meta = *meta;
}
return info;
}
static SymbolInfo make_macro(const std::string& name,
const goos::Object& defining_form,
const std::optional<Metadata> meta = {}) {
SymbolInfo info;
info.m_kind = Kind::MACRO;
info.m_name = name;
info.m_def_form = defining_form;
if (meta) {
info.m_meta = *meta;
}
return info;
}
static SymbolInfo make_builtin(const std::string& name, const std::optional<Metadata> meta = {}) {
SymbolInfo info;
info.m_kind = Kind::LANGUAGE_BUILTIN;
info.m_name = name;
if (meta) {
info.m_meta = *meta;
}
return info;
}
static SymbolInfo make_method(const std::string& method_name,
const std::vector<GoalArg> args,
const MethodInfo& method_info,
const goos::Object& defining_form) {
SymbolInfo info;
info.m_kind = Kind::METHOD;
info.m_name = method_name;
info.m_method_info = method_info;
info.m_def_form = defining_form;
info.m_meta.docstring =
info.m_method_info.docstring.has_value() ? info.m_method_info.docstring.value() : "";
info.m_args = args;
return info;
}
const std::string& name() const { return m_name; }
const MethodInfo& method_info() const { return m_method_info; }
Kind kind() const { return m_kind; }
const goos::Object& src_form() const { return m_def_form; }
const Metadata& meta() const { return m_meta; }
const std::vector<GoalArg>& args() const { return m_args; }
private:
Kind m_kind = Kind::INVALID;
goos::Object m_def_form;
std::string m_name;
MethodInfo m_method_info;
Metadata m_meta;
std::vector<GoalArg> m_args;
std::string m_return_type;
};
/*!
* 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,
const std::optional<SymbolInfo::Metadata> meta = {}) {
m_map[name]->push_back(SymbolInfo::make_global(name, defining_form, meta));
}
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));
}
// The m_symbol_types container stores TypeSpecs -- this does have argument information but not
// the names, which is why they have to be explicitly provided
void add_function(const std::string& name,
const std::vector<GoalArg> args,
const goos::Object& defining_form,
const std::optional<SymbolInfo::Metadata> meta = {}) {
m_map[name]->push_back(SymbolInfo::make_function(name, args, defining_form, meta));
}
void add_type(const std::string& name,
const goos::Object& defining_form,
const std::optional<SymbolInfo::Metadata> meta = {}) {
m_map[name]->push_back(SymbolInfo::make_type(name, defining_form, meta));
}
void add_constant(const std::string& name,
const goos::Object& defining_form,
const std::optional<SymbolInfo::Metadata> meta = {}) {
m_map[name]->push_back(SymbolInfo::make_constant(name, defining_form, meta));
}
void add_macro(const std::string& name,
const goos::Object& defining_form,
const std::optional<SymbolInfo::Metadata> meta = {}) {
m_map[name]->push_back(SymbolInfo::make_macro(name, defining_form, meta));
}
void add_builtin(const std::string& name, const std::optional<SymbolInfo::Metadata> meta = {}) {
m_map[name]->push_back(SymbolInfo::make_builtin(name, meta));
}
// The m_symbol_types container stores TypeSpecs -- this does have argument information but not
// the names, which is why they have to be explicitly provided
void add_method(const std::string& method_name,
const std::vector<GoalArg> args,
const MethodInfo& method_info,
const goos::Object& defining_form) {
m_map[method_name]->push_back(
SymbolInfo::make_method(method_name, args, method_info, defining_form));
}
std::vector<SymbolInfo>* lookup_exact_name(const std::string& name) const {
return m_map.lookup(name);
}
std::set<std::string> lookup_symbols_starting_with(const std::string& prefix,
int max_count) const {
std::set<std::string> result;
auto lookup = m_map.lookup_prefix(prefix, max_count);
for (auto& x : lookup) {
for (auto& y : *x) {
result.insert(y.name());
}
}
return result;
}
int symbol_count() const { return m_map.size(); }
std::vector<SymbolInfo> get_all_symbols() const {
std::vector<SymbolInfo> info;
auto lookup = m_map.get_all_nodes();
for (auto& x : lookup) {
for (auto& y : *x) {
info.push_back(y);
}
}
return info;
}
private:
Trie<std::vector<SymbolInfo>> m_map;
};
+227 -211
View File
@@ -14,8 +14,8 @@
#include "goalc/compiler/Compiler.h"
#include "goalc/compiler/IR.h"
#include "goalc/compiler/SymbolInfo.h"
#include "goalc/compiler/docs/DocTypes.h"
#include "goalc/compiler/symbol_info.h"
#include "goalc/data_compiler/dir_tpages.h"
#include "goalc/data_compiler/game_count.h"
#include "goalc/data_compiler/game_text_common.h"
@@ -358,35 +358,36 @@ Val* Compiler::compile_reload(const goos::Object& form, const goos::Object& rest
return get_none();
}
std::string Compiler::make_symbol_info_description(const SymbolInfo& info) {
switch (info.kind()) {
case SymbolInfo::Kind::GLOBAL_VAR:
std::string Compiler::make_symbol_info_description(
const std::shared_ptr<symbol_info::SymbolInfo> info) {
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.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:
m_symbol_types.at(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);
case symbol_info::Kind::METHOD:
return fmt::format("[Method] Type: {} Method Name: {} Defined: {}",
info.method_info().defined_in_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:
info->m_method_info.defined_in_type, info->m_name,
m_goos.reader.db.get_info_for(info->m_def_form));
case symbol_info::Kind::TYPE:
return fmt::format("[Type] Name: {} Defined: {}", info->m_name,
m_goos.reader.db.get_info_for(info->m_def_form));
case symbol_info::Kind::MACRO:
return fmt::format("[Macro] Name: {} Defined: {}", info->m_name,
m_goos.reader.db.get_info_for(info->m_def_form));
case symbol_info::Kind::CONSTANT:
return fmt::format(
"[Constant] Name: {} Value: {} Defined: {}", info.name(),
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(),
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()));
"[Constant] Name: {} Value: {} Defined: {}", info->m_name,
m_global_constants.at(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,
m_goos.reader.db.get_info_for(info->m_def_form));
case symbol_info::Kind::FWD_DECLARED_SYM:
return fmt::format("[Forward-Declared] Name: {} Defined: {}", info->m_name,
m_goos.reader.db.get_info_for(info->m_def_form));
default:
ASSERT(false);
return {};
@@ -398,11 +399,11 @@ 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_ptr);
if (!result) {
const auto result = m_symbol_info.lookup_exact_name(args.unnamed.at(0).as_symbol().name_ptr);
if (result.empty()) {
lg::print("No results found.\n");
} else {
for (auto& info : *result) {
for (const auto& info : result) {
lg::print("{}", make_symbol_info_description(info));
}
}
@@ -437,10 +438,12 @@ replxx::Replxx::completions_t Compiler::find_symbols_or_object_file_by_prefix(
completions.push_back(fmt::format("\"{}\")", match));
}
} else {
// TODO - GOAL's method calling syntax sucks for method name auto-completion
// maybe something that could be improved? Though it would be a radical departure from
// the syntax
const auto [token, stripped_leading_paren] = m_repl->get_current_repl_token(context);
// Otherwise, look for symbols
constexpr int kMaxForms = 100;
auto possible_forms = lookup_symbol_infos_starting_with(token, kMaxForms);
auto possible_forms = lookup_symbol_names_starting_with(token);
for (auto& x : possible_forms) {
completions.push_back(stripped_leading_paren ? "(" + x : x);
@@ -457,8 +460,7 @@ replxx::Replxx::hints_t Compiler::find_hints_by_prefix(std::string const& contex
(void)contextLen;
(void)user_data;
auto token = m_repl->get_current_repl_token(context);
constexpr int kMaxForms = 100;
auto possible_forms = lookup_symbol_infos_starting_with(token.first, kMaxForms);
auto possible_forms = lookup_symbol_names_starting_with(token.first);
replxx::Replxx::hints_t hints;
@@ -499,9 +501,8 @@ void Compiler::repl_coloring(
curr_symbol.second.erase(0, 1);
curr_symbol.first++;
}
std::vector<SymbolInfo>* sym_match = lookup_exact_name_info(curr_symbol.second);
if (sym_match != nullptr && sym_match->size() == 1) {
SymbolInfo sym_info = sym_match->at(0);
const auto matching_symbols = lookup_exact_name_info(curr_symbol.second);
if (matching_symbols.size() == 1) {
for (int pos = curr_symbol.first; pos <= int(i); pos++) {
// TODO - currently just coloring all types brown/gold
// - would be nice to have a different color for globals, functions, etc
@@ -543,7 +544,7 @@ void Compiler::repl_coloring(
}
}
// TODO - general syntax highlighting with regexes (quotes, symbols, etc)
// TODO - general syntax highlighting with AST
}
Val* Compiler::compile_autocomplete(const goos::Object& form, const goos::Object& rest, Env* env) {
@@ -552,8 +553,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_ptr, -1);
auto result = m_symbol_info.lookup_names_starting_with(args.unnamed.at(0).as_symbol().name_ptr);
auto time = timer.getMs();
for (auto& x : result) {
@@ -584,26 +584,33 @@ Val* Compiler::compile_update_macro_metadata(const goos::Object& form,
auto arg_spec = m_goos.parse_arg_spec(form, args.unnamed.at(2));
m_macro_specs[name] = arg_spec;
SymbolInfo::Metadata sym_meta;
sym_meta.docstring = args.unnamed.at(1).as_string()->data;
m_symbol_info.add_macro(name, form, sym_meta);
m_symbol_info.add_macro(name, arg_spec, form, args.unnamed.at(1).as_string()->data);
return get_none();
}
std::set<std::string> Compiler::lookup_symbol_infos_starting_with(const std::string& prefix,
int max_count) const {
std::vector<std::shared_ptr<symbol_info::SymbolInfo>> Compiler::lookup_symbol_info_by_file(
const std::string& file_path) const {
return m_symbol_info.lookup_symbols_by_file(file_path);
}
std::vector<std::shared_ptr<symbol_info::SymbolInfo>> Compiler::lookup_symbol_info_by_prefix(
const std::string& prefix) const {
return m_symbol_info.lookup_symbols_starting_with(prefix);
}
std::set<std::string> Compiler::lookup_symbol_names_starting_with(const std::string& prefix) const {
if (m_goos.reader.check_string_is_valid(prefix)) {
return m_symbol_info.lookup_symbols_starting_with(prefix, max_count);
return m_symbol_info.lookup_names_starting_with(prefix);
}
return {};
}
std::vector<SymbolInfo>* Compiler::lookup_exact_name_info(const std::string& name) const {
std::vector<std::shared_ptr<symbol_info::SymbolInfo>> Compiler::lookup_exact_name_info(
const std::string& name) const {
if (m_goos.reader.check_string_is_valid(name)) {
return m_symbol_info.lookup_exact_name(name);
} else {
return nullptr;
return {};
}
}
@@ -615,6 +622,176 @@ std::optional<TypeSpec> Compiler::lookup_typespec(const std::string& symbol_name
return {};
}
std::tuple<std::unordered_map<std::string, Docs::SymbolDocumentation>,
std::unordered_map<std::string, Docs::FileDocumentation>>
Compiler::generate_per_file_symbol_info() {
// TODO - remove this function, all required information has been consolidated into `SymbolInfo`
// it just has to be serialized in the same way, I will do it later
const auto symbols = m_symbol_info.get_all_symbols();
std::unordered_map<std::string, Docs::SymbolDocumentation> all_symbols;
std::unordered_map<std::string, Docs::FileDocumentation> file_docs;
lg::info("Processing {} symbols...", symbols.size());
int count = 0;
for (const auto& sym_info : symbols) {
count++;
if (count % 100 == 0 || count == (int)symbols.size()) {
lg::info("Processing [{}/{}] symbols...", count, symbols.size());
}
std::optional<Docs::DefinitionLocation> def_loc;
const auto& goos_info = m_goos.reader.db.get_short_info_for(sym_info->m_def_form);
if (goos_info) {
Docs::DefinitionLocation new_def_loc;
new_def_loc.filename = file_util::convert_to_unix_path_separators(file_util::split_path_at(
goos_info->filename, {"goal_src", version_to_game_name(m_version)}));
new_def_loc.line_idx = goos_info->line_idx_to_display;
new_def_loc.char_idx = goos_info->pos_in_line;
def_loc = new_def_loc;
}
Docs::SymbolDocumentation sym_doc;
sym_doc.name = sym_info->m_name;
sym_doc.description = sym_info->m_docstring;
sym_doc.kind = sym_info->m_kind;
sym_doc.def_location = def_loc;
if (all_symbols.count(sym_info->m_name) > 1) {
lg::error("A symbol was defined twice, how did this happen? {}", sym_info->m_name);
} else {
all_symbols.emplace(sym_info->m_name, sym_doc);
}
Docs::FileDocumentation file_doc;
std::string file_doc_key;
if (!goos_info) {
file_doc_key = "unknown";
} else {
file_doc_key = file_util::convert_to_unix_path_separators(
file_util::split_path_at(goos_info->filename, {"goal_src"}));
}
if (file_docs.count(file_doc_key) != 0) {
file_doc = file_docs.at(file_doc_key);
} else {
file_doc = Docs::FileDocumentation();
}
// TODO - states / enums / built-ins
if (sym_info->m_kind == symbol_info::Kind::GLOBAL_VAR ||
sym_info->m_kind == symbol_info::Kind::CONSTANT) {
Docs::VariableDocumentation var;
var.name = sym_info->m_name;
var.description = sym_info->m_docstring;
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.def_location = def_loc;
if (sym_info->m_kind == symbol_info::Kind::GLOBAL_VAR) {
file_doc.global_vars.push_back(var);
} else {
file_doc.constants.push_back(var);
}
} else if (sym_info->m_kind == symbol_info::Kind::FUNCTION) {
Docs::FunctionDocumentation func;
func.name = sym_info->m_name;
func.description = sym_info->m_docstring;
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();
file_doc.functions.push_back(func);
} else if (sym_info->m_kind == symbol_info::Kind::TYPE) {
Docs::TypeDocumentation type;
type.name = sym_info->m_name;
type.description = sym_info->m_docstring;
type.def_location = def_loc;
const auto& type_info = m_ts.lookup_type(type.name);
type.parent_type = type_info->get_parent();
type.size = type_info->get_size_in_memory();
type.method_count = type_info->get_methods_defined_for_type().size();
if (m_ts.typecheck_and_throw(m_ts.make_typespec("structure"), m_ts.make_typespec(type.name),
"", false, false, false)) {
auto struct_info = dynamic_cast<StructureType*>(type_info);
for (const auto& field : struct_info->fields()) {
Docs::FieldDocumentation field_doc;
field_doc.name = field.name();
field_doc.description = "";
field_doc.type = field.type().base_type();
field_doc.is_array = field.is_array();
field_doc.is_inline = field.is_inline();
field_doc.is_dynamic = field.is_dynamic();
type.fields.push_back(field_doc);
}
}
for (const auto& method : type_info->get_methods_defined_for_type()) {
// Check to see if it's a state
if (m_ts.typecheck_and_throw(m_ts.make_typespec("state"), method.type, "", false, false,
false)) {
Docs::TypeStateDocumentation state_doc;
state_doc.id = method.id;
state_doc.is_virtual = true;
state_doc.name = method.name;
type.states.push_back(state_doc);
} else {
Docs::TypeMethodDocumentation method_doc;
method_doc.id = method.id;
method_doc.name = method.name;
method_doc.is_override = method.overrides_parent;
type.methods.push_back(method_doc);
}
}
for (const auto& [state_name, state_info] : type_info->get_states_declared_for_type()) {
Docs::TypeStateDocumentation state_doc;
state_doc.name = state_name;
state_doc.is_virtual = false;
type.states.push_back(state_doc);
}
file_doc.types.push_back(type);
} else if (sym_info->m_kind == symbol_info::Kind::MACRO) {
Docs::MacroDocumentation macro_doc;
macro_doc.name = sym_info->m_name;
macro_doc.description = sym_info->m_docstring;
macro_doc.def_location = def_loc;
const auto& arg_spec = m_macro_specs[macro_doc.name];
for (const auto& arg : arg_spec.unnamed) {
macro_doc.args.push_back(arg);
}
for (const auto& arg : arg_spec.named) {
std::optional<std::string> def_value;
if (arg.second.has_default) {
def_value = arg.second.default_value.print();
}
macro_doc.kwargs.push_back({arg.first, def_value});
}
if (!arg_spec.rest.empty()) {
macro_doc.variadic_arg = arg_spec.rest;
}
file_doc.macros.push_back(macro_doc);
} else if (sym_info->m_kind == symbol_info::Kind::METHOD) {
Docs::MethodDocumentation method_doc;
method_doc.name = sym_info->m_name;
method_doc.description = sym_info->m_docstring;
method_doc.def_location = def_loc;
const auto& method_info = sym_info->m_method_info;
method_doc.id = method_info.id;
method_doc.type = sym_info->m_method_info.defined_in_type;
method_doc.is_override = method_info.overrides_parent;
method_doc.args = Docs::get_args_from_docstring(sym_info->m_args, method_doc.description);
// The last arg in the typespec is the return type
const auto& method_type = method_info.type;
method_doc.return_type = method_type.last_arg().base_type();
method_doc.is_builtin = method_doc.id <= 9;
file_doc.methods.push_back(method_doc);
}
file_docs[file_doc_key] = file_doc;
}
return {all_symbols, file_docs};
}
Val* Compiler::compile_load_project(const goos::Object& form, const goos::Object& rest, Env*) {
auto args = get_va(form, rest);
va_check(form, args, {goos::ObjectType::STRING}, {});
@@ -664,168 +841,7 @@ Val* Compiler::compile_gen_docs(const goos::Object& form, const goos::Object& re
const auto& doc_path = fs::path(args.unnamed.at(0).as_string()->data);
lg::info("Saving docs to: {}", doc_path.string());
const auto symbols = m_symbol_info.get_all_symbols();
std::unordered_map<std::string, Docs::SymbolDocumentation> all_symbols;
std::unordered_map<std::string, Docs::FileDocumentation> file_docs;
lg::info("Processing {} symbols...", symbols.size());
int count = 0;
for (const auto& sym_info : symbols) {
count++;
if (count % 100 == 0 || count == (int)symbols.size()) {
lg::info("Processing [{}/{}] symbols...", count, symbols.size());
}
std::optional<Docs::DefinitionLocation> def_loc;
const auto& goos_info = m_goos.reader.db.get_short_info_for(sym_info.src_form());
if (goos_info) {
Docs::DefinitionLocation new_def_loc;
new_def_loc.filename = file_util::convert_to_unix_path_separators(file_util::split_path_at(
goos_info->filename, {"goal_src", version_to_game_name(m_version)}));
new_def_loc.line_idx = goos_info->line_idx_to_display;
new_def_loc.char_idx = goos_info->pos_in_line;
def_loc = new_def_loc;
}
Docs::SymbolDocumentation sym_doc;
sym_doc.name = sym_info.name();
sym_doc.description = sym_info.meta().docstring;
sym_doc.kind = sym_info.kind();
sym_doc.def_location = def_loc;
if (all_symbols.count(sym_info.name()) > 1) {
lg::error("A symbol was defined twice, how did this happen? {}", sym_info.name());
} else {
all_symbols.emplace(sym_info.name(), sym_doc);
}
Docs::FileDocumentation file_doc;
std::string file_doc_key;
if (!goos_info) {
file_doc_key = "unknown";
} else {
file_doc_key = file_util::convert_to_unix_path_separators(
file_util::split_path_at(goos_info->filename, {"goal_src"}));
}
if (file_docs.count(file_doc_key) != 0) {
file_doc = file_docs.at(file_doc_key);
} else {
file_doc = Docs::FileDocumentation();
}
// TODO - states / enums / built-ins
if (sym_info.kind() == SymbolInfo::Kind::GLOBAL_VAR ||
sym_info.kind() == SymbolInfo::Kind::CONSTANT) {
Docs::VariableDocumentation var;
var.name = sym_info.name();
var.description = sym_info.meta().docstring;
if (sym_info.kind() == SymbolInfo::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.def_location = def_loc;
if (sym_info.kind() == SymbolInfo::Kind::GLOBAL_VAR) {
file_doc.global_vars.push_back(var);
} else {
file_doc.constants.push_back(var);
}
} else if (sym_info.kind() == SymbolInfo::Kind::FUNCTION) {
Docs::FunctionDocumentation func;
func.name = sym_info.name();
func.description = sym_info.meta().docstring;
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(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) {
Docs::TypeDocumentation type;
type.name = sym_info.name();
type.description = sym_info.meta().docstring;
type.def_location = def_loc;
const auto& type_info = m_ts.lookup_type(type.name);
type.parent_type = type_info->get_parent();
type.size = type_info->get_size_in_memory();
type.method_count = type_info->get_methods_defined_for_type().size();
if (m_ts.typecheck_and_throw(m_ts.make_typespec("structure"), m_ts.make_typespec(type.name),
"", false, false, false)) {
auto struct_info = dynamic_cast<StructureType*>(type_info);
for (const auto& field : struct_info->fields()) {
Docs::FieldDocumentation field_doc;
field_doc.name = field.name();
field_doc.description = "";
field_doc.type = field.type().base_type();
field_doc.is_array = field.is_array();
field_doc.is_inline = field.is_inline();
field_doc.is_dynamic = field.is_dynamic();
type.fields.push_back(field_doc);
}
}
for (const auto& method : type_info->get_methods_defined_for_type()) {
// Check to see if it's a state
if (m_ts.typecheck_and_throw(m_ts.make_typespec("state"), method.type, "", false, false,
false)) {
Docs::TypeStateDocumentation state_doc;
state_doc.id = method.id;
state_doc.is_virtual = true;
state_doc.name = method.name;
type.states.push_back(state_doc);
} else {
Docs::TypeMethodDocumentation method_doc;
method_doc.id = method.id;
method_doc.name = method.name;
method_doc.is_override = method.overrides_parent;
type.methods.push_back(method_doc);
}
}
for (const auto& [state_name, state_info] : type_info->get_states_declared_for_type()) {
Docs::TypeStateDocumentation state_doc;
state_doc.name = state_name;
state_doc.is_virtual = false;
type.states.push_back(state_doc);
}
file_doc.types.push_back(type);
} else if (sym_info.kind() == SymbolInfo::Kind::MACRO) {
Docs::MacroDocumentation macro_doc;
macro_doc.name = sym_info.name();
macro_doc.description = sym_info.meta().docstring;
macro_doc.def_location = def_loc;
const auto& arg_spec = m_macro_specs[macro_doc.name];
for (const auto& arg : arg_spec.unnamed) {
macro_doc.args.push_back(arg);
}
for (const auto& arg : arg_spec.named) {
std::optional<std::string> def_value;
if (arg.second.has_default) {
def_value = arg.second.default_value.print();
}
macro_doc.kwargs.push_back({arg.first, def_value});
}
if (!arg_spec.rest.empty()) {
macro_doc.variadic_arg = arg_spec.rest;
}
file_doc.macros.push_back(macro_doc);
} else if (sym_info.kind() == SymbolInfo::Kind::METHOD) {
Docs::MethodDocumentation method_doc;
method_doc.name = sym_info.name();
method_doc.description = sym_info.meta().docstring;
method_doc.def_location = def_loc;
const auto& method_info = sym_info.method_info();
method_doc.id = method_info.id;
method_doc.type = sym_info.method_info().defined_in_type;
method_doc.is_override = method_info.overrides_parent;
method_doc.args = Docs::get_args_from_docstring(sym_info.args(), method_doc.description);
// The last arg in the typespec is the return type
const auto& method_type = method_info.type;
method_doc.return_type = method_type.last_arg().base_type();
method_doc.is_builtin = method_doc.id <= 9;
file_doc.methods.push_back(method_doc);
}
file_docs[file_doc_key] = file_doc;
}
const auto [all_symbols, file_docs] = generate_per_file_symbol_info();
json symbol_map_data(all_symbols);
file_util::write_text_file(
+10 -7
View File
@@ -11,10 +11,10 @@
*/
Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest, Env* env) {
auto args = get_va(form, rest);
SymbolInfo::Metadata sym_meta;
std::string docstring;
// Grab the docstring (if it's there) and then rip it out so we can do the normal validation
if (args.unnamed.size() == 3 && args.unnamed.at(1).is_string()) {
sym_meta.docstring = args.unnamed.at(1).as_string()->data;
docstring = args.unnamed.at(1).as_string()->data;
args.unnamed.erase(args.unnamed.begin() + 1);
}
@@ -35,6 +35,7 @@ Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest
auto sym_val = fe->alloc_val<SymbolVal>(symbol_string(sym), m_ts.make_typespec("symbol"));
auto compiled_val = compile_error_guard(val, env);
auto as_lambda = dynamic_cast<LambdaVal*>(compiled_val);
auto in_gpr = compiled_val->to_gpr(form, fe);
if (as_lambda) {
// there are two cases in which we save a function body that is passed to a define:
// 1. It generated code [so went through the compiler] and the allow_inline flag is set.
@@ -50,11 +51,14 @@ Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest
}
// Most defines come via macro invokations, we want the TRUE defining form location
// if we can get it
// TODO - test the return value changes
if (env->macro_expand_env()) {
m_symbol_info.add_function(symbol_string(sym), as_lambda->lambda.params,
env->macro_expand_env()->root_form(), sym_meta);
m_symbol_info.add_function(symbol_string(sym), in_gpr->type().last_arg().base_type(),
as_lambda->lambda.params, env->macro_expand_env()->root_form(),
docstring);
} else {
m_symbol_info.add_function(symbol_string(sym), as_lambda->lambda.params, form, sym_meta);
m_symbol_info.add_function(symbol_string(sym), in_gpr->type().last_arg().base_type(),
as_lambda->lambda.params, form, docstring);
}
}
@@ -62,7 +66,6 @@ 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 in_gpr = compiled_val->to_gpr(form, fe);
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();
@@ -79,7 +82,7 @@ Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest
if (!as_lambda) {
// Don't double-add functions as globals
m_symbol_info.add_global(symbol_string(sym), form, sym_meta);
m_symbol_info.add_global(symbol_string(sym), in_gpr->type().base_type(), form, docstring);
}
env->emit(form, std::make_unique<IR_SetSymbolValue>(sym_val, in_gpr));
+4 -4
View File
@@ -45,6 +45,7 @@ Val* Compiler::compile_goos_macro(const goos::Object& o,
env->function_env()->alloc_env<MacroExpandEnv>(env, name.as_symbol(), macro->body, o);
try {
const auto& compile_result = compile(goos_result, compile_env_for_macro);
// TODO - is this critical (do the args and such change?)?
m_macro_specs.emplace(macro->name, macro->args);
return compile_result;
} catch (CompilerException& ce) {
@@ -180,10 +181,9 @@ Val* Compiler::compile_define_constant(const goos::Object& form,
rest = &pair_cdr(*rest);
// check for potential docstring
SymbolInfo::Metadata sym_meta;
std::string docstring = "";
if (rest->is_pair() && pair_car(*rest).is_string() && !pair_cdr(*rest).is_empty_list()) {
std::string docstring = pair_car(*rest).as_string()->data;
sym_meta.docstring = docstring;
docstring = pair_car(*rest).as_string()->data;
rest = &pair_cdr(*rest);
}
@@ -218,7 +218,7 @@ Val* Compiler::compile_define_constant(const goos::Object& form,
// TODO - eventually, it'd be nice if global constants were properly typed
// and this information was propagated
m_symbol_info.add_constant(sym.name_ptr, form, sym_meta);
m_symbol_info.add_constant(sym.name_ptr, form, docstring);
return get_none();
}
+1 -1
View File
@@ -441,7 +441,7 @@ Val* Compiler::compile_deftype(const goos::Object& form, const goos::Object& res
}
}
m_symbol_info.add_type(result.type.base_type(), form);
m_symbol_info.add_type(result.type.base_type(), result.type_info, form);
// return none, making the value of (deftype..) unusable
return get_none();
+4 -3
View File
@@ -123,14 +123,15 @@ void to_json(json& j, const MacroDocumentation& obj) {
}
}
std::vector<ArgumentDocumentation> get_args_from_docstring(std::vector<GoalArg> args,
std::string docstring) {
std::vector<ArgumentDocumentation> get_args_from_docstring(
std::vector<symbol_info::ArgumentInfo> args,
std::string docstring) {
std::vector<ArgumentDocumentation> arg_docs;
for (const auto& arg : args) {
ArgumentDocumentation arg_doc;
arg_doc.name = arg.name;
// TODO - is this type reliable?
arg_doc.type = arg.type.base_type();
arg_doc.type = arg.type;
arg_docs.push_back(arg_doc);
}
if (docstring.empty()) {
+14 -4
View File
@@ -3,12 +3,15 @@
#include <optional>
#include <string>
#include "goalc/compiler/SymbolInfo.h"
#include "goalc/compiler/symbol_info.h"
#include "third-party/json.hpp"
using json = nlohmann::json;
// TODO - deprecate this file in factor of the now consolidated `SymbolInfo`
// which now contains comprehensive info on all forms of symbols
namespace Docs {
struct DefinitionLocation {
@@ -69,6 +72,7 @@ struct FieldDocumentation {
void to_json(json& j, const FieldDocumentation& obj);
struct TypeMethodDocumentation {
// TODO - relevant?
int id;
std::string name;
bool is_override = false;
@@ -89,6 +93,7 @@ struct TypeDocumentation {
std::optional<DefinitionLocation> def_location;
int size;
std::vector<FieldDocumentation> fields = {};
// TODO - who cares, remove this probably
int method_count;
std::vector<TypeMethodDocumentation> methods = {};
std::vector<TypeStateDocumentation> states = {};
@@ -96,10 +101,14 @@ struct TypeDocumentation {
void to_json(json& j, const TypeDocumentation& obj);
struct MethodDocumentation {
// TODO - relevant?
int id;
bool is_builtin;
std::string name;
std::string description = "";
// TODO - this is `object` sometimes, for example `(defmethod print ((this light))`
// i believe this is because we always grab the first symbol, but of course, overridden methods
// dont work like that so things are likely working as intended
std::string type;
std::optional<DefinitionLocation> def_location;
// TODO - need to track function calls to determine this, obviously cant be determined from just
@@ -139,13 +148,14 @@ struct SymbolDocumentation {
// TODO - forward declared symbols
std::string name;
std::string description = "";
SymbolInfo::Kind kind;
symbol_info::Kind kind;
std::optional<DefinitionLocation> def_location = {};
std::vector<DefinitionLocation> forward_declared_in = {};
};
void to_json(json& j, const SymbolDocumentation& obj);
std::vector<ArgumentDocumentation> get_args_from_docstring(std::vector<GoalArg> args,
std::string docstring);
std::vector<ArgumentDocumentation> get_args_from_docstring(
std::vector<symbol_info::ArgumentInfo> args,
std::string docstring);
} // namespace Docs
+318
View File
@@ -0,0 +1,318 @@
#include "symbol_info.h"
#include "common/log/log.h"
#include "common/util/FileUtil.h"
#include "common/util/string_util.h"
namespace symbol_info {
void SymbolInfo::update_args_from_docstring() {
if (m_docstring.empty()) {
return;
}
auto lines = str_util::split(m_docstring);
for (const auto& line : lines) {
const auto trimmed_line = str_util::ltrim(line);
if (str_util::starts_with(trimmed_line, "@param")) {
// Get the info from the @param line
const auto& tokens =
str_util::regex_get_capture_groups(trimmed_line, "(@param.)\\s?([^\\s]*)\\s(.*)");
if (tokens.size() != 3) {
lg::warn("invalid docstring line - {}, skipping", trimmed_line);
continue;
}
const auto& param_type = str_util::trim(tokens[0]);
const auto& param_name = str_util::trim(tokens[1]);
const auto& param_description = str_util::trim(tokens[2]);
// Locate the appropriate arg based on the name
for (auto& arg : m_args) {
if (arg.name == param_name) {
arg.description = param_description;
if (param_type == "@param") {
// a normal arg, nothing fancy
} else if (param_type == "@param_") {
// it's unused
arg.is_unused = true;
} else if (param_type == "@param!") {
// the params value is mutated within the function body
arg.is_mutated = true;
} else if (param_type == "@param?") {
// the param is optional -- there are checks to see if it was provided or not so its
// safe to pass "nothing"
arg.is_optional = true;
}
}
}
}
}
}
void SymbolInfo::set_definition_location(const goos::TextDb* textdb) {
const auto& goos_info = textdb->get_short_info_for(m_def_form);
if (goos_info) {
DefinitionLocation def_loc;
def_loc.line_idx = goos_info->line_idx_to_display;
def_loc.char_idx = goos_info->pos_in_line;
def_loc.file_path = file_util::convert_to_unix_path_separators(goos_info->filename);
m_def_location = def_loc;
}
}
void SymbolInfoMap::add_symbol_to_file_index(const std::string& file_path,
std::shared_ptr<SymbolInfo> symbol) {
if (m_file_symbol_index.find(file_path) == m_file_symbol_index.end()) {
m_file_symbol_index[file_path] = {};
}
m_file_symbol_index[file_path].push_back(symbol);
}
void SymbolInfoMap::add_global(const std::string& name,
const std::string& type,
const goos::Object& defining_form,
const std::string& docstring) {
SymbolInfo info = {
.m_kind = Kind::GLOBAL_VAR,
.m_name = name,
.m_def_form = defining_form,
.m_docstring = docstring,
.m_type = type,
};
info.set_definition_location(m_textdb);
const auto inserted_symbol = m_symbol_map.insert(name, info);
if (info.m_def_location) {
add_symbol_to_file_index(info.m_def_location->file_path, inserted_symbol);
}
}
void SymbolInfoMap::add_fwd_dec(const std::string& name, const goos::Object& defining_form) {
SymbolInfo info = {.m_kind = Kind::FWD_DECLARED_SYM, .m_name = name, .m_def_form = defining_form};
info.set_definition_location(m_textdb);
const auto inserted_symbol = m_symbol_map.insert(name, info);
if (info.m_def_location) {
add_symbol_to_file_index(info.m_def_location->file_path, inserted_symbol);
}
}
void SymbolInfoMap::add_function(const std::string& name,
const std::string& return_type,
const std::vector<GoalArg>& args,
const goos::Object& defining_form,
const std::string& docstring) {
SymbolInfo info = {
.m_kind = Kind::FUNCTION,
.m_name = name,
.m_def_form = defining_form,
.m_docstring = docstring,
.m_return_type = return_type,
};
for (const auto& goal_arg : args) {
ArgumentInfo arg_info;
arg_info.name = goal_arg.name;
arg_info.type_spec = goal_arg.type;
// TODO - is this reliable?
arg_info.type = goal_arg.type.base_type();
info.m_args.push_back(arg_info);
}
info.update_args_from_docstring();
info.set_definition_location(m_textdb);
const auto inserted_symbol = m_symbol_map.insert(name, info);
if (info.m_def_location) {
add_symbol_to_file_index(info.m_def_location->file_path, inserted_symbol);
}
}
void SymbolInfoMap::add_type(const std::string& name,
Type* type_info,
const goos::Object& defining_form,
const std::string& docstring) {
SymbolInfo info = {
.m_kind = Kind::TYPE,
.m_name = name,
.m_def_form = defining_form,
.m_docstring = docstring,
.m_parent_type = type_info->get_parent(),
.m_type_size = type_info->get_size_in_memory(),
};
// Only structure types have fields
auto as_structure_type = dynamic_cast<StructureType*>(type_info);
if (as_structure_type) { // generate the inspect method
for (const auto& field : as_structure_type->fields()) {
// TODO - field docstrings arent a thing, yet!
FieldInfo field_info = {
.name = field.name(),
.description = "",
.type = field.type().base_type(),
.is_array = field.is_array(),
.is_dynamic = field.is_dynamic(),
.is_inline = field.is_inline(),
};
info.m_type_fields.push_back(field_info);
}
}
for (const auto& method : type_info->get_methods_defined_for_type()) {
if (method.type.base_type() == "state") {
TypeStateInfo state_info = {
.name = method.name,
.is_virtual = true,
.id = method.id,
};
info.m_type_states.push_back(state_info);
} else {
TypeMethodInfo method_info = {
.id = method.id,
.name = method.name,
.is_override = method.overrides_parent,
};
info.m_type_methods.push_back(method_info);
}
}
for (const auto& [state_name, state_info] : type_info->get_states_declared_for_type()) {
TypeStateInfo type_state_info = {
.name = state_name,
.is_virtual = false,
};
info.m_type_states.push_back(type_state_info);
}
info.set_definition_location(m_textdb);
const auto inserted_symbol = m_symbol_map.insert(name, info);
if (info.m_def_location) {
add_symbol_to_file_index(info.m_def_location->file_path, inserted_symbol);
}
}
void SymbolInfoMap::add_constant(const std::string& name,
const goos::Object& defining_form,
const std::string& docstring) {
SymbolInfo info = {
.m_kind = Kind::CONSTANT,
.m_name = name,
.m_def_form = defining_form,
.m_docstring = docstring,
// TODO - unfortunately, constants are not properly typed
.m_type = "unknown",
};
info.set_definition_location(m_textdb);
const auto inserted_symbol = m_symbol_map.insert(name, info);
if (info.m_def_location) {
add_symbol_to_file_index(info.m_def_location->file_path, inserted_symbol);
}
}
void SymbolInfoMap::add_macro(const std::string& name,
const goos::ArgumentSpec arg_spec,
const goos::Object& defining_form,
const std::string& docstring) {
SymbolInfo info = {
.m_kind = Kind::MACRO,
.m_name = name,
.m_def_form = defining_form,
.m_docstring = docstring,
};
for (const auto& arg : arg_spec.unnamed) {
info.m_macro_args.push_back(arg);
}
for (const auto& arg : arg_spec.named) {
std::optional<std::string> def_value;
if (arg.second.has_default) {
def_value = arg.second.default_value.print();
}
info.m_macro_kwargs.push_back({arg.first, def_value});
}
if (!arg_spec.rest.empty()) {
info.m_variadic_arg = arg_spec.rest;
}
info.set_definition_location(m_textdb);
const auto inserted_symbol = m_symbol_map.insert(name, info);
if (info.m_def_location) {
add_symbol_to_file_index(info.m_def_location->file_path, inserted_symbol);
}
}
void SymbolInfoMap::add_builtin(const std::string& name, const std::string& docstring) {
SymbolInfo info = {
.m_kind = Kind::LANGUAGE_BUILTIN,
.m_name = name,
.m_docstring = docstring,
};
info.set_definition_location(m_textdb);
m_symbol_map.insert(name, info);
}
void SymbolInfoMap::add_method(const std::string& method_name,
const std::vector<GoalArg>& args,
const MethodInfo& method_info,
const goos::Object& defining_form) {
SymbolInfo info = {
.m_kind = Kind::METHOD,
.m_name = method_name,
.m_method_info = method_info,
.m_method_builtin = method_info.id <= 9,
};
if (method_info.docstring) {
info.m_docstring = method_info.docstring.value();
}
for (const auto& goal_arg : args) {
ArgumentInfo arg_info;
arg_info.name = goal_arg.name;
arg_info.type_spec = goal_arg.type;
// TODO - is this reliable?
arg_info.type = goal_arg.type.base_type();
info.m_args.push_back(arg_info);
}
info.update_args_from_docstring();
info.set_definition_location(m_textdb);
const auto inserted_symbol = m_symbol_map.insert(method_name, info);
if (info.m_def_location) {
add_symbol_to_file_index(info.m_def_location->file_path, inserted_symbol);
}
}
std::vector<std::shared_ptr<SymbolInfo>> SymbolInfoMap::lookup_symbols_by_file(
const std::string& file_path) const {
if (m_file_symbol_index.find(file_path) != m_file_symbol_index.end()) {
return m_file_symbol_index.at(file_path);
}
return {};
}
std::vector<std::shared_ptr<SymbolInfo>> SymbolInfoMap::lookup_exact_name(
const std::string& name) const {
return m_symbol_map.retrieve_with_exact(name);
}
std::vector<std::shared_ptr<SymbolInfo>> SymbolInfoMap::lookup_symbols_starting_with(
const std::string& prefix) const {
std::vector<std::shared_ptr<SymbolInfo>> symbols;
const auto lookup = m_symbol_map.retrieve_with_prefix(prefix);
for (const auto& result : lookup) {
symbols.push_back(result);
}
return symbols;
}
std::set<std::string> SymbolInfoMap::lookup_names_starting_with(const std::string& prefix) const {
std::set<std::string> names;
const auto lookup = m_symbol_map.retrieve_with_prefix(prefix);
for (const auto& result : lookup) {
names.insert(result->m_name);
}
return names;
}
int SymbolInfoMap::symbol_count() const {
return m_symbol_map.size();
}
std::vector<std::shared_ptr<SymbolInfo>> SymbolInfoMap::get_all_symbols() const {
return m_symbol_map.get_all_elements();
}
void SymbolInfoMap::evict_symbols_using_file_index(const std::string& file_path) {
const auto standardized_path = file_util::convert_to_unix_path_separators(file_path);
if (m_file_symbol_index.find(standardized_path) != m_file_symbol_index.end()) {
for (const auto& symbol : m_file_symbol_index.at(standardized_path)) {
m_symbol_map.remove(symbol);
}
m_file_symbol_index.erase(standardized_path);
}
}
} // namespace symbol_info
+173
View File
@@ -0,0 +1,173 @@
#pragma once
#include <set>
#include <string>
#include <vector>
#include "common/goos/Object.h"
#include "common/util/Assert.h"
#include "common/util/trie_map.h"
#include "goalc/compiler/Val.h"
namespace symbol_info {
// TODO - states
// TODO - enums
enum class Kind {
GLOBAL_VAR,
FWD_DECLARED_SYM,
FUNCTION,
TYPE,
CONSTANT,
MACRO,
LANGUAGE_BUILTIN,
METHOD,
INVALID
};
struct DefinitionLocation {
std::string file_path;
uint32_t line_idx;
uint32_t char_idx;
// TODO - store the extent of the symbol definition as well
};
struct ArgumentInfo {
std::string name;
// TODO - anything use this?
TypeSpec type_spec;
std::string type;
std::string description = "";
// !var
bool is_mutated = false;
// ?var
bool is_optional = false;
// _var
bool is_unused = false;
};
struct FieldInfo {
std::string name;
// TODO - DefinitionLocation def_location;
std::string description = "";
std::string type;
// ?? TODO
bool is_array = false;
// :dynamic
bool is_dynamic = false;
// :inline
bool is_inline = false;
};
struct TypeMethodInfo {
int id; // TODO - is this even relevant anymore?
std::string name;
// TODO - DefinitionLocation def_location;
bool is_override = false;
};
struct TypeStateInfo {
std::string name;
// TODO - DefinitionLocation def_location;
bool is_virtual = false;
std::optional<int> id; // TODO - is this even relevant anymore?
};
/*!
* Info about a single symbol, representing one of:
* - Global variable
* - Global function
* - Type
* - Constant
* - Macro
* - Builtin keyword of the OpenGOAL language
*/
struct SymbolInfo {
Kind m_kind = Kind::INVALID;
std::string m_name;
goos::Object m_def_form;
std::optional<DefinitionLocation> m_def_location;
std::string m_docstring = "";
std::string m_type = "";
// Method or Function Related
std::vector<ArgumentInfo> m_args = {};
std::string m_return_type = "";
// Method Related
MethodInfo m_method_info;
bool m_method_builtin = false;
// Type Related
std::string m_parent_type = "";
int m_type_size = -1;
// NOTE - removed method count...seems unnecessary?
std::vector<FieldInfo> m_type_fields = {};
std::vector<TypeMethodInfo> m_type_methods = {};
std::vector<TypeStateInfo> m_type_states = {};
// Macro Related
std::vector<std::string> m_macro_args = {};
std::vector<std::pair<std::string, std::optional<std::string>>> m_macro_kwargs = {};
std::optional<std::string> m_variadic_arg = {};
// TODO: need to track references for this, this is a TODO for LSP work
// bool is_unused = false;
void update_args_from_docstring();
void set_definition_location(const goos::TextDb* textdb);
};
/*!
* 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 {
goos::TextDb* m_textdb;
TrieMap<SymbolInfo> m_symbol_map;
// Indexes references to symbols by the file they are defined within
// This allows us to not only efficiently retrieve symbols by file, but also allows us to
// cleanup symbols when files are re-compiled.
std::unordered_map<std::string, std::vector<std::shared_ptr<SymbolInfo>>> m_file_symbol_index;
void add_symbol_to_file_index(const std::string& file_path, std::shared_ptr<SymbolInfo> symbol);
public:
SymbolInfoMap(goos::TextDb* textdb) : m_textdb(textdb) {}
void add_global(const std::string& name,
const std::string& type,
const goos::Object& defining_form,
const std::string& docstring = "");
void add_fwd_dec(const std::string& name, const goos::Object& defining_form);
void add_function(const std::string& name,
const std::string& return_type,
const std::vector<GoalArg>& args,
const goos::Object& defining_form,
const std::string& docstring = "");
void add_type(const std::string& name,
Type* type_info,
const goos::Object& defining_form,
const std::string& docstring = "");
void add_constant(const std::string& name,
const goos::Object& defining_form,
const std::string& docstring = "");
void add_macro(const std::string& name,
const goos::ArgumentSpec arg_spec,
const goos::Object& defining_form,
const std::string& docstring = "");
void add_builtin(const std::string& name, const std::string& docstring = "");
void add_method(const std::string& method_name,
const std::vector<GoalArg>& args,
const MethodInfo& method_info,
const goos::Object& defining_form);
std::vector<std::shared_ptr<SymbolInfo>> lookup_symbols_by_file(
const std::string& file_path) const;
std::vector<std::shared_ptr<SymbolInfo>> lookup_exact_name(const std::string& name) const;
std::vector<std::shared_ptr<SymbolInfo>> lookup_symbols_starting_with(
const std::string& prefix) const;
std::set<std::string> lookup_names_starting_with(const std::string& prefix) const;
int symbol_count() const;
std::vector<std::shared_ptr<SymbolInfo>> get_all_symbols() const;
// Uses the per-file index to find and evict symbols globally
// This should be done before re-compiling a file, symbols will be re-added to the DB if they are
// found again
void evict_symbols_using_file_index(const std::string& file_path);
};
} // namespace symbol_info
+1
View File
@@ -8,6 +8,7 @@
#include "common/util/diff.h"
#include "common/util/string_util.h"
#include "common/util/term_util.h"
#include "common/util/trie_map.h"
#include "common/util/unicode_util.h"
#include "common/versions/versions.h"
+12 -1
View File
@@ -1,5 +1,14 @@
add_executable(lsp
handlers/lsp_router.cpp
handlers/initialize.cpp
handlers/text_document/completion.cpp
handlers/text_document/document_color.cpp
handlers/text_document/document_symbol.cpp
handlers/text_document/document_synchronization.cpp
handlers/text_document/formatting.cpp
handlers/text_document/go_to.cpp
handlers/text_document/hover.cpp
handlers/text_document/type_hierarchy.cpp
main.cpp
protocol/common_types.cpp
protocol/completion.cpp
@@ -10,10 +19,12 @@ add_executable(lsp
protocol/formatting.cpp
protocol/hover.cpp
protocol/progress_report.cpp
protocol/type_hierarchy.cpp
state/data/mips_instruction.cpp
state/lsp_requester.cpp
state/workspace.cpp
transport/stdio.cpp)
transport/stdio.cpp
lsp_util.cpp)
target_compile_definitions(lsp PRIVATE -DJSON_DIAGNOSTICS=1)
@@ -1,19 +1,11 @@
// TODO - convert this to a proper class
#include "initialize.h"
#include "third-party/json.hpp"
using json = nlohmann::json;
class InitializeResult {
public:
InitializeResult(){};
json to_json() { return result; }
private:
namespace lsp_handlers {
std::optional<json> initialize(Workspace& workspace, int id, json params) {
json text_document_sync{
{"openClose", true},
{"change", 1}, // Full sync
{"willSave", false},
{"willSave", true},
{"willSaveWaitUntil", false},
{"save", {{"includeText", false}}},
};
@@ -55,6 +47,9 @@ class InitializeResult {
{"renameProvider", false},
{"documentLinkProvider", document_link_provider},
{"executeCommandProvider", execute_command_provider},
{"typeHierarchyProvider", true},
{"experimental", {}},
}}};
};
return result;
}
} // namespace lsp_handlers
+4 -8
View File
@@ -1,14 +1,10 @@
#pragma once
#include "common/log/log.h"
#include "common/util/json_util.h"
#include "lsp/protocol/initialize_result.h"
#include "lsp/state/workspace.h"
#include "third-party/json.hpp"
using json = nlohmann::json;
std::optional<json> initialize_handler(Workspace& /*workspace*/, int /*id*/, json /*params*/) {
InitializeResult result;
return result.to_json();
namespace lsp_handlers {
std::optional<json> initialize(Workspace& workspace, int id, json params);
}
+32 -21
View File
@@ -3,6 +3,7 @@
#include "common/log/log.h"
#include "lsp/handlers/initialize.h"
#include "lsp/handlers/text_document/type_hierarchy.h"
#include "lsp/protocol/error_codes.h"
#include "text_document/completion.h"
#include "text_document/document_color.h"
@@ -14,6 +15,14 @@
#include "fmt/core.h"
json error_resp(ErrorCodes error_code, const std::string& error_message) {
json error{
{"code", static_cast<int>(error_code)},
{"message", error_message},
};
return json{{"error", error}};
}
LSPRoute::LSPRoute() : m_route_type(LSPRouteType::NOOP) {}
LSPRoute::LSPRoute(std::function<void(Workspace&, json)> notification_handler)
@@ -29,41 +38,43 @@ LSPRoute::LSPRoute(std::function<std::optional<json>(Workspace&, int, json)> req
: m_route_type(LSPRouteType::REQUEST_RESPONSE), m_request_handler(request_handler) {}
void LSPRouter::init_routes() {
m_routes["exit"] = LSPRoute([](Workspace& /*workspace*/, nlohmann::json /*params*/) {
lg::info("Shutting down LSP due to explicit request");
exit(0);
});
m_routes["shutdown"] = LSPRoute(
[](Workspace& /*workspace*/, int /*id*/, nlohmann::json /*params*/) -> std::optional<json> {
lg::info("Shutting down LSP due to explicit request");
exit(0);
lg::info("Received shutdown request");
return error_resp(ErrorCodes::UnknownErrorCode, "Problem occurred while existing");
});
m_routes["initialize"] = LSPRoute(initialize_handler);
m_routes["initialize"] = LSPRoute(lsp_handlers::initialize);
m_routes["initialize"].m_generic_post_action = [](Workspace& workspace) {
workspace.set_initialized(true);
};
m_routes["initialized"] = LSPRoute();
m_routes["textDocument/documentSymbol"] = LSPRoute(document_symbols_handler);
m_routes["textDocument/didOpen"] = LSPRoute(did_open_handler, did_open_push_diagnostics);
m_routes["textDocument/didChange"] = LSPRoute(did_change_handler, did_change_push_diagnostics);
m_routes["textDocument/didClose"] = LSPRoute(did_close_handler);
m_routes["textDocument/hover"] = LSPRoute(hover_handler);
m_routes["textDocument/definition"] = LSPRoute(go_to_definition_handler);
m_routes["textDocument/completion"] = LSPRoute(get_completions_handler);
m_routes["textDocument/documentColor"] = LSPRoute(document_color_handler);
m_routes["textDocument/formatting"] = LSPRoute(formatting_handler);
m_routes["textDocument/documentSymbol"] = LSPRoute(lsp_handlers::document_symbols);
m_routes["textDocument/didOpen"] =
LSPRoute(lsp_handlers::did_open, lsp_handlers::did_open_push_diagnostics);
m_routes["textDocument/didChange"] =
LSPRoute(lsp_handlers::did_change, lsp_handlers::did_change_push_diagnostics);
m_routes["textDocument/didClose"] = LSPRoute(lsp_handlers::did_close);
m_routes["textDocument/willSave"] = LSPRoute(lsp_handlers::will_save);
m_routes["textDocument/hover"] = LSPRoute(lsp_handlers::hover);
m_routes["textDocument/definition"] = LSPRoute(lsp_handlers::go_to_definition);
m_routes["textDocument/completion"] = LSPRoute(lsp_handlers::get_completions);
m_routes["textDocument/documentColor"] = LSPRoute(lsp_handlers::document_color);
m_routes["textDocument/formatting"] = LSPRoute(lsp_handlers::formatting);
m_routes["textDocument/prepareTypeHierarchy"] = LSPRoute(lsp_handlers::prepare_type_hierarchy);
m_routes["typeHierarchy/supertypes"] = LSPRoute(lsp_handlers::supertypes_type_hierarchy);
m_routes["typeHierarchy/subtypes"] = LSPRoute(lsp_handlers::subtypes_type_hierarchy);
// TODO - m_routes["textDocument/signatureHelp"] = LSPRoute(get_completions_handler);
// Not Yet Supported Routes, noops
// Not Supported Routes, noops
m_routes["$/cancelRequest"] = LSPRoute();
m_routes["textDocument/documentLink"] = LSPRoute();
m_routes["textDocument/codeLens"] = LSPRoute();
m_routes["textDocument/colorPresentation"] = LSPRoute();
}
json error_resp(ErrorCodes error_code, const std::string& error_message) {
json error{
{"code", static_cast<int>(error_code)},
{"message", error_message},
};
return json{{"error", error}};
}
std::string LSPRouter::make_response(const json& result) {
json content = result;
content["jsonrpc"] = "2.0";
+58
View File
@@ -0,0 +1,58 @@
#include "completion.h"
namespace lsp_handlers {
std::unordered_map<symbol_info::Kind, LSPSpec::CompletionItemKind> completion_item_kind_map = {
{symbol_info::Kind::CONSTANT, LSPSpec::CompletionItemKind::Constant},
{symbol_info::Kind::FUNCTION, LSPSpec::CompletionItemKind::Function},
{symbol_info::Kind::FWD_DECLARED_SYM, LSPSpec::CompletionItemKind::Reference},
{symbol_info::Kind::GLOBAL_VAR, LSPSpec::CompletionItemKind::Variable},
{symbol_info::Kind::INVALID, LSPSpec::CompletionItemKind::Text},
{symbol_info::Kind::LANGUAGE_BUILTIN, LSPSpec::CompletionItemKind::Function},
{symbol_info::Kind::MACRO, LSPSpec::CompletionItemKind::Operator},
{symbol_info::Kind::METHOD, LSPSpec::CompletionItemKind::Method},
{symbol_info::Kind::TYPE, LSPSpec::CompletionItemKind::Class},
};
std::optional<json> get_completions(Workspace& workspace, int /*id*/, json params) {
auto converted_params = params.get<LSPSpec::CompletionParams>();
const auto file_type = workspace.determine_filetype_from_uri(converted_params.textDocument.m_uri);
if (file_type != Workspace::FileType::OpenGOAL) {
return nullptr;
}
auto maybe_tracked_file = workspace.get_tracked_og_file(converted_params.textDocument.m_uri);
if (!maybe_tracked_file) {
return nullptr;
}
std::vector<LSPSpec::CompletionItem> items;
const auto& tracked_file = maybe_tracked_file.value().get();
// The cursor position in the context of completions is always 1 character ahead of the text, we
// move it back 1 spot so we can actually detect what the user has typed so far
LSPSpec::Position new_position = converted_params.position;
if (new_position.m_character > 0) {
new_position.m_character--;
}
const auto symbol = tracked_file.get_symbol_at_position(new_position);
if (!symbol) {
lg::debug("get_completions - no symbol to work from");
} else {
const auto matching_symbols =
workspace.get_symbols_starting_with(tracked_file.m_game_version, symbol.value());
lg::debug("get_completions - found {} symbols", matching_symbols.size());
for (const auto& symbol : matching_symbols) {
LSPSpec::CompletionItem item;
item.label = symbol->m_name;
item.kind = completion_item_kind_map.at(symbol->m_kind);
// TODO - flesh out this more fully when auto-complete with non-globals works as well
items.push_back(item);
}
}
LSPSpec::CompletionList list_result;
list_result.isIncomplete = false; // we want further typing to re-evaluate the list
list_result.items = items;
return list_result;
}
} // namespace lsp_handlers
+4 -8
View File
@@ -2,17 +2,13 @@
#include <optional>
#include "common/util/json_util.h"
#include "lsp/protocol/common_types.h"
#include "lsp/protocol/completion.h"
#include "lsp/state/data/mips_instructions.h"
#include "lsp/state/workspace.h"
std::optional<json> get_completions_handler(Workspace& /*workspace*/, int /*id*/, json params) {
auto converted_params = params.get<LSPSpec::CompletionParams>();
// TODO - these need to be cached,
// TODO - implement response object
return json::array();
namespace lsp_handlers {
std::optional<json> get_completions(Workspace& workspace, int id, json params);
}
@@ -0,0 +1,157 @@
#include "lsp/protocol/document_color.h"
#include <optional>
#include "lsp/protocol/common_types.h"
#include "lsp/state/workspace.h"
int hex_to_dec(const std::string& hex) {
std::string cleaned_string = hex;
if (cleaned_string.starts_with("#x")) {
cleaned_string = cleaned_string.substr(2);
}
return std::stoi(cleaned_string, nullptr, 16);
}
std::unordered_map<GameVersion, std::unordered_map<int, std::tuple<float, float, float, float>>>
game_font_colors = {{GameVersion::Jak1,
{
{0, {223.0, 239.0, 223.0, 255.0}}, {1, {255.0, 255.0, 255.0, 255.0}},
{2, {255.0, 255.0, 255.0, 127.0}}, {3, {255.0, 191.0, 63.0, 255.0}},
{4, {255.0, 199.0, 0.0, 255.0}}, {5, {255.0, 255.0, 0.0, 255.0}},
{6, {63.0, 255.0, 63.0, 255.0}}, {7, {127.0, 127.0, 255.0, 255.0}},
{8, {-1.0, 255.0, 255.0, 255.0}}, {9, {255.0, 127.0, 255.0, 255.0}},
{10, {191.0, 255.0, 255.0, 255.0}}, {11, {127.0, 191.0, 191.0, 255.0}},
{12, {255.0, 255.0, 255.0, 255.0}}, {13, {159.0, 159.0, 159.0, 255.0}},
{14, {255.0, 167.0, 0.0, 255.0}}, {15, {223.0, 255.0, 95.0, 255.0}},
{16, {143.0, 175.0, 15.0, 255.0}}, {17, {175.0, 191.0, 175.0, 255.0}},
{18, {127.0, 143.0, 127.0, 255.0}}, {19, {95.0, 63.0, 95.0, 255.0}},
{20, {255.0, 241.0, 143.0, 255.0}}, {21, {63.0, 187.0, 239.0, 255.0}},
{22, {57.0, 57.0, 57.0, 255.0}}, {23, {127.0, 127.0, 127.0, 255.0}},
{24, {243.0, 153.0, 201.0, 255.0}}, {25, {243.0, 103.0, 103.0, 255.0}},
{26, {31.0, 201.0, 151.0, 255.0}}, {27, {139.0, 147.0, 239.0, 255.0}},
{28, {173.0, 251.0, 255.0, 255.0}}, {29, {253.0, 245.0, 101.0, 255.0}},
{30, {241.0, 241.0, 3.0, 255.0}}, {31, {141.0, 207.0, 243.0, 255.0}},
{32, {223.0, 239.0, 223.0, 255.0}}, {33, {191.0, -1.0, 0.0, 255.0}},
{34, {255.0, 191.0, 63.0, 255.0}},
}},
{GameVersion::Jak2,
{
{0, {223.0, 239.0, 223.0, 255.0}}, {1, {255.0, 255.0, 255.0, 255.0}},
{2, {255.0, 255.0, 255.0, 127.0}}, {3, {255.0, 63.0, 0.0, 255.0}},
{4, {255.0, 199.0, 0.0, 255.0}}, {5, {255.0, 255.0, 0.0, 255.0}},
{6, {63.0, 255.0, 63.0, 255.0}}, {7, {0.0, 63.0, 255.0, 255.0}},
{8, {0.0, 255.0, 255.0, 255.0}}, {9, {255.0, 127.0, 255.0, 255.0}},
{10, {191.0, 255.0, 255.0, 255.0}}, {11, {127.0, 191.0, 191.0, 255.0}},
{12, {255.0, 255.0, 255.0, 255.0}}, {13, {159.0, 159.0, 159.0, 255.0}},
{14, {255.0, 167.0, 0.0, 255.0}}, {15, {223.0, 255.0, 95.0, 255.0}},
{16, {143.0, 175.0, 31.0, 255.0}}, {17, {175.0, 191.0, 175.0, 255.0}},
{18, {127.0, 143.0, 127.0, 255.0}}, {19, {95.0, 63.0, 95.0, 255.0}},
{20, {255.0, 241.0, 143.0, 255.0}}, {21, {63.0, 187.0, 239.0, 255.0}},
{22, {57.0, 57.0, 57.0, 255.0}}, {23, {127.0, 127.0, 127.0, 255.0}},
{24, {243.0, 153.0, 201.0, 255.0}}, {25, {243.0, 103.0, 103.0, 255.0}},
{26, {31.0, 201.0, 151.0, 255.0}}, {27, {139.0, 147.0, 239.0, 255.0}},
{28, {173.0, 251.0, 255.0, 255.0}}, {29, {253.0, 245.0, 101.0, 255.0}},
{30, {241.0, 241.0, 3.0, 255.0}}, {31, {141.0, 207.0, 243.0, 255.0}},
{32, {127.0, 255.0, 255.0, 255.0}}, {33, {127.0, 255.0, 255.0, 255.0}},
{34, {255.0, 255.0, 255.0, 255.0}}, {35, {63.0, 127.0, 127.0, 191.0}},
{36, {223.0, 239.0, 223.0, 255.0}}, {37, {191.0, 0.0, 0.0, 255.0}},
{38, {255.0, 191.0, 63.0, 255.0}}, {39, {0.0, 0.0, 1.0, 255.0}},
}}};
namespace lsp_handlers {
std::optional<json> document_color(Workspace& workspace, int /*id*/, json raw_params) {
auto params = raw_params.get<LSPSpec::DocumentColorParams>();
auto file_type = workspace.determine_filetype_from_uri(params.textDocument.m_uri);
const auto game_version = workspace.determine_game_version_from_uri(params.textDocument.m_uri);
json colors = json::array();
if (!game_version || file_type != Workspace::FileType::OpenGOAL) {
return colors;
}
auto maybe_tracked_file = workspace.get_tracked_og_file(params.textDocument.m_uri);
if (!maybe_tracked_file) {
return colors;
}
const auto& tracked_file = maybe_tracked_file.value().get();
// Search for `(new 'static 'rgba....` forms as these can be colored
// for example - `(new 'static 'rgba :r #x70 :g #x78 :b #x70 :a #x80)`
const auto rgba_results =
tracked_file.search_for_forms_that_begin_with({"(", "new", "'static", "'rgba"});
for (const auto& result : rgba_results) {
// Iterate the forms and find the color and alpha info
float red = 0.0f;
float green = 0.0f;
float blue = 0.0f;
float alpha = 0.0f;
int token_idx = 0;
while (token_idx < result.tokens.size()) {
const auto& token = result.tokens[token_idx];
// in OpenGOAL -- 255 is equal to 128, so we double every value and subtract 1
if (token == ":r" && result.tokens.size() > token_idx + 1) {
red = static_cast<float>((hex_to_dec(result.tokens[token_idx + 1]) * 2) - 1) / 255.0f;
} else if (token == ":g" && result.tokens.size() > token_idx + 1) {
green = static_cast<float>((hex_to_dec(result.tokens[token_idx + 1]) * 2) - 1) / 255.0f;
} else if (token == ":b" && result.tokens.size() > token_idx + 1) {
blue = static_cast<float>((hex_to_dec(result.tokens[token_idx + 1]) * 2) - 1) / 255.0f;
} else if (token == ":a" && result.tokens.size() > token_idx + 1) {
alpha = static_cast<float>((hex_to_dec(result.tokens[token_idx + 1]) * 2) - 1) / 255.0f;
}
token_idx++;
}
LSPSpec::ColorInformation color_info;
color_info.range = {{(uint32_t)result.start_point.first, (uint32_t)result.start_point.second},
{(uint32_t)result.end_point.first, (uint32_t)result.end_point.second}};
color_info.color = LSPSpec::Color{red, green, blue, alpha};
colors.push_back(color_info);
}
// Also search for the `(static-rgba ...` macro
const auto static_rgba_results =
tracked_file.search_for_forms_that_begin_with({"(", "static-rgba"});
for (const auto& result : static_rgba_results) {
float red = static_cast<float>((hex_to_dec(result.tokens[2]) * 2) - 1) / 255.0f;
float green = static_cast<float>((hex_to_dec(result.tokens[3]) * 2) - 1) / 255.0f;
float blue = static_cast<float>((hex_to_dec(result.tokens[4]) * 2) - 1) / 255.0f;
float alpha = static_cast<float>((hex_to_dec(result.tokens[5]) * 2) - 1) / 255.0f;
LSPSpec::ColorInformation color_info;
color_info.range = {{(uint32_t)result.start_point.first, (uint32_t)result.start_point.second},
{(uint32_t)result.end_point.first, (uint32_t)result.end_point.second}};
color_info.color = LSPSpec::Color{red, green, blue, alpha};
colors.push_back(color_info);
}
// Search for `(font-color ...` forms
const auto font_color_results =
tracked_file.search_for_forms_that_begin_with({"(", "font-color"});
const auto font_color_enum_entries =
workspace.get_enum_entries("font-color", game_version.value());
if (!font_color_enum_entries.empty() &&
game_font_colors.find(game_version.value()) != game_font_colors.end()) {
for (const auto& result : font_color_results) {
const auto font_color = result.tokens[2];
if (font_color_enum_entries.find(font_color) != font_color_enum_entries.end()) {
const auto font_color_val = font_color_enum_entries.at(font_color);
if (game_font_colors[game_version.value()].find(font_color_val) !=
game_font_colors[game_version.value()].end()) {
const auto& [red, green, blue, alpha] =
game_font_colors[game_version.value()].at(font_color_val);
LSPSpec::ColorInformation color_info;
color_info.range = {
{(uint32_t)result.start_point.first, (uint32_t)result.start_point.second},
{(uint32_t)result.end_point.first, (uint32_t)result.end_point.second}};
color_info.color =
LSPSpec::Color{red / 255.0f, green / 255.0f, blue / 255.0f, alpha / 255.0f};
colors.push_back(color_info);
}
}
}
}
return colors;
}
} // namespace lsp_handlers
+5 -67
View File
@@ -2,76 +2,14 @@
#include <optional>
#include "common/util/string_util.h"
#include "common/util/json_util.h"
#include "lsp/protocol/common_types.h"
#include "lsp/protocol/document_color.h"
#include "lsp/state/workspace.h"
float hexToFloat(const std::string& hex) {
int value = std::stoi(hex, nullptr, 16);
return static_cast<float>(value) / 255.0f;
}
namespace lsp_handlers {
std::optional<LSPSpec::Color> color_hexstring_to_lsp_color(const std::string& color_name) {
if (!str_util::contains(color_name, "#")) {
return {};
}
const auto color_tokens = str_util::split(color_name, '#');
const auto hexstring = color_tokens.at(1);
std::string red_hex = hexstring.substr(0, 2);
std::string green_hex = hexstring.substr(2, 2);
std::string blue_hex = hexstring.substr(4, 2);
std::optional<json> document_color(Workspace& workspace, int id, json raw_params);
float red = hexToFloat(red_hex);
float green = hexToFloat(green_hex);
float blue = hexToFloat(blue_hex);
return LSPSpec::Color{red, green, blue, 1.0};
}
std::optional<json> document_color_handler(Workspace& /*workspace*/, int /*id*/, json raw_params) {
auto params = raw_params.get<LSPSpec::DocumentColorParams>();
json colors = json::array();
// TODO - hex strings aren't desirable in the `font-color` enum
// this could be used for the `new 'static 'rgba` instances but that requires proper
// AST support as it cannot (and should not) be assumed that all 4 components will be on the same
// line
return colors;
//// Iterate through document, mark text colors ourselves
// auto file_type = workspace.determine_filetype_from_uri(params.textDocument.m_uri);
// if (file_type == Workspace::FileType::OpenGOAL) {
// auto tracked_file = workspace.get_tracked_og_file(params.textDocument.m_uri);
// if (!tracked_file) {
// return {};
// }
// // This is something that is ok to be a regex, because it's very niche
// for (int i = 0; i < tracked_file->m_lines.size(); i++) {
// const auto& line = tracked_file->m_lines.at(i);
// std::smatch matches;
// std::regex regex("\\(font-color ([^)]*)\\)");
// std::sregex_iterator iter(line.begin(), line.end(), regex);
// std::sregex_iterator end;
// for (; iter != end; iter++) {
// std::smatch match = *iter;
// std::string capture_group = match.str(1);
// LSPSpec::ColorInformation color_info;
// color_info.range = {{i, match.position(1)}, {i, match.position(1) + match.size()}};
// const auto color = color_hexstring_to_lsp_color(capture_group);
// if (!color) {
// continue;
// }
// color_info.color = color.value();
// colors.push_back(color_info);
// lg::debug("color - {}", capture_group);
// }
// }
//}
// return colors;
}
} // namespace lsp_handlers
@@ -0,0 +1,53 @@
#include "document_symbol.h"
#include "third-party/json.hpp"
using json = nlohmann::json;
std::optional<json> ir_symbols(Workspace& workspace, LSPSpec::DocumentSymbolParams params) {
json symbols = json::array();
auto maybe_tracked_file = workspace.get_tracked_ir_file(params.m_textDocument.m_uri);
if (!maybe_tracked_file) {
return symbols;
}
const auto& tracked_file = maybe_tracked_file.value().get();
for (const auto& symbol : tracked_file.m_symbols) {
symbols.push_back(symbol);
}
return symbols;
}
std::optional<json> og_symbols(Workspace& workspace, LSPSpec::DocumentSymbolParams params) {
json symbols = json::array();
auto maybe_tracked_file = workspace.get_tracked_og_file(params.m_textDocument.m_uri);
if (!maybe_tracked_file) {
return symbols;
}
const auto& tracked_file = maybe_tracked_file.value().get();
for (const auto& symbol : tracked_file.m_symbols) {
symbols.push_back(symbol);
}
return symbols;
}
namespace lsp_handlers {
std::optional<json> document_symbols(Workspace& workspace, int /*id*/, json params) {
auto converted_params = params.get<LSPSpec::DocumentSymbolParams>();
const auto file_type =
workspace.determine_filetype_from_uri(converted_params.m_textDocument.m_uri);
if (file_type == Workspace::FileType::OpenGOALIR) {
return ir_symbols(workspace, converted_params);
} else if (file_type == Workspace::FileType::OpenGOAL) {
return og_symbols(workspace, converted_params);
}
return json::array();
}
} // namespace lsp_handlers
+5 -18
View File
@@ -2,26 +2,13 @@
#include <optional>
#include "common/util/json_util.h"
#include "lsp/protocol/common_types.h"
#include "lsp/state/workspace.h"
#include "third-party/json.hpp"
namespace lsp_handlers {
using json = nlohmann::json;
std::optional<json> document_symbols(Workspace& workspace, int id, json params);
std::optional<json> document_symbols_handler(Workspace& workspace, int /*id*/, json params) {
auto converted_params = params.get<LSPSpec::DocumentSymbolParams>();
auto tracked_file = workspace.get_tracked_ir_file(converted_params.m_textDocument.m_uri);
if (!tracked_file) {
return {};
}
// TODO - convert to type!
json arr = json::array();
for (const auto& symbol : tracked_file.value().m_symbols) {
arr.push_back(symbol);
}
return arr;
}
} // namespace lsp_handlers
@@ -0,0 +1,77 @@
#include "document_synchronization.h"
namespace lsp_handlers {
void did_open(Workspace& workspace, json raw_params) {
auto params = raw_params.get<LSPSpec::DidOpenTextDocumentParams>();
workspace.start_tracking_file(params.m_textDocument.m_uri, params.m_textDocument.m_languageId,
params.m_textDocument.m_text);
}
void did_change(Workspace& workspace, json raw_params) {
auto params = raw_params.get<LSPSpec::DidChangeTextDocumentParams>();
for (const auto& change : params.m_contentChanges) {
workspace.update_tracked_file(params.m_textDocument.m_uri, change.m_text);
}
}
void did_close(Workspace& workspace, json raw_params) {
auto params = raw_params.get<LSPSpec::DidCloseTextDocumentParams>();
workspace.stop_tracking_file(params.m_textDocument.m_uri);
}
void will_save(Workspace& workspace, json raw_params) {
auto params = raw_params.get<LSPSpec::WillSaveTextDocumentParams>();
workspace.tracked_file_will_save(params.textDocument.m_uri);
}
std::optional<json> did_open_push_diagnostics(Workspace& workspace, json raw_params) {
auto params = raw_params.get<LSPSpec::DidOpenTextDocumentParams>();
const auto file_type =
workspace.determine_filetype_from_languageid(params.m_textDocument.m_languageId);
LSPSpec::PublishDiagnosticParams publish_params;
publish_params.m_uri = params.m_textDocument.m_uri;
publish_params.m_version = params.m_textDocument.m_version;
if (file_type == Workspace::FileType::OpenGOALIR) {
auto maybe_tracked_file = workspace.get_tracked_ir_file(params.m_textDocument.m_uri);
if (!maybe_tracked_file) {
return {};
}
const auto& tracked_file = maybe_tracked_file.value().get();
publish_params.m_diagnostics = tracked_file.m_diagnostics;
}
json response;
response["method"] = "textDocument/publishDiagnostics";
response["params"] = publish_params;
return response;
}
std::optional<json> did_change_push_diagnostics(Workspace& workspace, json raw_params) {
auto params = raw_params.get<LSPSpec::DidChangeTextDocumentParams>();
const auto file_type = workspace.determine_filetype_from_uri(params.m_textDocument.m_uri);
LSPSpec::PublishDiagnosticParams publish_params;
publish_params.m_uri = params.m_textDocument.m_uri;
publish_params.m_version = params.m_textDocument.m_version;
if (file_type == Workspace::FileType::OpenGOALIR) {
auto maybe_tracked_file = workspace.get_tracked_ir_file(params.m_textDocument.m_uri);
if (!maybe_tracked_file) {
return {};
}
const auto& tracked_file = maybe_tracked_file.value().get();
publish_params.m_diagnostics = tracked_file.m_diagnostics;
}
json response;
response["method"] = "textDocument/publishDiagnostics";
response["params"] = publish_params;
return response;
}
} // namespace lsp_handlers
@@ -2,76 +2,20 @@
#include <optional>
#include "common/util/json_util.h"
#include "lsp/protocol/document_diagnostics.h"
#include "lsp/protocol/document_synchronization.h"
#include "lsp/state/workspace.h"
#include "third-party/json.hpp"
namespace lsp_handlers {
using json = nlohmann::json;
void did_open(Workspace& workspace, json raw_params);
void did_change(Workspace& workspace, json raw_params);
void did_close(Workspace& workspace, json raw_params);
void will_save(Workspace& workspace, json raw_params);
void did_open_handler(Workspace& workspace, json raw_params) {
auto params = raw_params.get<LSPSpec::DidOpenTextDocumentParams>();
workspace.start_tracking_file(params.m_textDocument.m_uri, params.m_textDocument.m_languageId,
params.m_textDocument.m_text);
}
std::optional<json> did_open_push_diagnostics(Workspace& workspace, json raw_params);
std::optional<json> did_change_push_diagnostics(Workspace& workspace, json raw_params);
void did_change_handler(Workspace& workspace, json raw_params) {
auto params = raw_params.get<LSPSpec::DidChangeTextDocumentParams>();
for (const auto& change : params.m_contentChanges) {
workspace.update_tracked_file(params.m_textDocument.m_uri, change.m_text);
}
}
void did_close_handler(Workspace& workspace, json raw_params) {
auto params = raw_params.get<LSPSpec::DidCloseTextDocumentParams>();
workspace.stop_tracking_file(params.m_textDocument.m_uri);
}
std::optional<json> did_open_push_diagnostics(Workspace& workspace, json raw_params) {
auto params = raw_params.get<LSPSpec::DidOpenTextDocumentParams>();
const auto file_type =
workspace.determine_filetype_from_languageid(params.m_textDocument.m_languageId);
LSPSpec::PublishDiagnosticParams publish_params;
publish_params.m_uri = params.m_textDocument.m_uri;
publish_params.m_version = params.m_textDocument.m_version;
if (file_type == Workspace::FileType::OpenGOALIR) {
auto tracked_file = workspace.get_tracked_ir_file(params.m_textDocument.m_uri);
if (!tracked_file) {
return {};
}
publish_params.m_diagnostics = tracked_file.value().m_diagnostics;
}
json response;
response["method"] = "textDocument/publishDiagnostics";
response["params"] = publish_params;
return response;
}
std::optional<json> did_change_push_diagnostics(Workspace& workspace, json raw_params) {
auto params = raw_params.get<LSPSpec::DidChangeTextDocumentParams>();
const auto file_type = workspace.determine_filetype_from_uri(params.m_textDocument.m_uri);
LSPSpec::PublishDiagnosticParams publish_params;
publish_params.m_uri = params.m_textDocument.m_uri;
publish_params.m_version = params.m_textDocument.m_version;
if (file_type == Workspace::FileType::OpenGOALIR) {
auto tracked_file = workspace.get_tracked_ir_file(params.m_textDocument.m_uri);
if (!tracked_file) {
return {};
}
publish_params.m_diagnostics = tracked_file.value().m_diagnostics;
}
json response;
response["method"] = "textDocument/publishDiagnostics";
response["params"] = publish_params;
return response;
}
} // namespace lsp_handlers
+38
View File
@@ -0,0 +1,38 @@
#include "formatting.h"
#include "common/formatter/formatter.h"
#include "lsp/protocol/common_types.h"
#include "lsp/protocol/formatting.h"
#include "lsp/state/data/mips_instructions.h"
#include "lsp/state/workspace.h"
namespace lsp_handlers {
std::optional<json> formatting(Workspace& workspace, int id, json raw_params) {
auto params = raw_params.get<LSPSpec::DocumentFormattingParams>();
const auto file_type = workspace.determine_filetype_from_uri(params.textDocument.m_uri);
if (file_type == Workspace::FileType::OpenGOALIR) {
return nullptr;
} else if (file_type == Workspace::FileType::OpenGOAL) {
auto maybe_tracked_file = workspace.get_tracked_og_file(params.textDocument.m_uri);
if (!maybe_tracked_file) {
return {};
}
const auto& tracked_file = maybe_tracked_file.value().get();
const auto result = formatter::format_code(tracked_file.m_content);
if (!result) {
return nullptr;
}
json edits = json::array();
auto format_edit = LSPSpec::TextEdit();
format_edit.range = {{0, 0}, {(uint32_t)tracked_file.m_line_count, 0}};
format_edit.newText = result.value();
edits.push_back(format_edit);
return edits;
}
return nullptr;
}
} // namespace lsp_handlers
+4 -28
View File
@@ -2,36 +2,12 @@
#include <optional>
#include "common/formatter/formatter.h"
#include "common/util/json_util.h"
#include "lsp/protocol/common_types.h"
#include "lsp/protocol/formatting.h"
#include "lsp/state/data/mips_instructions.h"
#include "lsp/state/workspace.h"
std::optional<json> formatting_handler(Workspace& workspace, int /*id*/, json raw_params) {
auto params = raw_params.get<LSPSpec::DocumentFormattingParams>();
const auto file_type = workspace.determine_filetype_from_uri(params.textDocument.m_uri);
namespace lsp_handlers {
if (file_type == Workspace::FileType::OpenGOALIR) {
return nullptr;
} else if (file_type == Workspace::FileType::OpenGOAL) {
auto tracked_file = workspace.get_tracked_og_file(params.textDocument.m_uri);
if (!tracked_file) {
return nullptr;
}
// TODO move away from holding the content directly
const auto result = formatter::format_code(tracked_file->m_content);
if (!result) {
return nullptr;
}
json edits = json::array();
auto format_edit = LSPSpec::TextEdit();
format_edit.range = {{0, 0}, {(uint32_t)tracked_file->m_lines.size(), 0}};
format_edit.newText = result.value();
edits.push_back(format_edit);
return edits;
}
std::optional<json> formatting(Workspace& workspace, int id, json raw_params);
return nullptr;
}
} // namespace lsp_handlers
+61
View File
@@ -0,0 +1,61 @@
#include "go_to.h"
namespace lsp_handlers {
std::optional<json> go_to_definition(Workspace& workspace, int /*id*/, json raw_params) {
auto params = raw_params.get<LSPSpec::TextDocumentPositionParams>();
const auto file_type = workspace.determine_filetype_from_uri(params.m_textDocument.m_uri);
json locations = json::array();
if (file_type == Workspace::FileType::OpenGOALIR) {
auto maybe_tracked_file = workspace.get_tracked_ir_file(params.m_textDocument.m_uri);
if (!maybe_tracked_file) {
return {};
}
const auto& tracked_file = maybe_tracked_file.value().get();
auto symbol_name = tracked_file.get_symbol_at_position(params.m_position);
if (!symbol_name) {
return {};
}
auto symbol_info = workspace.get_definition_info_from_all_types(symbol_name.value(),
tracked_file.m_all_types_uri);
if (!symbol_info) {
return {};
}
LSPSpec::Location location;
location.m_uri = tracked_file.m_all_types_uri;
location.m_range.m_start = {(uint32_t)symbol_info.value().definition_info->line_idx_to_display,
(uint32_t)symbol_info.value().definition_info->pos_in_line};
location.m_range.m_end = {(uint32_t)symbol_info.value().definition_info->line_idx_to_display,
(uint32_t)symbol_info.value().definition_info->pos_in_line};
locations.push_back(location);
} else if (file_type == Workspace::FileType::OpenGOAL) {
auto maybe_tracked_file = workspace.get_tracked_og_file(params.m_textDocument.m_uri);
if (!maybe_tracked_file) {
return {};
}
const auto& tracked_file = maybe_tracked_file.value().get();
const auto symbol = tracked_file.get_symbol_at_position(params.m_position);
if (!symbol) {
return {};
}
const auto& symbol_info = workspace.get_global_symbol_info(tracked_file, symbol.value());
if (!symbol_info) {
return {};
}
const auto& def_loc = workspace.get_symbol_def_location(tracked_file, symbol_info.value());
if (!def_loc) {
return {};
}
LSPSpec::Location location;
location.m_uri = def_loc->file_path;
location.m_range.m_start = {(uint32_t)def_loc->line_idx, (uint32_t)def_loc->char_idx};
location.m_range.m_end = {(uint32_t)def_loc->line_idx, (uint32_t)def_loc->char_idx};
locations.push_back(location);
}
return locations;
}
} // namespace lsp_handlers
+4 -58
View File
@@ -2,65 +2,11 @@
#include <optional>
#include "common/util/json_util.h"
#include "lsp/protocol/common_types.h"
#include "lsp/protocol/hover.h"
#include "lsp/state/data/mips_instructions.h"
#include "lsp/state/workspace.h"
std::optional<json> go_to_definition_handler(Workspace& workspace, int /*id*/, json raw_params) {
auto params = raw_params.get<LSPSpec::TextDocumentPositionParams>();
const auto file_type = workspace.determine_filetype_from_uri(params.m_textDocument.m_uri);
json locations = json::array();
if (file_type == Workspace::FileType::OpenGOALIR) {
auto tracked_file = workspace.get_tracked_ir_file(params.m_textDocument.m_uri);
if (!tracked_file) {
return {};
}
auto symbol_name = tracked_file->get_symbol_at_position(params.m_position);
if (!symbol_name) {
return {};
}
auto symbol_info = workspace.get_definition_info_from_all_types(symbol_name.value(),
tracked_file->m_all_types_uri);
if (!symbol_info) {
return {};
}
LSPSpec::Location location;
location.m_uri = tracked_file->m_all_types_uri;
location.m_range.m_start = {(uint32_t)symbol_info.value().definition_info->line_idx_to_display,
(uint32_t)symbol_info.value().definition_info->pos_in_line};
location.m_range.m_end = {(uint32_t)symbol_info.value().definition_info->line_idx_to_display,
(uint32_t)symbol_info.value().definition_info->pos_in_line};
locations.push_back(location);
} else if (file_type == Workspace::FileType::OpenGOAL) {
auto tracked_file = workspace.get_tracked_og_file(params.m_textDocument.m_uri);
if (!tracked_file) {
return {};
}
const auto symbol = tracked_file->get_symbol_at_position(params.m_position);
if (!symbol) {
return {};
}
const auto& symbol_info =
workspace.get_global_symbol_info(tracked_file.value(), symbol.value());
if (!symbol_info) {
return {};
}
const auto& def_loc =
workspace.get_symbol_def_location(tracked_file.value(), symbol_info.value());
if (!def_loc) {
return {};
}
LSPSpec::Location location;
location.m_uri = def_loc->filename;
location.m_range.m_start = {(uint32_t)def_loc->line_idx, (uint32_t)def_loc->char_idx};
location.m_range.m_end = {(uint32_t)def_loc->line_idx, (uint32_t)def_loc->char_idx};
locations.push_back(location);
}
return locations;
namespace lsp_handlers {
std::optional<json> go_to_definition(Workspace& workspace, int id, json raw_params);
}
+269
View File
@@ -0,0 +1,269 @@
#include "hover.h"
bool is_number(const std::string& s) {
return !s.empty() && std::find_if(s.begin(), s.end(),
[](unsigned char c) { return !std::isdigit(c); }) == s.end();
}
std::vector<std::string> og_method_names = {"new", "delete", "print", "inspect", "length",
"asize-of", "copy", "relocate", "mem-usage"};
std::optional<LSPSpec::Hover> hover_handler_ir(Workspace& workspace,
const LSPSpec::TextDocumentPositionParams& params,
const WorkspaceIRFile& tracked_file) {
// See if it's an OpenGOAL symbol or a MIPS mnemonic
auto symbol_name = tracked_file.get_symbol_at_position(params.m_position);
auto token_at_pos = tracked_file.get_mips_instruction_at_position(params.m_position);
if (!symbol_name && !token_at_pos) {
return {};
}
LSPSpec::MarkupContent markup;
markup.m_kind = "markdown";
// TODO - try specifying the range so it highlights everything, ie. `c.lt.s`
// Prefer symbols
if (symbol_name) {
lg::debug("hover - symbol match - {}", symbol_name.value());
auto symbol_info = workspace.get_definition_info_from_all_types(symbol_name.value(),
tracked_file.m_all_types_uri);
if (symbol_info && symbol_info.value().docstring.has_value()) {
std::string docstring = symbol_info.value().docstring.value();
lg::debug("hover - symbol has docstring - {}", docstring);
// A docstring exists, print it!
// By convention, docstrings are assumed to be markdown, they support code-blocks everything
// the only thing extra we do, is replace [[<symbol>]] with links if available
std::unordered_map<std::string, std::string> symbol_replacements = {};
std::smatch match;
std::string::const_iterator searchStart(docstring.cbegin());
while (
std::regex_search(searchStart, docstring.cend(), match, std::regex("\\[{2}(.*)\\]{2}"))) {
// Have we already accounted for this symbol?
const auto& name = match[1].str();
if (symbol_replacements.count(name) != 0) {
continue;
}
// Get this symbols info
auto symbol_info =
workspace.get_definition_info_from_all_types(name, tracked_file.m_all_types_uri);
if (!symbol_info) {
symbol_replacements[name] = fmt::format("_{}_", name);
} else {
// Construct path
auto symbol_uri =
fmt::format("{}#L{}%2C{}", tracked_file.m_all_types_uri,
symbol_info.value().definition_info->line_idx_to_display + 1,
symbol_info.value().definition_info->pos_in_line);
symbol_replacements[name] = fmt::format("[{}]({})", name, symbol_uri);
}
searchStart = match.suffix().first;
}
// Replace all symbol occurences
for (const auto& [key, val] : symbol_replacements) {
docstring = std::regex_replace(docstring, std::regex("\\[{2}" + key + "\\]{2}"), val);
}
markup.m_value = docstring;
LSPSpec::Hover hover_resp;
hover_resp.m_contents = markup;
return hover_resp;
} else if (!token_at_pos) {
// Check if it's a number, and if so we'll do some numeric conversions
if (!is_number(symbol_name.value())) {
return {};
}
lg::debug("hover - numeric match - {}", symbol_name.value());
// Construct the body
std::string body = "";
uint32_t num = std::atoi(symbol_name.value().data());
// Assuming it comes in as Decimal
body += "| Base | Value |\n";
body += "|---------|-------|\n";
body += fmt::format("| Decimal | `{:d}` |\n", num);
body += fmt::format("| Hex | `{:X}` |\n", num);
// TODO - would be nice to format as groups of 4
body += fmt::format("| Binary | `{:b}` |\n", num);
if (num >= 16 && (num - 16) % 4 == 0) {
uint32_t method_id = (num - 16) / 4;
std::string method_name = "not built-in";
if (method_id <= 8) {
method_name = og_method_names.at(method_id);
}
body += fmt::format("| Method ID | `{}` - `{}` |\n", method_id, method_name);
}
body += fmt::format("| Octal | `{:o}` |\n", num);
markup.m_value = body;
LSPSpec::Hover hover_resp;
hover_resp.m_contents = markup;
return hover_resp;
}
}
// Otherwise, maybe it's a MIPS instruction
if (token_at_pos) {
lg::debug("hover - token match - {}", token_at_pos.value());
auto& token = token_at_pos.value();
std::transform(token.begin(), token.end(), token.begin(),
[](unsigned char c) { return std::tolower(c); });
// Find the instruction, there are some edge-cases here where they could be multiple
// TODO - havn't addressed `bc` and such instructions! Those need to be prefixed matched
std::vector<std::string> ee_instructions = {};
std::vector<std::string> vu_instructions = {};
for (const auto& instr : LSPData::MIPS_INSTRUCTION_LIST) {
auto mnemonic_lower = instr.mnemonic;
std::transform(mnemonic_lower.begin(), mnemonic_lower.end(), mnemonic_lower.begin(),
[](unsigned char c) { return std::tolower(c); });
if (mnemonic_lower == token) {
if (instr.type == "ee") {
ee_instructions.push_back(fmt::format("- _{}_\n\n", instr.description));
} else {
vu_instructions.push_back(fmt::format("- _{}_\n\n", instr.description));
}
}
}
// Construct the body
std::string body = "";
if (!ee_instructions.empty()) {
body += "**EE Instructions**\n\n";
for (const auto& instr : ee_instructions) {
body += instr;
}
body += "___\n\n";
}
if (!vu_instructions.empty()) {
body += "**VU Instructions**\n\n";
for (const auto& instr : vu_instructions) {
body += instr;
}
body += "___\n\n";
}
markup.m_value = body;
LSPSpec::Hover hover_resp;
hover_resp.m_contents = markup;
return hover_resp;
}
return {};
}
std::string truncate_docstring(const std::string& docstring) {
std::string truncated = "";
const auto lines = str_util::split(docstring);
for (const auto& line : lines) {
const auto trimmed_line = str_util::ltrim(line);
if (str_util::starts_with(trimmed_line, "@")) {
break;
}
truncated += trimmed_line + "\n";
}
return truncated;
}
namespace lsp_handlers {
std::optional<json> hover(Workspace& workspace, int /*id*/, json raw_params) {
auto params = raw_params.get<LSPSpec::TextDocumentPositionParams>();
auto file_type = workspace.determine_filetype_from_uri(params.m_textDocument.m_uri);
if (file_type == Workspace::FileType::OpenGOALIR) {
auto tracked_file = workspace.get_tracked_ir_file(params.m_textDocument.m_uri);
if (!tracked_file) {
return {};
}
return hover_handler_ir(workspace, params, tracked_file.value());
} else if (file_type == Workspace::FileType::OpenGOAL) {
auto maybe_tracked_file = workspace.get_tracked_og_file(params.m_textDocument.m_uri);
if (!maybe_tracked_file) {
return {};
}
const auto& tracked_file = maybe_tracked_file.value().get();
const auto symbol = tracked_file.get_symbol_at_position(params.m_position);
if (!symbol) {
lg::debug("hover - no symbol");
return {};
}
// TODO - there is an issue with docstrings and overridden methods
const auto& symbol_info = workspace.get_global_symbol_info(tracked_file, symbol.value());
if (!symbol_info) {
lg::debug("hover - no symbol info - {}", symbol.value());
return {};
}
LSPSpec::MarkupContent markup;
markup.m_kind = "markdown";
const auto args = Docs::get_args_from_docstring(symbol_info.value()->m_args,
symbol_info.value()->m_docstring);
std::string signature = "";
bool takes_args = true;
if (symbol_info.value()->m_kind == symbol_info::Kind::FUNCTION) {
signature += "function ";
} else if (symbol_info.value()->m_kind == symbol_info::Kind::METHOD) {
signature += "method ";
} else if (symbol_info.value()->m_kind == symbol_info::Kind::MACRO) {
signature += "macro ";
} else {
takes_args = false;
}
// TODO - others useful, probably states?
auto type_info = workspace.get_symbol_typeinfo(tracked_file, symbol.value());
signature += symbol.value();
if (takes_args) {
signature += "(";
for (int i = 0; i < (int)args.size(); i++) {
const auto& arg = args.at(i);
if (i == (int)args.size() - 1) {
signature += fmt::format("{}: {}", arg.name, arg.type);
} else {
signature += fmt::format("{}: {}, ", arg.name, arg.type);
}
}
signature += ")";
if (symbol_info.value()->m_kind == symbol_info::Kind::FUNCTION && type_info) {
signature += fmt::format(": {}", type_info->first.last_arg().base_type());
} else if (symbol_info.value()->m_kind == symbol_info::Kind::METHOD) {
signature +=
fmt::format(": {}", symbol_info.value()->m_method_info.type.last_arg().base_type());
}
} else if (type_info) {
signature += fmt::format(": {}", type_info->second->get_parent());
}
std::string body = fmt::format("```opengoal\n{}\n```\n\n", signature);
body += "___\n\n";
if (!symbol_info.value()->m_docstring.empty()) {
body += truncate_docstring(symbol_info.value()->m_docstring) + "\n\n";
}
// TODO - support @see/@returns/[[reference]]
for (const auto& arg : args) {
std::string param_line = "";
if (arg.is_mutated) {
param_line += fmt::format("*@param!* `{}: {}`", arg.name, arg.type);
} else if (arg.is_optional) {
param_line += fmt::format("*@param?* `{}: {}`", arg.name, arg.type);
} else if (arg.is_unused) {
param_line += fmt::format("*@param_* `{}: {}`", arg.name, arg.type);
} else {
param_line += fmt::format("*@param* `{}: {}`", arg.name, arg.type);
}
if (!arg.description.empty()) {
param_line += fmt::format(" - {}\n\n", arg.description);
} else {
param_line += "\n\n";
}
body += param_line;
}
markup.m_value = body;
LSPSpec::Hover hover_resp;
hover_resp.m_contents = markup;
return hover_resp;
}
return {};
}
} // namespace lsp_handlers
+6 -268
View File
@@ -3,278 +3,16 @@
#include <optional>
#include <regex>
#include "common/util/json_util.h"
#include "common/util/string_util.h"
#include "goalc/compiler/docs/DocTypes.h"
#include "lsp/protocol/common_types.h"
#include "lsp/protocol/hover.h"
#include "lsp/state/data/mips_instructions.h"
#include "lsp/state/workspace.h"
bool is_number(const std::string& s) {
return !s.empty() && std::find_if(s.begin(), s.end(),
[](unsigned char c) { return !std::isdigit(c); }) == s.end();
}
namespace lsp_handlers {
std::optional<json> hover(Workspace& workspace, int id, json raw_params);
std::vector<std::string> og_method_names = {"new", "delete", "print", "inspect", "length",
"asize-of", "copy", "relocate", "mem-usage"};
std::optional<LSPSpec::Hover> hover_handler_ir(Workspace& workspace,
const LSPSpec::TextDocumentPositionParams& params,
const WorkspaceIRFile& tracked_file) {
// See if it's an OpenGOAL symbol or a MIPS mnemonic
auto symbol_name = tracked_file.get_symbol_at_position(params.m_position);
auto token_at_pos = tracked_file.get_mips_instruction_at_position(params.m_position);
if (!symbol_name && !token_at_pos) {
return {};
}
LSPSpec::MarkupContent markup;
markup.m_kind = "markdown";
// TODO - try specifying the range so it highlights everything, ie. `c.lt.s`
// Prefer symbols
if (symbol_name) {
lg::debug("hover - symbol match - {}", symbol_name.value());
auto symbol_info = workspace.get_definition_info_from_all_types(symbol_name.value(),
tracked_file.m_all_types_uri);
if (symbol_info && symbol_info.value().docstring.has_value()) {
std::string docstring = symbol_info.value().docstring.value();
lg::debug("hover - symbol has docstring - {}", docstring);
// A docstring exists, print it!
// By convention, docstrings are assumed to be markdown, they support code-blocks everything
// the only thing extra we do, is replace [[<symbol>]] with links if available
std::unordered_map<std::string, std::string> symbol_replacements = {};
std::smatch match;
std::string::const_iterator searchStart(docstring.cbegin());
while (
std::regex_search(searchStart, docstring.cend(), match, std::regex("\\[{2}(.*)\\]{2}"))) {
// Have we already accounted for this symbol?
const auto& name = match[1].str();
if (symbol_replacements.count(name) != 0) {
continue;
}
// Get this symbols info
auto symbol_info =
workspace.get_definition_info_from_all_types(name, tracked_file.m_all_types_uri);
if (!symbol_info) {
symbol_replacements[name] = fmt::format("_{}_", name);
} else {
// Construct path
auto symbol_uri =
fmt::format("{}#L{}%2C{}", tracked_file.m_all_types_uri,
symbol_info.value().definition_info->line_idx_to_display + 1,
symbol_info.value().definition_info->pos_in_line);
symbol_replacements[name] = fmt::format("[{}]({})", name, symbol_uri);
}
searchStart = match.suffix().first;
}
// Replace all symbol occurences
for (const auto& [key, val] : symbol_replacements) {
docstring = std::regex_replace(docstring, std::regex("\\[{2}" + key + "\\]{2}"), val);
}
markup.m_value = docstring;
LSPSpec::Hover hover_resp;
hover_resp.m_contents = markup;
return hover_resp;
} else if (!token_at_pos) {
// Check if it's a number, and if so we'll do some numeric conversions
if (!is_number(symbol_name.value())) {
return {};
}
lg::debug("hover - numeric match - {}", symbol_name.value());
// Construct the body
std::string body = "";
uint32_t num = std::atoi(symbol_name.value().data());
// Assuming it comes in as Decimal
body += "| Base | Value |\n";
body += "|---------|-------|\n";
body += fmt::format("| Decimal | `{:d}` |\n", num);
body += fmt::format("| Hex | `{:X}` |\n", num);
// TODO - would be nice to format as groups of 4
body += fmt::format("| Binary | `{:b}` |\n", num);
if (num >= 16 && (num - 16) % 4 == 0) {
uint32_t method_id = (num - 16) / 4;
std::string method_name = "not built-in";
if (method_id <= 8) {
method_name = og_method_names.at(method_id);
}
body += fmt::format("| Method ID | `{}` - `{}` |\n", method_id, method_name);
}
body += fmt::format("| Octal | `{:o}` |\n", num);
markup.m_value = body;
LSPSpec::Hover hover_resp;
hover_resp.m_contents = markup;
return hover_resp;
}
}
// Otherwise, maybe it's a MIPS instruction
if (token_at_pos) {
lg::debug("hover - token match - {}", token_at_pos.value());
auto& token = token_at_pos.value();
std::transform(token.begin(), token.end(), token.begin(),
[](unsigned char c) { return std::tolower(c); });
// Find the instruction, there are some edge-cases here where they could be multiple
// TODO - havn't addressed `bc` and such instructions! Those need to be prefixed matched
std::vector<std::string> ee_instructions = {};
std::vector<std::string> vu_instructions = {};
for (const auto& instr : LSPData::MIPS_INSTRUCTION_LIST) {
auto mnemonic_lower = instr.mnemonic;
std::transform(mnemonic_lower.begin(), mnemonic_lower.end(), mnemonic_lower.begin(),
[](unsigned char c) { return std::tolower(c); });
if (mnemonic_lower == token) {
if (instr.type == "ee") {
ee_instructions.push_back(fmt::format("- _{}_\n\n", instr.description));
} else {
vu_instructions.push_back(fmt::format("- _{}_\n\n", instr.description));
}
}
}
// Construct the body
std::string body = "";
if (!ee_instructions.empty()) {
body += "**EE Instructions**\n\n";
for (const auto& instr : ee_instructions) {
body += instr;
}
body += "___\n\n";
}
if (!vu_instructions.empty()) {
body += "**VU Instructions**\n\n";
for (const auto& instr : vu_instructions) {
body += instr;
}
body += "___\n\n";
}
markup.m_value = body;
LSPSpec::Hover hover_resp;
hover_resp.m_contents = markup;
return hover_resp;
}
return {};
}
std::string truncate_docstring(const std::string& docstring) {
std::string truncated = "";
const auto lines = str_util::split(docstring);
for (const auto& line : lines) {
const auto trimmed_line = str_util::ltrim(line);
if (str_util::starts_with(trimmed_line, "@")) {
break;
}
truncated += trimmed_line + "\n";
}
return truncated;
}
std::optional<json> hover_handler(Workspace& workspace, int /*id*/, json raw_params) {
auto params = raw_params.get<LSPSpec::TextDocumentPositionParams>();
auto file_type = workspace.determine_filetype_from_uri(params.m_textDocument.m_uri);
if (file_type == Workspace::FileType::OpenGOALIR) {
auto tracked_file = workspace.get_tracked_ir_file(params.m_textDocument.m_uri);
if (!tracked_file) {
return {};
}
return hover_handler_ir(workspace, params, tracked_file.value());
} else if (file_type == Workspace::FileType::OpenGOAL) {
auto tracked_file = workspace.get_tracked_og_file(params.m_textDocument.m_uri);
if (!tracked_file) {
return {};
}
// TODO - replace with AST usage instead of figuring out the symbol ourselves
const auto symbol = tracked_file->get_symbol_at_position(params.m_position);
if (!symbol) {
lg::debug("hover - no symbol");
return {};
}
// TODO - there is an issue with docstrings and overridden methods
const auto& symbol_info =
workspace.get_global_symbol_info(tracked_file.value(), symbol.value());
if (!symbol_info) {
lg::debug("hover - no symbol info - {}", symbol.value());
return {};
}
LSPSpec::MarkupContent markup;
markup.m_kind = "markdown";
const auto args =
Docs::get_args_from_docstring(symbol_info->args(), symbol_info->meta().docstring);
std::string signature = "";
bool takes_args = true;
if (symbol_info->kind() == SymbolInfo::Kind::FUNCTION) {
signature += "function ";
} else if (symbol_info->kind() == SymbolInfo::Kind::METHOD) {
signature += "method ";
} else if (symbol_info->kind() == SymbolInfo::Kind::MACRO) {
signature += "macro ";
} else {
takes_args = false;
}
// TODO - others useful, probably states?
signature += symbol.value();
if (takes_args) {
signature += "(";
for (int i = 0; i < (int)args.size(); i++) {
const auto& arg = args.at(i);
if (i == (int)args.size() - 1) {
signature += fmt::format("{}: {}", arg.name, arg.type);
} else {
signature += fmt::format("{}: {}, ", arg.name, arg.type);
}
}
signature += ")";
if (symbol_info->kind() == SymbolInfo::Kind::FUNCTION &&
workspace.get_symbol_typespec(tracked_file.value(), symbol.value())) {
signature +=
fmt::format(": {}", workspace.get_symbol_typespec(tracked_file.value(), symbol.value())
->last_arg()
.base_type());
} else if (symbol_info->kind() == SymbolInfo::Kind::METHOD) {
signature += fmt::format(": {}", symbol_info->method_info().type.last_arg().base_type());
}
} else if (workspace.get_symbol_typespec(tracked_file.value(), symbol.value())) {
signature += fmt::format(
": {}", workspace.get_symbol_typespec(tracked_file.value(), symbol.value())->base_type());
}
std::string body = fmt::format("```opengoal\n{}\n```\n\n", signature);
body += "___\n\n";
if (!symbol_info->meta().docstring.empty()) {
body += truncate_docstring(symbol_info->meta().docstring) + "\n\n";
}
// TODO - support @see/@returns/[[reference]]
for (const auto& arg : args) {
std::string param_line = "";
if (arg.is_mutated) {
param_line += fmt::format("*@param!* `{}: {}`", arg.name, arg.type);
} else if (arg.is_optional) {
param_line += fmt::format("*@param?* `{}: {}`", arg.name, arg.type);
} else if (arg.is_unused) {
param_line += fmt::format("*@param_* `{}: {}`", arg.name, arg.type);
} else {
param_line += fmt::format("*@param* `{}: {}`", arg.name, arg.type);
}
if (!arg.description.empty()) {
param_line += fmt::format(" - {}\n\n", arg.description);
} else {
param_line += "\n\n";
}
body += param_line;
}
markup.m_value = body;
LSPSpec::Hover hover_resp;
hover_resp.m_contents = markup;
return hover_resp;
}
return {};
}
} // namespace lsp_handlers
@@ -0,0 +1,144 @@
#include "type_hierarchy.h"
#include "lsp/lsp_util.h"
namespace lsp_handlers {
std::optional<json> prepare_type_hierarchy(Workspace& workspace, int /*id*/, json raw_params) {
auto params = raw_params.get<LSPSpec::TypeHierarchyPrepareParams>();
const auto file_type = workspace.determine_filetype_from_uri(params.m_textDocument.m_uri);
if (file_type != Workspace::FileType::OpenGOAL) {
return nullptr;
}
auto maybe_tracked_file = workspace.get_tracked_og_file(params.m_textDocument.m_uri);
if (!maybe_tracked_file) {
return nullptr;
}
const auto& tracked_file = maybe_tracked_file.value().get();
const auto symbol = tracked_file.get_symbol_at_position(params.m_position);
if (!symbol) {
lg::debug("prepare_type_hierarchy - no symbol");
return nullptr;
}
const auto& symbol_info = workspace.get_global_symbol_info(tracked_file, symbol.value());
if (!symbol_info) {
lg::debug("prepare_type_hierarchy - no symbol info - {}", symbol.value());
return nullptr;
}
const auto& def_loc = workspace.get_symbol_def_location(tracked_file, symbol_info.value());
if (!def_loc) {
return nullptr;
}
auto type_item = LSPSpec::TypeHierarchyItem();
type_item.name = symbol.value();
// TODO - differentiate between struct and class perhaps
type_item.kind = LSPSpec::SymbolKind::Class;
if (symbol_info && !symbol_info.value()->m_docstring.empty()) {
type_item.detail = symbol_info.value()->m_docstring;
}
type_item.uri = lsp_util::uri_from_path(def_loc->file_path);
// TODO - this range is technically not entirely correct, we'd have to parse the defining file
// with an AST to get the true extent of the deftype. But for this purpose, its not really needed
//
// HACK - the definition that our compiler stores is the form itself, so we will add
// the width of the prefix `(deftype ` to the char_index
// TODO - A better way would be to use the AST
type_item.range.m_start = {(uint32_t)def_loc->line_idx, (uint32_t)(def_loc->char_idx + 9)};
type_item.range.m_end = {(uint32_t)def_loc->line_idx,
(uint32_t)(def_loc->char_idx + 9 + symbol.value().length())};
type_item.selectionRange.m_start = {(uint32_t)def_loc->line_idx,
(uint32_t)(def_loc->char_idx + 8)};
type_item.selectionRange.m_end = {(uint32_t)def_loc->line_idx,
(uint32_t)(def_loc->char_idx + 8 + symbol.value().length())};
json items = json::array();
items.push_back(type_item);
return items;
}
std::optional<json> supertypes_type_hierarchy(Workspace& workspace, int /*id*/, json raw_params) {
auto params = raw_params.get<LSPSpec::TypeHierarchySupertypesParams>();
const std::optional<GameVersion> game_version =
workspace.determine_game_version_from_uri(params.item.uri);
if (!game_version) {
return nullptr;
}
const auto& parent_type_path =
workspace.get_symbols_parent_type_path(params.item.name, game_version.value());
json items = json::array();
for (const auto& parent_type : parent_type_path) {
if (std::get<0>(parent_type) == params.item.name) {
continue; // skip the item itself
}
auto type_item = LSPSpec::TypeHierarchyItem();
type_item.name = std::get<0>(parent_type);
// TODO - differentiate between struct and class perhaps
type_item.kind = LSPSpec::SymbolKind::Class;
if (!std::get<1>(parent_type).empty()) {
type_item.detail = std::get<1>(parent_type);
}
const auto& def_loc = std::get<2>(parent_type);
type_item.uri = def_loc.filename;
// TODO - this range is technically not entirely correct, we'd have to parse the defining file
// with an AST to get the true entent of the deftype. But for this purpose, its not really
// needed
//
// HACK - the definition that our compiler stores is the form itself, so we will add
// the width of the prefix `(deftype ` to the char_index
// TODO - A better way would be to use the AST
type_item.range.m_start = {(uint32_t)def_loc.line_idx, (uint32_t)(def_loc.char_idx + 9)};
type_item.range.m_end = {(uint32_t)def_loc.line_idx,
(uint32_t)(def_loc.char_idx + 9 + std::get<0>(parent_type).length())};
type_item.selectionRange.m_start = {(uint32_t)def_loc.line_idx,
(uint32_t)(def_loc.char_idx + 8)};
type_item.selectionRange.m_end = {
(uint32_t)def_loc.line_idx,
(uint32_t)(def_loc.char_idx + 8 + std::get<0>(parent_type).length())};
items.push_back(type_item);
}
return items;
}
std::optional<json> subtypes_type_hierarchy(Workspace& workspace, int /*id*/, json raw_params) {
auto params = raw_params.get<LSPSpec::TypeHierarchySupertypesParams>();
const std::optional<GameVersion> game_version =
workspace.determine_game_version_from_uri(params.item.uri);
if (!game_version) {
return nullptr;
}
const auto& parent_type_path =
workspace.get_types_subtypes(params.item.name, game_version.value());
json items = json::array();
for (const auto& parent_type : parent_type_path) {
auto type_item = LSPSpec::TypeHierarchyItem();
type_item.name = std::get<0>(parent_type);
// TODO - differentiate between struct and class perhaps
type_item.kind = LSPSpec::SymbolKind::Class;
if (!std::get<1>(parent_type).empty()) {
type_item.detail = std::get<1>(parent_type);
}
const auto& def_loc = std::get<2>(parent_type);
type_item.uri = def_loc.filename;
// TODO - this range is technically not entirely correct, we'd have to parse the defining file
// with an AST to get the true entent of the deftype. But for this purpose, its not really
// needed
//
// HACK - the definition that our compiler stores is the form itself, so we will add
// the width of the prefix `(deftype ` to the char_index
// TODO - A better way would be to use the AST
type_item.range.m_start = {(uint32_t)def_loc.line_idx, (uint32_t)(def_loc.char_idx + 9)};
type_item.range.m_end = {(uint32_t)def_loc.line_idx,
(uint32_t)(def_loc.char_idx + 9 + std::get<0>(parent_type).length())};
type_item.selectionRange.m_start = {(uint32_t)def_loc.line_idx,
(uint32_t)(def_loc.char_idx + 8)};
type_item.selectionRange.m_end = {
(uint32_t)def_loc.line_idx,
(uint32_t)(def_loc.char_idx + 8 + std::get<0>(parent_type).length())};
items.push_back(type_item);
}
return items;
}
} // namespace lsp_handlers
@@ -0,0 +1,18 @@
#pragma once
#include <optional>
#include "common/util/json_util.h"
#include "lsp/protocol/common_types.h"
#include "lsp/protocol/type_hierarchy.h"
#include "lsp/state/workspace.h"
namespace lsp_handlers {
std::optional<json> prepare_type_hierarchy(Workspace& workspace, int id, json raw_params);
std::optional<json> supertypes_type_hierarchy(Workspace& workspace, int id, json raw_params);
std::optional<json> subtypes_type_hierarchy(Workspace& workspace, int id, json raw_params);
} // namespace lsp_handlers
+83
View File
@@ -0,0 +1,83 @@
#include "lsp_util.h"
#include <sstream>
#include "common/util/string_util.h"
#include "fmt/core.h"
namespace lsp_util {
std::string url_encode(const std::string& value) {
std::ostringstream escaped;
escaped.fill('0');
escaped << std::hex;
for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) {
std::string::value_type c = (*i);
// Keep alphanumeric and other accepted characters intact
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' || c == '/') {
escaped << c;
continue;
}
// Any other characters are percent-encoded
escaped << std::uppercase;
escaped << '%' << std::setw(2) << int((unsigned char)c);
escaped << std::nouppercase;
}
return escaped.str();
}
std::string url_decode(const std::string& input) {
std::ostringstream decoded;
for (std::size_t i = 0; i < input.length(); ++i) {
if (input[i] == '%') {
// Check if there are enough characters remaining
if (i + 2 < input.length()) {
// Convert the next two characters after '%' into an integer value
std::istringstream hexStream(input.substr(i + 1, 2));
int hexValue = 0;
hexStream >> std::hex >> hexValue;
// Append the decoded character to the result
decoded << static_cast<char>(hexValue);
// Skip the next two characters
i += 2;
}
} else if (input[i] == '+') {
// Replace '+' with space character ' '
decoded << ' ';
} else {
// Append the character as is
decoded << input[i];
}
}
return decoded.str();
}
LSPSpec::DocumentUri uri_from_path(fs::path path) {
auto path_str = file_util::convert_to_unix_path_separators(path.string());
// vscode works with proper URL encoded URIs for file paths
// which means we have to roll our own...
path_str = url_encode(path_str);
return fmt::format("file:///{}", path_str);
}
std::string uri_to_path(const LSPSpec::DocumentUri& uri) {
auto decoded_uri = url_decode(uri);
if (str_util::starts_with(decoded_uri, "file:///")) {
#ifdef _WIN32
decoded_uri = decoded_uri.substr(8);
#else
decoded_uri = decoded_uri.substr(7);
#endif
}
return decoded_uri;
}
} // namespace lsp_util
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common/util/FileUtil.h"
#include "protocol/common_types.h"
namespace lsp_util {
std::string url_encode(const std::string& value);
std::string url_decode(const std::string& input);
LSPSpec::DocumentUri uri_from_path(fs::path path);
std::string uri_to_path(const LSPSpec::DocumentUri& uri);
}; // namespace lsp_util
+29
View File
@@ -55,6 +55,29 @@ void setup_logging(bool verbose, std::string log_file, bool disable_ansi_colors)
lg::initialize();
}
std::string temp_url_encode(const std::string& value) {
std::ostringstream escaped;
escaped.fill('0');
escaped << std::hex;
for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) {
std::string::value_type c = (*i);
// Keep alphanumeric and other accepted characters intact
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' || c == '/') {
escaped << c;
continue;
}
// Any other characters are percent-encoded
escaped << std::uppercase;
escaped << '%' << std::setw(2) << int((unsigned char)c);
escaped << std::nouppercase;
}
return escaped.str();
}
int main(int argc, char** argv) {
ArgumentGuard u8_guard(argc, argv);
@@ -72,6 +95,7 @@ int main(int argc, char** argv) {
CLI11_PARSE(app, argc, argv);
AppState appstate;
LSPRouter lsp_router;
appstate.verbose = verbose;
try {
@@ -89,6 +113,11 @@ int main(int argc, char** argv) {
_setmode(_fileno(stdin), _O_BINARY);
#endif
// TODO - make the server check for the process id of the extension host and exit itself if that
// process goes away (the process id comes on the command line as an argument and in the
// initialize request). This is what we do in all our servers since the extension host could die
// unexpected as well.
try {
char c;
MessageBuffer message_buffer;
+5
View File
@@ -9,6 +9,11 @@ void LSPSpec::from_json(const json& j, Position& obj) {
j.at("character").get_to(obj.m_character);
}
LSPSpec::Range::Range(Position start, Position end) : m_start(start), m_end(end) {}
LSPSpec::Range::Range(uint32_t line, uint32_t character)
: m_start({line, character}), m_end({line, character}) {}
void LSPSpec::to_json(json& j, const Range& obj) {
// TODO - not sure if this works yet, but nice if it does!
j = json{{"start", obj.m_start}, {"end", obj.m_end}};
+5
View File
@@ -28,6 +28,11 @@ void from_json(const json& j, Position& obj);
struct Range {
Position m_start;
Position m_end;
Range(){};
Range(Position start, Position end);
// point constructor
Range(uint32_t line, uint32_t character);
};
void to_json(json& j, const Range& obj);
void from_json(const json& j, Range& obj);
+56 -5
View File
@@ -1,14 +1,65 @@
#include "completion.h"
void LSPSpec::to_json(json& j, const CompletionParams& obj) {
j = json{{"textDocument", obj.m_textDocument}, {"position", obj.m_position}};
json_serialize(textDocument);
json_serialize(position);
}
void LSPSpec::from_json(const json& j, CompletionParams& obj) {
j.at("textDocument").get_to(obj.m_textDocument);
j.at("position").get_to(obj.m_position);
json_deserialize_if_exists(textDocument);
json_deserialize_if_exists(position);
}
void LSPSpec::to_json(json& /*j*/, const CompletionList& /*obj*/) {}
void LSPSpec::to_json(json& j, const CompletionItemLabelDetails& obj) {
json_serialize_optional(detail);
json_serialize_optional(description);
}
void LSPSpec::from_json(const json& /*j*/, CompletionList& /*obj*/) {}
void LSPSpec::from_json(const json& j, CompletionItemLabelDetails& obj) {
json_deserialize_optional_if_exists(detail);
json_deserialize_optional_if_exists(description);
}
void LSPSpec::to_json(json& j, const CompletionItem& obj) {
json_serialize(label);
json_serialize_optional(labelDetails);
json_serialize_optional(kind);
json_serialize_optional(tags);
json_serialize_optional(detail);
json_serialize_optional(documentation);
json_serialize_optional(preselect);
json_serialize_optional(sortText);
json_serialize_optional(filterText);
json_serialize_optional(insertText);
json_serialize_optional(textEdit);
json_serialize_optional(textEditText);
json_serialize_optional(additionalTextEdits);
json_serialize_optional(commitCharacters);
}
void LSPSpec::from_json(const json& j, CompletionItem& obj) {
json_deserialize_if_exists(label);
json_deserialize_optional_if_exists(labelDetails);
json_deserialize_optional_if_exists(kind);
json_deserialize_optional_if_exists(tags);
json_deserialize_optional_if_exists(detail);
json_deserialize_optional_if_exists(documentation);
json_deserialize_optional_if_exists(preselect);
json_deserialize_optional_if_exists(sortText);
json_deserialize_optional_if_exists(filterText);
json_deserialize_optional_if_exists(insertText);
json_deserialize_optional_if_exists(textEdit);
json_deserialize_optional_if_exists(textEditText);
json_deserialize_optional_if_exists(additionalTextEdits);
json_deserialize_optional_if_exists(commitCharacters);
}
void LSPSpec::to_json(json& j, const CompletionList& obj) {
json_serialize(isIncomplete);
json_serialize(items);
}
void LSPSpec::from_json(const json& j, CompletionList& obj) {
json_deserialize_if_exists(isIncomplete);
json_deserialize_if_exists(items);
}
+102 -11
View File
@@ -20,10 +20,10 @@ enum class CompletionTriggerKind {
// TODO - look into inheriting structs?
struct CompletionParams {
/// @brief The text document.
TextDocumentIdentifier m_textDocument;
/// @brief The position inside the text document.
Position m_position;
/// The text document.
TextDocumentIdentifier textDocument;
/// The position inside the text document.
Position position;
};
void to_json(json& j, const CompletionParams& obj);
@@ -40,6 +40,9 @@ struct CompletionItemLabelDetails {
std::optional<std::string> description;
};
void to_json(json& j, const CompletionItemLabelDetails& obj);
void from_json(const json& j, CompletionItemLabelDetails& obj);
/// @brief The kind of a completion entry.
enum class CompletionItemKind {
Text = 1,
@@ -95,8 +98,9 @@ struct CompletionItem {
/// information.
std::optional<std::string> detail;
/// A human-readable string that represents a doc-comment.
/// TODO - can also be MarkupContent
std::optional<std::string> documentation;
// NOTE - skipped deprecated
// NOTE - skipped deprecated (because it's deprecated!)
/// Select this item when showing.
///
/// *Note* that only one completion item can be selected and that the tool / client decides which
@@ -108,17 +112,104 @@ struct CompletionItem {
/// A string that should be used when filtering a set of completion items. When omitted the label
/// is used as the filter text for this item.
std::optional<std::string> filterText;
// TODO - a lot of other fields...
/// A string that should be inserted into a document when selecting
/// this completion. When omitted the label is used as the insert text
/// for this item.
///
/// The `insertText` is subject to interpretation by the client side.
/// Some tools might not take the string literally. For example
/// VS Code when code complete is requested in this example
/// `con<cursor position>` and a completion item with an `insertText` of
/// `console` is provided it will only insert `sole`. Therefore it is
/// recommended to use `textEdit` instead since it avoids additional client
/// side interpretation.
std::optional<std::string> insertText;
/// The format of the insert text. The format applies to both the
/// `insertText` property and the `newText` property of a provided
/// `textEdit`. If omitted defaults to `InsertTextFormat.PlainText`.
///
/// Please note that the insertTextFormat doesn't apply to
/// `additionalTextEdits`.
// TODO - std::optional<InsertTextFormat> insertTextFormat;
/// How whitespace and indentation is handled during completion
/// item insertion. If not provided the client's default value depends on
/// the `textDocument.completion.insertTextMode` client capability.
///
/// @since 3.16.0
/// @since 3.17.0 - support for `textDocument.completion.insertTextMode`
// TODO - std::optional<InsertTextMode> insertTextMode;
/// An edit which is applied to a document when selecting this completion.
/// When an edit is provided the value of `insertText` is ignored.
///
/// *Note:* The range of the edit must be a single line range and it must
/// contain the position at which completion has been requested.
///
/// Most editors support two different operations when accepting a completion
/// item. One is to insert a completion text and the other is to replace an
/// existing text with a completion text. Since this can usually not be
/// predetermined by a server it can report both ranges. Clients need to
/// signal support for `InsertReplaceEdit`s via the
/// `textDocument.completion.completionItem.insertReplaceSupport` client
/// capability property.
///
/// *Note 1:* The text edit's range as well as both ranges from an insert
/// replace edit must be a [single line] and they must contain the position
/// at which completion has been requested.
/// *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range
/// must be a prefix of the edit's replace range, that means it must be
/// contained and starting at the same position.
///
/// @since 3.16.0 additional type `InsertReplaceEdit`
/// TODO - can also be InsertReplaceEdit
std::optional<TextEdit> textEdit;
/// The edit text used if the completion item is part of a CompletionList and
/// CompletionList defines an item default for the text edit range.
///
/// Clients will only honor this property if they opt into completion list
/// item defaults using the capability `completionList.itemDefaults`.
///
/// If not provided and a list's default range is provided the label
/// property is used as a text.
///
/// @since 3.17.0
std::optional<std::string> textEditText;
/// An optional array of additional text edits that are applied when
/// selecting this completion. Edits must not overlap (including the same
/// insert position) with the main edit nor with themselves.
///
/// Additional text edits should be used to change text unrelated to the
/// current cursor position (for example adding an import statement at the
/// top of the file if the completion item will insert an unqualified type).
std::optional<std::vector<TextEdit>> additionalTextEdits;
/// An optional set of characters that when pressed while this completion is
/// active will accept it first and then type that character. *Note* that all
/// commit characters should have `length=1` and that superfluous characters
/// will be ignored.
std::optional<std::vector<std::string>> commitCharacters;
/// An optional command that is executed *after* inserting this completion.
/// *Note* that additional modifications to the current document should be
/// described with the additionalTextEdits-property.
// TODO - std::optional<Command> command;
/// A data entry field that is preserved on a completion item between
/// a completion and a completion resolve request.
// TODO - LSPAny for data
};
void to_json(json& j, const CompletionItem& obj);
void from_json(const json& j, CompletionItem& obj);
// Represents a collection of [completion items](#CompletionItem) to be
// presented in the editor.
struct CompletionList {
/// This list is not complete. Further typing should result in recomputing this list.
/// This list is not complete. Further typing should result in recomputing
/// this list.
///
/// Recomputed lists have all their items replaced (not appended) in the incomplete completion
/// sessions.
bool m_isIncomplete;
/// Recomputed lists have all their items replaced (not appended) in the
/// incomplete completion sessions.
bool isIncomplete;
// TODO - do itemDefaults
/// The completion items.
std::vector<CompletionItem> m_items;
std::vector<CompletionItem> items;
};
void to_json(json& j, const CompletionList& obj);
+10
View File
@@ -32,3 +32,13 @@ void LSPSpec::to_json(json& j, const DidCloseTextDocumentParams& obj) {
void LSPSpec::from_json(const json& j, DidCloseTextDocumentParams& obj) {
j.at("textDocument").get_to(obj.m_textDocument);
}
void LSPSpec::to_json(json& j, const WillSaveTextDocumentParams& obj) {
json_serialize(textDocument);
json_serialize(reason);
}
void LSPSpec::from_json(const json& j, WillSaveTextDocumentParams& obj) {
json_deserialize_if_exists(textDocument);
json_deserialize_if_exists(reason);
}
+20
View File
@@ -32,4 +32,24 @@ struct DidCloseTextDocumentParams {
void to_json(json& j, const DidCloseTextDocumentParams& obj);
void from_json(const json& j, DidCloseTextDocumentParams& obj);
enum class TextDocumentSaveReason {
// Manually triggered, e.g. by the user pressing save, by starting debugging, or by an API call.
Manual = 1,
// Automatic after a delay.
AfterDelay = 2,
// When the editor lost focus.
FocusOut = 3,
};
// The parameters send in a will save text document notification.
struct WillSaveTextDocumentParams {
// The document that will be saved.
TextDocumentIdentifier textDocument;
// The 'TextDocumentSaveReason'.
TextDocumentSaveReason reason;
};
void to_json(json& j, const WillSaveTextDocumentParams& obj);
void from_json(const json& j, WillSaveTextDocumentParams& obj);
} // namespace LSPSpec
+17 -30
View File
@@ -8,7 +8,7 @@ void LSPSpec::from_json(const json& j, WorkDoneProgressCreateParams& obj) {
json_deserialize_if_exists(token);
}
void LSPSpec::to_json(json& j, const ProgressPayloadBegin& obj) {
void LSPSpec::to_json(json& j, const WorkDoneProgressBegin& obj) {
json_serialize(kind);
json_serialize(title);
json_serialize(cancellable);
@@ -16,7 +16,7 @@ void LSPSpec::to_json(json& j, const ProgressPayloadBegin& obj) {
json_serialize_optional(percentage);
}
void LSPSpec::from_json(const json& j, ProgressPayloadBegin& obj) {
void LSPSpec::from_json(const json& j, WorkDoneProgressBegin& obj) {
json_deserialize_if_exists(kind);
json_deserialize_if_exists(title);
json_deserialize_if_exists(cancellable);
@@ -24,56 +24,43 @@ void LSPSpec::from_json(const json& j, ProgressPayloadBegin& obj) {
json_deserialize_optional_if_exists(percentage);
}
void LSPSpec::to_json(json& j, const ProgressParamsBegin& obj) {
json_serialize(token);
json_serialize(value);
}
void LSPSpec::from_json(const json& j, ProgressParamsBegin& obj) {
json_deserialize_if_exists(token);
json_deserialize_if_exists(value);
}
void LSPSpec::to_json(json& j, const ProgressPayloadReport& obj) {
void LSPSpec::to_json(json& j, const WorkDoneProgressReport& obj) {
json_serialize(kind);
json_serialize(cancellable);
json_serialize_optional(message);
json_serialize_optional(percentage);
}
void LSPSpec::from_json(const json& j, ProgressPayloadReport& obj) {
void LSPSpec::from_json(const json& j, WorkDoneProgressReport& obj) {
json_deserialize_if_exists(kind);
json_deserialize_if_exists(cancellable);
json_deserialize_optional_if_exists(message);
json_deserialize_optional_if_exists(percentage);
}
void LSPSpec::to_json(json& j, const ProgressParamsReport& obj) {
json_serialize(token);
json_serialize(value);
}
void LSPSpec::from_json(const json& j, ProgressParamsReport& obj) {
json_deserialize_if_exists(token);
json_deserialize_if_exists(value);
}
void LSPSpec::to_json(json& j, const ProgressPayloadEnd& obj) {
void LSPSpec::to_json(json& j, const WorkDoneProgressEnd& obj) {
json_serialize(kind);
json_serialize_optional(message);
}
void LSPSpec::from_json(const json& j, ProgressPayloadEnd& obj) {
void LSPSpec::from_json(const json& j, WorkDoneProgressEnd& obj) {
json_deserialize_if_exists(kind);
json_deserialize_optional_if_exists(message);
}
void LSPSpec::to_json(json& j, const ProgressParamsEnd& obj) {
void LSPSpec::to_json(json& j, const ProgressNotificationPayload& obj) {
json_serialize(token);
json_serialize(value);
if (obj.beginValue) {
j["value"] = obj.beginValue.value();
} else if (obj.reportValue) {
j["value"] = obj.reportValue.value();
} else {
j["value"] = obj.endValue.value();
}
}
void LSPSpec::from_json(const json& j, ProgressParamsEnd& obj) {
void LSPSpec::from_json(const json& j, ProgressNotificationPayload& obj) {
json_deserialize_if_exists(token);
json_deserialize_if_exists(value);
// TODO - not needed, but if so -- deserialize 'value', it's possible to figure out which is the
// right one
}
+15 -35
View File
@@ -11,7 +11,7 @@ struct WorkDoneProgressCreateParams {
void to_json(json& j, const WorkDoneProgressCreateParams& obj);
void from_json(const json& j, WorkDoneProgressCreateParams& obj);
struct ProgressPayloadBegin {
struct WorkDoneProgressBegin {
std::string kind = "begin";
// Mandatory title of the progress operation. Used to briefly inform about
// the kind of operation being performed.
@@ -36,20 +36,10 @@ struct ProgressPayloadBegin {
// that are not following this rule. The value range is [0, 100]
std::optional<uint32_t> percentage;
};
void to_json(json& j, const ProgressPayloadBegin& obj);
void from_json(const json& j, ProgressPayloadBegin& obj);
void to_json(json& j, const WorkDoneProgressBegin& obj);
void from_json(const json& j, WorkDoneProgressBegin& obj);
struct ProgressParamsBegin {
// The progress token provided by the client or server.
std::string token;
// Payload
ProgressPayloadBegin value;
};
void to_json(json& j, const ProgressParamsBegin& obj);
void from_json(const json& j, ProgressParamsBegin& obj);
struct ProgressPayloadReport {
struct WorkDoneProgressReport {
std::string kind = "report";
// Controls enablement state of a cancel button. This property is only valid
// if a cancel button got requested in the `WorkDoneProgressBegin` payload.
@@ -71,35 +61,25 @@ struct ProgressPayloadReport {
// that are not following this rule. The value range is [0, 100]
std::optional<uint32_t> percentage;
};
void to_json(json& j, const ProgressPayloadReport& obj);
void from_json(const json& j, ProgressPayloadReport& obj);
void to_json(json& j, const WorkDoneProgressReport& obj);
void from_json(const json& j, WorkDoneProgressReport& obj);
struct ProgressParamsReport {
// The progress token provided by the client or server.
std::string token;
// Payload
ProgressPayloadReport value;
};
void to_json(json& j, const ProgressParamsReport& obj);
void from_json(const json& j, ProgressParamsReport& obj);
struct ProgressPayloadEnd {
struct WorkDoneProgressEnd {
std::string kind = "end";
// Optional, a final message indicating to for example indicate the outcome
// of the operation.
std::optional<std::string> message;
};
void to_json(json& j, const ProgressPayloadEnd& obj);
void from_json(const json& j, ProgressPayloadEnd& obj);
void to_json(json& j, const WorkDoneProgressEnd& obj);
void from_json(const json& j, WorkDoneProgressEnd& obj);
struct ProgressParamsEnd {
// The progress token provided by the client or server.
struct ProgressNotificationPayload {
std::string token;
// Payload
ProgressPayloadEnd value;
std::optional<WorkDoneProgressBegin> beginValue;
std::optional<WorkDoneProgressReport> reportValue;
std::optional<WorkDoneProgressEnd> endValue;
};
void to_json(json& j, const ProgressNotificationPayload& obj);
void from_json(const json& j, ProgressNotificationPayload& obj);
void to_json(json& j, const ProgressParamsEnd& obj);
void from_json(const json& j, ProgressParamsEnd& obj);
} // namespace LSPSpec
+50
View File
@@ -0,0 +1,50 @@
#include "type_hierarchy.h"
#include "common/util/json_util.h"
// TODO - there's gotta be a way to share json serialization/deserialization
// figure it out _soon_
void LSPSpec::to_json(json& j, const TypeHierarchyPrepareParams& obj) {
j = json{{"textDocument", obj.m_textDocument}, {"position", obj.m_position}};
}
void LSPSpec::from_json(const json& j, TypeHierarchyPrepareParams& obj) {
j.at("textDocument").get_to(obj.m_textDocument);
j.at("position").get_to(obj.m_position);
}
void LSPSpec::to_json(json& j, const TypeHierarchyItem& obj) {
json_serialize(name);
json_serialize(kind);
json_serialize_optional(tags);
json_serialize_optional(detail);
json_serialize(uri);
json_serialize(range);
json_serialize(selectionRange);
}
void LSPSpec::from_json(const json& j, TypeHierarchyItem& obj) {
json_deserialize_if_exists(name);
json_deserialize_if_exists(kind);
json_deserialize_optional_if_exists(tags);
json_deserialize_optional_if_exists(detail);
json_deserialize_if_exists(uri);
json_deserialize_if_exists(range);
json_deserialize_if_exists(selectionRange);
}
void LSPSpec::to_json(json& j, const TypeHierarchySupertypesParams& obj) {
json_serialize(item);
}
void LSPSpec::from_json(const json& j, TypeHierarchySupertypesParams& obj) {
json_deserialize_if_exists(item);
}
void LSPSpec::to_json(json& j, const TypeHierarchySubtypesParams& obj) {
json_serialize(item);
}
void LSPSpec::from_json(const json& j, TypeHierarchySubtypesParams& obj) {
json_deserialize_if_exists(item);
}
+56
View File
@@ -0,0 +1,56 @@
#pragma once
#include "common_types.h"
#include "lsp/protocol/document_symbols.h"
namespace LSPSpec {
struct TypeHierarchyPrepareParams : TextDocumentPositionParams {};
void to_json(json& j, const TypeHierarchyPrepareParams& obj);
void from_json(const json& j, TypeHierarchyPrepareParams& obj);
struct TypeHierarchyItem {
/// The name of this item.
std::string name;
/// The kind of this item.
SymbolKind kind;
/// Tags for this item.
std::optional<std::vector<SymbolTag>> tags;
/// More detail for this item, e.g. the signature of a function.
std::optional<std::string> detail;
/// The resource identifier of this item.
DocumentUri uri;
/// The range enclosing this symbol not including leading/trailing whitespace
/// but everything else, e.g. comments and code.
Range range;
/// The range that should be selected and revealed when this symbol is being
/// picked, e.g. the name of a function. Must be contained by the
/// `range` of this
Range selectionRange;
/// A data entry field that is preserved between a type hierarchy prepare and
/// supertypes or subtypes requests. It could also be used to identify the
/// type hierarchy in the server, helping improve the performance on
/// resolving supertypes and subtypes.
// ANY data;
};
void to_json(json& j, const TypeHierarchyItem& obj);
void from_json(const json& j, TypeHierarchyItem& obj);
struct TypeHierarchySupertypesParams {
TypeHierarchyItem item;
};
void to_json(json& j, const TypeHierarchySupertypesParams& obj);
void from_json(const json& j, TypeHierarchySupertypesParams& obj);
struct TypeHierarchySubtypesParams {
TypeHierarchyItem item;
};
void to_json(json& j, const TypeHierarchySubtypesParams& obj);
void from_json(const json& j, TypeHierarchySubtypesParams& obj);
} // namespace LSPSpec
+1
View File
@@ -2,6 +2,7 @@
#include "lsp/state/workspace.h"
// TODO - remove this, not really benefiting (never going to have multiple appstates)
struct AppState {
Workspace workspace;
bool verbose;
+37 -23
View File
@@ -42,35 +42,49 @@ void LSPRequester::send_notification(const json& params, const std::string& meth
std::cout << request.c_str() << std::flush;
}
void LSPRequester::send_progress_create_request(const std::string& token,
const std::string& title) {
LSPSpec::WorkDoneProgressCreateParams params;
params.token = token;
send_request(params, "window/workDoneProgress/create");
LSPSpec::ProgressPayloadBegin beginPayload;
void LSPRequester::send_progress_create_request(const std::string& title,
const std::string& message,
const int percentage) {
const std::string token = fmt::format("opengoal/{}", title);
LSPSpec::WorkDoneProgressCreateParams createRequest;
createRequest.token = token;
send_request(createRequest, "window/workDoneProgress/create");
LSPSpec::WorkDoneProgressBegin beginPayload;
beginPayload.title = title;
LSPSpec::ProgressParamsBegin beginParams;
beginParams.token = token;
beginParams.value = beginPayload;
send_notification(beginParams, "$/progress");
beginPayload.cancellable = false; // TODO - maybe one day
beginPayload.message = message;
if (percentage > 0) {
beginPayload.percentage = percentage;
}
LSPSpec::ProgressNotificationPayload notification;
notification.token = token;
notification.beginValue = beginPayload;
send_notification(notification, "$/progress");
}
void LSPRequester::send_progress_update_request(const std::string& token,
const std::string& message) {
LSPSpec::ProgressPayloadReport reportPayload;
void LSPRequester::send_progress_update_request(const std::string& title,
const std::string& message,
const int percentage) {
const std::string token = fmt::format("opengoal/{}", title);
LSPSpec::WorkDoneProgressReport reportPayload;
reportPayload.cancellable = false; // TODO - maybe one day
reportPayload.message = message;
LSPSpec::ProgressParamsReport reportParams;
reportParams.token = token;
reportParams.value = reportPayload;
send_notification(reportParams, "$/progress");
if (percentage > 0) {
reportPayload.percentage = percentage;
}
LSPSpec::ProgressNotificationPayload notification;
notification.token = token;
notification.reportValue = reportPayload;
send_notification(notification, "$/progress");
}
void LSPRequester::send_progress_finish_request(const std::string& token,
void LSPRequester::send_progress_finish_request(const std::string& title,
const std::string& message) {
LSPSpec::ProgressPayloadEnd endPayload;
const std::string token = fmt::format("opengoal/{}", title);
LSPSpec::WorkDoneProgressEnd endPayload;
endPayload.message = message;
LSPSpec::ProgressParamsEnd endParams;
endParams.token = token;
endParams.value = endPayload;
send_notification(endParams, "$/progress");
LSPSpec::ProgressNotificationPayload notification;
notification.token = token;
notification.endValue = endPayload;
send_notification(notification, "$/progress");
}
+7 -3
View File
@@ -9,9 +9,13 @@
class LSPRequester {
public:
void send_progress_create_request(const std::string& token, const std::string& title);
void send_progress_update_request(const std::string& token, const std::string& message);
void send_progress_finish_request(const std::string& token, const std::string& message);
void send_progress_create_request(const std::string& title,
const std::string& message,
const int percentage);
void send_progress_update_request(const std::string& title,
const std::string& message,
const int percentage);
void send_progress_finish_request(const std::string& title, const std::string& message);
private:
void send_request(const json& payload, const std::string& method);
+375 -152
View File
@@ -1,86 +1,23 @@
#include "workspace.h"
#include <iomanip>
#include <regex>
#include <sstream>
#include "common/log/log.h"
#include "common/util/FileUtil.h"
#include "common/util/ast_util.h"
#include "common/util/string_util.h"
#include "lsp/lsp_util.h"
#include "lsp/protocol/common_types.h"
#include "tree_sitter/api.h"
std::string url_encode(const std::string& value) {
std::ostringstream escaped;
escaped.fill('0');
escaped << std::hex;
for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) {
std::string::value_type c = (*i);
// Keep alphanumeric and other accepted characters intact
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' || c == '/') {
escaped << c;
continue;
}
// Any other characters are percent-encoded
escaped << std::uppercase;
escaped << '%' << std::setw(2) << int((unsigned char)c);
escaped << std::nouppercase;
}
return escaped.str();
// Declare the `tree_sitter_opengoal` function, which is
// implemented by the `tree-sitter-opengoal` library.
extern "C" {
extern const TSLanguage* tree_sitter_opengoal();
}
std::string url_decode(const std::string& input) {
std::ostringstream decoded;
for (std::size_t i = 0; i < input.length(); ++i) {
if (input[i] == '%') {
// Check if there are enough characters remaining
if (i + 2 < input.length()) {
// Convert the next two characters after '%' into an integer value
std::istringstream hexStream(input.substr(i + 1, 2));
int hexValue = 0;
hexStream >> std::hex >> hexValue;
// Append the decoded character to the result
decoded << static_cast<char>(hexValue);
// Skip the next two characters
i += 2;
}
} else if (input[i] == '+') {
// Replace '+' with space character ' '
decoded << ' ';
} else {
// Append the character as is
decoded << input[i];
}
}
return decoded.str();
}
LSPSpec::DocumentUri uri_from_path(fs::path path) {
auto path_str = file_util::convert_to_unix_path_separators(path.string());
// vscode works with proper URL encoded URIs for file paths
// which means we have to roll our own...
path_str = url_encode(path_str);
return fmt::format("file:///{}", path_str);
}
std::string uri_to_path(LSPSpec::DocumentUri uri) {
auto decoded_uri = url_decode(uri);
if (str_util::starts_with(decoded_uri, "file:///")) {
#ifdef _WIN32
decoded_uri = decoded_uri.substr(8);
#else
decoded_uri = decoded_uri.substr(7);
#endif
}
return decoded_uri;
}
const TSLanguage* g_opengoalLang = tree_sitter_opengoal();
Workspace::Workspace(){};
Workspace::~Workspace(){};
@@ -111,18 +48,22 @@ Workspace::FileType Workspace::determine_filetype_from_uri(const LSPSpec::Docume
return FileType::Unsupported;
}
std::optional<WorkspaceOGFile> Workspace::get_tracked_og_file(const LSPSpec::URI& file_uri) {
if (m_tracked_og_files.find(file_uri) == m_tracked_og_files.end()) {
return {};
std::optional<std::reference_wrapper<WorkspaceOGFile>> Workspace::get_tracked_og_file(
const LSPSpec::URI& file_uri) {
auto it = m_tracked_og_files.find(file_uri);
if (it == m_tracked_og_files.end()) {
return std::nullopt;
}
return m_tracked_og_files[file_uri];
return std::ref(it->second);
}
std::optional<WorkspaceIRFile> Workspace::get_tracked_ir_file(const LSPSpec::URI& file_uri) {
if (m_tracked_ir_files.count(file_uri) == 0) {
return {};
std::optional<std::reference_wrapper<WorkspaceIRFile>> Workspace::get_tracked_ir_file(
const LSPSpec::URI& file_uri) {
auto it = m_tracked_ir_files.find(file_uri);
if (it == m_tracked_ir_files.end()) {
return std::nullopt;
}
return m_tracked_ir_files[file_uri];
return std::ref(it->second);
}
std::optional<DefinitionMetadata> Workspace::get_definition_info_from_all_types(
@@ -143,18 +84,34 @@ std::optional<DefinitionMetadata> Workspace::get_definition_info_from_all_types(
//
// This is bad because jak 2 now uses some code from the jak1 folder, and also wouldn't be able to
// be determined (jak1 or jak2?) if we had a proper 'common' folder(s).
std::optional<GameVersion> determine_game_version_from_uri(const LSPSpec::DocumentUri& uri) {
const auto path = uri_to_path(uri);
std::optional<GameVersion> Workspace::determine_game_version_from_uri(
const LSPSpec::DocumentUri& uri) {
const auto path = lsp_util::uri_to_path(uri);
if (str_util::contains(path, "goal_src/jak1")) {
return GameVersion::Jak1;
} else if (str_util::contains(path, "goal_src/jak2")) {
return GameVersion::Jak2;
} else if (str_util::contains(path, "goal_src/jak3")) {
return GameVersion::Jak3;
}
return {};
}
std::optional<SymbolInfo> Workspace::get_global_symbol_info(const WorkspaceOGFile& file,
const std::string& symbol_name) {
std::vector<std::shared_ptr<symbol_info::SymbolInfo>> Workspace::get_symbols_starting_with(
const GameVersion game_version,
const std::string& symbol_prefix) {
if (m_compiler_instances.find(game_version) == m_compiler_instances.end()) {
lg::debug("Compiler not instantiated for game version - {}",
version_to_game_name(game_version));
return {};
}
const auto& compiler = m_compiler_instances[game_version].get();
return compiler->lookup_symbol_info_by_prefix(symbol_prefix);
}
std::optional<std::shared_ptr<symbol_info::SymbolInfo>> Workspace::get_global_symbol_info(
const WorkspaceOGFile& file,
const std::string& symbol_name) {
if (m_compiler_instances.find(file.m_game_version) == m_compiler_instances.end()) {
lg::debug("Compiler not instantiated for game version - {}",
version_to_game_name(file.m_game_version));
@@ -162,19 +119,21 @@ std::optional<SymbolInfo> Workspace::get_global_symbol_info(const WorkspaceOGFil
}
const auto& compiler = m_compiler_instances[file.m_game_version].get();
const auto symbol_infos = compiler->lookup_exact_name_info(symbol_name);
if (!symbol_infos || symbol_infos->empty()) {
if (symbol_infos.empty()) {
return {};
} else if (symbol_infos->size() > 1) {
} else if (symbol_infos.size() > 1) {
// TODO - handle this (overriden methods is the main issue here)
lg::debug("Found symbol info, but found multiple infos - {}", symbol_infos->size());
lg::debug("Found symbol info, but found multiple infos - {}", symbol_infos.size());
return {};
}
const auto& symbol = symbol_infos->at(0);
const auto& symbol = symbol_infos.at(0);
return symbol;
}
std::optional<TypeSpec> Workspace::get_symbol_typespec(const WorkspaceOGFile& file,
const std::string& symbol_name) {
// TODO - consolidate what is needed into `SymbolInfo`
std::optional<std::pair<TypeSpec, Type*>> Workspace::get_symbol_typeinfo(
const WorkspaceOGFile& file,
const std::string& symbol_name) {
if (m_compiler_instances.find(file.m_game_version) == m_compiler_instances.end()) {
lg::debug("Compiler not instantiated for game version - {}",
version_to_game_name(file.m_game_version));
@@ -183,32 +142,122 @@ std::optional<TypeSpec> Workspace::get_symbol_typespec(const WorkspaceOGFile& fi
const auto& compiler = m_compiler_instances[file.m_game_version].get();
const auto typespec = compiler->lookup_typespec(symbol_name);
if (typespec) {
return typespec;
// NOTE - for some reason calling with the symbol's typespec and the symbol itself produces
// different results!
const auto full_type_info = compiler->type_system().lookup_type_no_throw(symbol_name);
if (full_type_info != nullptr) {
return std::make_pair(typespec.value(), full_type_info);
}
}
return {};
}
std::optional<Docs::DefinitionLocation> Workspace::get_symbol_def_location(
std::optional<symbol_info::DefinitionLocation> Workspace::get_symbol_def_location(
const WorkspaceOGFile& file,
const SymbolInfo& symbol_info) {
if (m_compiler_instances.find(file.m_game_version) == m_compiler_instances.end()) {
lg::debug("Compiler not instantiated for game version - {}",
version_to_game_name(file.m_game_version));
const std::shared_ptr<symbol_info::SymbolInfo> symbol_info) {
const auto& def_loc = symbol_info->m_def_location;
if (!def_loc) {
return {};
}
const auto& compiler = m_compiler_instances[file.m_game_version].get();
std::optional<Docs::DefinitionLocation> def_loc;
const auto& goos_info = compiler->get_goos().reader.db.get_short_info_for(symbol_info.src_form());
if (goos_info) {
Docs::DefinitionLocation new_def_loc;
new_def_loc.filename = uri_from_path(goos_info->filename);
new_def_loc.line_idx = goos_info->line_idx_to_display;
new_def_loc.char_idx = goos_info->pos_in_line;
def_loc = new_def_loc;
}
return def_loc;
}
std::vector<std::tuple<std::string, std::string, Docs::DefinitionLocation>>
Workspace::get_symbols_parent_type_path(const std::string& symbol_name,
const GameVersion game_version) {
if (m_compiler_instances.find(game_version) == m_compiler_instances.end()) {
lg::debug("Compiler not instantiated for game version - {}",
version_to_game_name(game_version));
return {};
}
// name, docstring, def_loc
std::vector<std::tuple<std::string, std::string, Docs::DefinitionLocation>> parents = {};
const auto& compiler = m_compiler_instances[game_version].get();
const auto parent_path = compiler->type_system().get_path_up_tree(symbol_name);
for (const auto& parent : parent_path) {
const auto symbol_infos = compiler->lookup_exact_name_info(parent);
if (symbol_infos.empty()) {
continue;
}
std::shared_ptr<symbol_info::SymbolInfo> symbol_info;
if (symbol_infos.size() > 1) {
for (const auto& info : symbol_infos) {
if (info->m_kind == symbol_info::Kind::TYPE) {
symbol_info = info;
}
}
} else {
symbol_info = symbol_infos.at(0);
}
if (!symbol_info) {
continue;
}
const auto& def_loc = symbol_info->m_def_location;
if (!def_loc) {
continue;
}
Docs::DefinitionLocation new_def_loc;
new_def_loc.filename = lsp_util::uri_from_path(def_loc->file_path);
new_def_loc.line_idx = def_loc->line_idx;
new_def_loc.char_idx = def_loc->char_idx;
parents.push_back({parent, symbol_info->m_docstring, new_def_loc});
}
return parents;
}
std::vector<std::tuple<std::string, std::string, Docs::DefinitionLocation>>
Workspace::get_types_subtypes(const std::string& symbol_name, const GameVersion game_version) {
if (m_compiler_instances.find(game_version) == m_compiler_instances.end()) {
lg::debug("Compiler not instantiated for game version - {}",
version_to_game_name(game_version));
return {};
}
// name, docstring, def_loc
std::vector<std::tuple<std::string, std::string, Docs::DefinitionLocation>> subtypes = {};
const auto& compiler = m_compiler_instances[game_version].get();
const auto subtype_names =
compiler->type_system().search_types_by_parent_type_strict(symbol_name);
for (const auto& subtype_name : subtype_names) {
const auto symbol_infos = compiler->lookup_exact_name_info(subtype_name);
if (symbol_infos.empty()) {
continue;
} else if (symbol_infos.size() > 1) {
continue;
}
const auto& symbol_info = symbol_infos.at(0);
const auto& def_loc = symbol_info->m_def_location;
if (!def_loc) {
continue;
}
Docs::DefinitionLocation new_def_loc;
new_def_loc.filename = lsp_util::uri_from_path(def_loc->file_path);
new_def_loc.line_idx = def_loc->line_idx;
new_def_loc.char_idx = def_loc->char_idx;
subtypes.push_back({subtype_name, symbol_info->m_docstring, new_def_loc});
}
return subtypes;
}
std::unordered_map<std::string, s64> Workspace::get_enum_entries(const std::string& enum_name,
const GameVersion game_version) {
if (m_compiler_instances.find(game_version) == m_compiler_instances.end()) {
lg::debug("Compiler not instantiated for game version - {}",
version_to_game_name(game_version));
return {};
}
const auto& compiler = m_compiler_instances[game_version].get();
const auto enum_info = compiler->type_system().try_enum_lookup(enum_name);
if (!enum_info) {
return {};
}
return enum_info->entries();
}
void Workspace::start_tracking_file(const LSPSpec::DocumentUri& file_uri,
const std::string& language_id,
const std::string& content) {
@@ -225,33 +274,51 @@ void Workspace::start_tracking_file(const LSPSpec::DocumentUri& file_uri,
}
}
} else if (language_id == "opengoal") {
if (m_tracked_og_files.find(file_uri) != m_tracked_og_files.end()) {
lg::debug("Already tracking - {}", file_uri);
return;
}
auto game_version = determine_game_version_from_uri(file_uri);
if (!game_version) {
lg::debug("Could not determine game version from path - {}", file_uri);
return;
}
// TODO - this should happen on a separate thread so the LSP is not blocking during this lengthy
// step
if (m_compiler_instances.find(*game_version) == m_compiler_instances.end()) {
lg::debug(
"first time encountering a OpenGOAL file for game version - {}, initializing a compiler",
version_to_game_name(*game_version));
const auto project_path = file_util::try_get_project_path_from_path(uri_to_path(file_uri));
const auto project_path =
file_util::try_get_project_path_from_path(lsp_util::uri_to_path(file_uri));
lg::debug("Detected project path - {}", project_path.value());
if (!file_util::setup_project_path(project_path)) {
lg::debug("unable to setup project path, not initializing a compiler");
return;
}
m_requester.send_progress_create_request("indexing-jak2", "Indexing - Jak 2");
const std::string progress_title =
fmt::format("Compiling {}", version_to_game_name_external(game_version.value()));
m_requester.send_progress_create_request(progress_title, "compiling project", -1);
m_compiler_instances.emplace(game_version.value(),
std::make_unique<Compiler>(game_version.value()));
// TODO - if this fails, annotate some errors, adjust progress
m_compiler_instances.at(*game_version)->run_front_end_on_string("(make-group \"all-code\")");
m_requester.send_progress_finish_request("indexing-jak2", "Indexed - Jak 2");
try {
// TODO - this should happen on a separate thread so the LSP is not blocking during this
// lengthy step
// TODO - make this a setting (disable indexing)
// TODO - ask water if there is a fancy way to reduce memory usage (disabling coloring,
// etc?)
m_compiler_instances.at(*game_version)
->run_front_end_on_string("(make-group \"all-code\")");
m_requester.send_progress_finish_request(progress_title, "indexed");
} catch (std::exception& e) {
// TODO - If it fails, annotate errors (DIAGNOSTIC TODO)
m_requester.send_progress_finish_request(progress_title, "failed");
lg::debug("error when {}", progress_title);
}
}
// TODO - otherwise, just `ml` the file instead of rebuilding the entire thing
// TODO - if the file fails to `ml`, annotate some errors
m_tracked_og_files[file_uri] = WorkspaceOGFile(content, *game_version);
m_tracked_og_files.emplace(file_uri, WorkspaceOGFile(file_uri, content, *game_version));
m_tracked_og_files[file_uri].update_symbols(
m_compiler_instances.at(*game_version)
->lookup_symbol_info_by_file(lsp_util::uri_to_path(file_uri)));
}
}
@@ -260,7 +327,7 @@ void Workspace::update_tracked_file(const LSPSpec::DocumentUri& file_uri,
lg::debug("potentially updating - {}", file_uri);
// Check if the file is already tracked or not, this is done because change events don't give
// language details it's assumed you are keeping track of that!
if (m_tracked_ir_files.count(file_uri) != 0) {
if (m_tracked_ir_files.find(file_uri) != m_tracked_ir_files.end()) {
lg::debug("updating tracked IR file - {}", file_uri);
WorkspaceIRFile file(content);
m_tracked_ir_files[file_uri] = file;
@@ -274,52 +341,210 @@ void Workspace::update_tracked_file(const LSPSpec::DocumentUri& file_uri,
all_types_file->m_game_version = file.m_game_version;
all_types_file->update_type_system();
}
}
if (m_tracked_all_types_files.count(file_uri) != 0) {
} else if (m_tracked_all_types_files.find(file_uri) != m_tracked_all_types_files.end()) {
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();
}
};
void Workspace::stop_tracking_file(const LSPSpec::DocumentUri& file_uri) {
if (m_tracked_ir_files.count(file_uri) != 0) {
m_tracked_ir_files.erase(file_uri);
}
if (m_tracked_all_types_files.count(file_uri) != 0) {
m_tracked_all_types_files.erase(file_uri);
} else if (m_tracked_og_files.find(file_uri) != m_tracked_og_files.end()) {
lg::debug("updating tracked OG file - {}", file_uri);
m_tracked_og_files[file_uri].parse_content(content);
// re-`ml` the file
const auto game_version = m_tracked_og_files[file_uri].m_game_version;
if (m_compiler_instances.find(game_version) == m_compiler_instances.end()) {
lg::debug("No compiler initialized for - {}", version_to_game_name(game_version));
return;
}
}
}
WorkspaceOGFile::WorkspaceOGFile(const std::string& content, const GameVersion& game_version)
: m_content(content), m_game_version(game_version) {
const auto line_ending = file_util::get_majority_file_line_endings(content);
m_lines = str_util::split_string(content, line_ending);
lg::info("Added new OG file. {} lines with {} symbols and {} diagnostics", m_lines.size(),
m_symbols.size(), m_diagnostics.size());
void Workspace::tracked_file_will_save(const LSPSpec::DocumentUri& file_uri) {
lg::debug("file will be saved - {}", file_uri);
if (m_tracked_og_files.find(file_uri) != m_tracked_og_files.end()) {
// goalc is not an incremental compiler (yet) so I believe it will be a better UX
// to re-compile on the file save, rather than as the user is typing
const auto game_version = m_tracked_og_files[file_uri].m_game_version;
if (m_compiler_instances.find(game_version) == m_compiler_instances.end()) {
lg::debug("No compiler initialized for - {}", version_to_game_name(game_version));
return;
}
CompilationOptions options;
options.filename = lsp_util::uri_to_path(file_uri);
// re-compile the file
m_compiler_instances.at(game_version)->asm_file(options);
// Update symbols for this specific file
const auto symbol_infos =
m_compiler_instances.at(game_version)->lookup_symbol_info_by_file(options.filename);
m_tracked_og_files[file_uri].update_symbols(symbol_infos);
}
}
void Workspace::update_global_index(const GameVersion game_version){
// TODO - project wide indexing potentially (ie. finding references)
};
void Workspace::stop_tracking_file(const LSPSpec::DocumentUri& file_uri) {
m_tracked_ir_files.erase(file_uri);
m_tracked_all_types_files.erase(file_uri);
m_tracked_og_files.erase(file_uri);
}
WorkspaceOGFile::WorkspaceOGFile(const LSPSpec::DocumentUri& uri,
const std::string& content,
const GameVersion& game_version)
: m_uri(uri), m_game_version(game_version), version(0) {
const auto [line_count, line_ending] =
file_util::get_majority_file_line_endings_and_count(content);
m_line_count = line_count;
m_line_ending = line_ending;
lg::info("Added new OG file. {} symbols and {} diagnostics", m_symbols.size(),
m_diagnostics.size());
parse_content(content);
}
void WorkspaceOGFile::parse_content(const std::string& content) {
m_content = content;
auto parser = ts_parser_new();
if (ts_parser_set_language(parser, g_opengoalLang)) {
// Get the AST for the current state of the file
// TODO - eventually, we should consider doing partial updates of the AST
// but right now the LSP just receives the entire document so that's a larger change.
m_ast.reset(ts_parser_parse_string(parser, NULL, m_content.c_str(), m_content.length()),
TreeSitterTreeDeleter());
}
ts_parser_delete(parser);
}
void WorkspaceOGFile::update_symbols(
const std::vector<std::shared_ptr<symbol_info::SymbolInfo>>& symbol_infos) {
m_symbols.clear();
// TODO - sorting by definition location would be nice (maybe VSCode already does this?)
for (const auto& symbol_info : symbol_infos) {
LSPSpec::DocumentSymbol lsp_sym;
lsp_sym.m_name = symbol_info->m_name;
lsp_sym.m_detail = symbol_info->m_docstring;
switch (symbol_info->m_kind) {
case symbol_info::Kind::CONSTANT:
lsp_sym.m_kind = LSPSpec::SymbolKind::Constant;
break;
case symbol_info::Kind::FUNCTION:
lsp_sym.m_kind = LSPSpec::SymbolKind::Function;
break;
case symbol_info::Kind::GLOBAL_VAR:
lsp_sym.m_kind = LSPSpec::SymbolKind::Variable;
break;
case symbol_info::Kind::MACRO:
lsp_sym.m_kind = LSPSpec::SymbolKind::Operator;
break;
case symbol_info::Kind::METHOD:
lsp_sym.m_name = fmt::format("{}::{}", symbol_info->m_type, symbol_info->m_name);
lsp_sym.m_kind = LSPSpec::SymbolKind::Method;
break;
case symbol_info::Kind::TYPE:
lsp_sym.m_kind = LSPSpec::SymbolKind::Class;
break;
default:
lsp_sym.m_kind = LSPSpec::SymbolKind::Object;
break;
}
if (symbol_info->m_def_location) {
lsp_sym.m_range = LSPSpec::Range(symbol_info->m_def_location->line_idx,
symbol_info->m_def_location->char_idx);
} else {
lsp_sym.m_range = LSPSpec::Range(0, 0);
}
// TODO - would be nice to make this accurate but we don't store that info yet
lsp_sym.m_selectionRange = lsp_sym.m_range;
if (symbol_info->m_kind == symbol_info::Kind::TYPE) {
std::vector<LSPSpec::DocumentSymbol> type_symbols = {};
for (const auto& field : symbol_info->m_type_fields) {
LSPSpec::DocumentSymbol field_sym;
field_sym.m_name = field.name;
field_sym.m_detail = field.description;
if (field.is_array) {
field_sym.m_kind = LSPSpec::SymbolKind::Array;
} else {
field_sym.m_kind = LSPSpec::SymbolKind::Field;
}
// TODO - we don't store the line number for fields
field_sym.m_range = lsp_sym.m_range;
field_sym.m_selectionRange = lsp_sym.m_selectionRange;
type_symbols.push_back(field_sym);
}
for (const auto& method : symbol_info->m_type_methods) {
LSPSpec::DocumentSymbol method_sym;
method_sym.m_name = method.name;
method_sym.m_kind = LSPSpec::SymbolKind::Method;
// TODO - we don't store the line number for fields
method_sym.m_range = lsp_sym.m_range;
method_sym.m_selectionRange = lsp_sym.m_selectionRange;
type_symbols.push_back(method_sym);
}
for (const auto& state : symbol_info->m_type_states) {
LSPSpec::DocumentSymbol state_sym;
state_sym.m_name = state.name;
state_sym.m_kind = LSPSpec::SymbolKind::Event;
// TODO - we don't store the line number for fields
state_sym.m_range = lsp_sym.m_range;
state_sym.m_selectionRange = lsp_sym.m_selectionRange;
type_symbols.push_back(state_sym);
}
lsp_sym.m_children = type_symbols;
}
m_symbols.push_back(lsp_sym);
}
}
std::optional<std::string> WorkspaceOGFile::get_symbol_at_position(
const LSPSpec::Position position) const {
// Split the line on typical word boundaries
std::string line = m_lines.at(position.m_line);
std::smatch matches;
std::regex regex("[\\w\\.\\-_!<>*?]+");
std::regex_token_iterator<std::string::iterator> rend;
std::regex_token_iterator<std::string::iterator> match(line.begin(), line.end(), regex);
while (match != rend) {
auto match_start = std::distance(line.begin(), match->first);
auto match_end = match_start + match->length();
if (position.m_character >= match_start && position.m_character <= match_end) {
return match->str();
if (m_ast) {
TSNode root_node = ts_tree_root_node(m_ast.get());
TSNode found_node =
ts_node_descendant_for_point_range(root_node, {position.m_line, position.m_character},
{position.m_line, position.m_character});
if (!ts_node_has_error(found_node)) {
uint32_t start = ts_node_start_byte(found_node);
uint32_t end = ts_node_end_byte(found_node);
const std::string node_str = m_content.substr(start, end - start);
lg::debug("AST SAP - {}", node_str);
const std::string node_name = ts_node_type(found_node);
if (node_name == "sym_name") {
return node_str;
}
} else {
// found_node = ts_node_child(found_node, 0);
// TODO - maybe get this one (but check if has an error)
return {};
}
match++;
}
return {};
}
std::vector<OpenGOALFormResult> WorkspaceOGFile::search_for_forms_that_begin_with(
std::vector<std::string> prefix) const {
std::vector<OpenGOALFormResult> results = {};
if (!m_ast) {
return results;
}
return {};
TSNode root_node = ts_tree_root_node(m_ast.get());
std::vector<TSNode> found_nodes = {};
ast_util::search_for_forms_that_begin_with(m_content, root_node, prefix, found_nodes);
for (const auto& node : found_nodes) {
std::vector<std::string> tokens = {};
for (size_t i = 0; i < ts_node_child_count(node); i++) {
const auto child_node = ts_node_child(node, i);
const auto contents = ast_util::get_source_code(m_content, child_node);
tokens.push_back(contents);
}
const auto start_point = ts_node_start_point(node);
const auto end_point = ts_node_end_point(node);
results.push_back(
{tokens, {start_point.row, start_point.column}, {end_point.row, end_point.column}});
}
return results;
}
WorkspaceIRFile::WorkspaceIRFile(const std::string& content) {
@@ -356,7 +581,7 @@ void WorkspaceIRFile::find_all_types_path(const std::string& line) {
const auto& game_version = matches[1];
const auto& all_types_path = matches[2];
lg::debug("Found DTS Path - {} : {}", game_version.str(), all_types_path.str());
auto all_types_uri = uri_from_path(fs::path(all_types_path.str()));
auto all_types_uri = lsp_util::uri_from_path(fs::path(all_types_path.str()));
lg::debug("DTS URI - {}", all_types_uri);
if (valid_game_version(game_version.str())) {
m_game_version = game_name_to_version(game_version.str());
@@ -381,8 +606,6 @@ void WorkspaceIRFile::find_function_symbol(const uint32_t line_num_zero_based,
lg::info("Adding Symbol - {}", match.str());
LSPSpec::DocumentSymbol new_symbol;
new_symbol.m_name = match.str();
// TODO - function doc-string
// new_symbol.m_detail = ...
new_symbol.m_kind = LSPSpec::SymbolKind::Function;
LSPSpec::Range symbol_range;
symbol_range.m_start = {line_num_zero_based, 0};
+63 -14
View File
@@ -2,6 +2,7 @@
#include <optional>
#include <string>
#include <tuple>
#include <unordered_map>
#include "common/util/FileUtil.h"
@@ -14,20 +15,49 @@
#include "lsp/protocol/document_symbols.h"
#include "lsp/state/lsp_requester.h"
#include "third-party/tree-sitter/tree-sitter/lib/src/tree.h"
// TODO -
// https://sourcegraph.com/github.com/ensisoft/detonator@36f626caf957d0734865a8f5641be6170d997f45/-/blob/editor/app/lua-tools.cpp?L116:15-116:30
struct TreeSitterTreeDeleter {
void operator()(TSTree* ptr) const { ts_tree_delete(ptr); }
};
struct OpenGOALFormResult {
std::vector<std::string> tokens;
std::pair<int, int> start_point;
std::pair<int, int> end_point;
};
struct OGGlobalIndex {
std::unordered_map<std::string, Docs::SymbolDocumentation> global_symbols = {};
std::unordered_map<std::string, Docs::FileDocumentation> per_file_symbols = {};
};
class WorkspaceOGFile {
public:
WorkspaceOGFile(){};
WorkspaceOGFile(const std::string& content, const GameVersion& game_version);
// TODO - make private
int32_t version;
// TODO - keep an AST of the file instead
WorkspaceOGFile(const LSPSpec::DocumentUri& uri,
const std::string& content,
const GameVersion& game_version);
LSPSpec::DocumentUri m_uri;
std::string m_content;
std::vector<std::string> m_lines;
int m_line_count = 0;
std::string m_line_ending;
GameVersion m_game_version;
std::vector<LSPSpec::DocumentSymbol> m_symbols;
std::vector<LSPSpec::Diagnostic> m_diagnostics;
GameVersion m_game_version;
void parse_content(const std::string& new_content);
void update_symbols(const std::vector<std::shared_ptr<symbol_info::SymbolInfo>>& symbol_infos);
std::optional<std::string> get_symbol_at_position(const LSPSpec::Position position) const;
std::vector<OpenGOALFormResult> search_for_forms_that_begin_with(
std::vector<std::string> prefix) const;
private:
int32_t version;
std::shared_ptr<TSTree> m_ast;
};
class WorkspaceIRFile {
@@ -93,23 +123,40 @@ class Workspace {
// and it's a lot faster to check the end of a string, then multiple tracked file maps
FileType determine_filetype_from_languageid(const std::string& language_id);
FileType determine_filetype_from_uri(const LSPSpec::DocumentUri& file_uri);
std::optional<GameVersion> determine_game_version_from_uri(const LSPSpec::DocumentUri& uri);
void start_tracking_file(const LSPSpec::DocumentUri& file_uri,
const std::string& language_id,
const std::string& content);
void update_tracked_file(const LSPSpec::DocumentUri& file_uri, const std::string& content);
void tracked_file_will_save(const LSPSpec::DocumentUri& file_uri);
void update_global_index(const GameVersion game_version);
void stop_tracking_file(const LSPSpec::DocumentUri& file_uri);
std::optional<WorkspaceOGFile> get_tracked_og_file(const LSPSpec::URI& file_uri);
std::optional<WorkspaceIRFile> get_tracked_ir_file(const LSPSpec::URI& file_uri);
std::optional<std::reference_wrapper<WorkspaceOGFile>> get_tracked_og_file(
const LSPSpec::URI& file_uri);
std::optional<std::reference_wrapper<WorkspaceIRFile>> get_tracked_ir_file(
const LSPSpec::URI& file_uri);
std::optional<DefinitionMetadata> get_definition_info_from_all_types(
const std::string& symbol_name,
const LSPSpec::DocumentUri& all_types_uri);
std::optional<SymbolInfo> get_global_symbol_info(const WorkspaceOGFile& file,
const std::string& symbol_name);
std::optional<TypeSpec> get_symbol_typespec(const WorkspaceOGFile& file,
const std::string& symbol_name);
std::optional<Docs::DefinitionLocation> get_symbol_def_location(const WorkspaceOGFile& file,
const SymbolInfo& symbol_info);
std::vector<std::shared_ptr<symbol_info::SymbolInfo>> get_symbols_starting_with(
const GameVersion game_version,
const std::string& symbol_prefix);
std::optional<std::shared_ptr<symbol_info::SymbolInfo>> get_global_symbol_info(
const WorkspaceOGFile& file,
const std::string& symbol_name);
std::optional<std::pair<TypeSpec, Type*>> get_symbol_typeinfo(const WorkspaceOGFile& file,
const std::string& symbol_name);
std::optional<symbol_info::DefinitionLocation> get_symbol_def_location(
const WorkspaceOGFile& file,
const std::shared_ptr<symbol_info::SymbolInfo> symbol_info);
std::vector<std::tuple<std::string, std::string, Docs::DefinitionLocation>>
get_symbols_parent_type_path(const std::string& symbol_name, const GameVersion game_version);
std::vector<std::tuple<std::string, std::string, Docs::DefinitionLocation>> get_types_subtypes(
const std::string& symbol_name,
const GameVersion game_version);
std::unordered_map<std::string, s64> get_enum_entries(const std::string& enum_name,
const GameVersion game_version);
private:
LSPRequester m_requester;
@@ -126,5 +173,7 @@ class Workspace {
// and then we can track projects instead of games
//
// Until that decoupling happens, things like this will remain fairly clunky.
// TODO - change this to a shared_ptr so it can more easily be passed around functions
std::unordered_map<GameVersion, std::unique_ptr<Compiler>> m_compiler_instances;
std::unordered_map<GameVersion, OGGlobalIndex> m_global_indicies;
};
@@ -11,4 +11,4 @@ Separate Top Level
(println "test")
(println "test")
(println "test")

Some files were not shown because too many files have changed in this diff Show More