formatter: bunch of updates to the formatter

This commit is contained in:
Tyler Wilding 2024-05-18 13:50:24 -04:00
parent a61f24a168
commit 42a8df39ef
No known key found for this signature in database
GPG key ID: BF7B068C2FEFD7EF
19 changed files with 764 additions and 166 deletions

View file

@ -7,42 +7,58 @@
"project": "CMakeLists.txt",
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
"name": "Tests - Unit-Tests - Summary",
"args": ["--gtest_brief=1"]
"args": [
"--gtest_brief=1"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
"name": "Tests - Unit-Tests - Verbose",
"args": ["--gtest_brief=0"]
"args": [
"--gtest_brief=0"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
"name": "Tests - Draft Tests - Verbose",
"args": ["--gtest_brief=0", "--gtest_filter=\"*Draft*\""]
"args": [
"--gtest_brief=0",
"--gtest_filter=\"*Draft*\""
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
"name": "Tests - TypeConsistency - Verbose",
"args": ["--gtest_brief=0", "--gtest_filter=\"*TypeConsistency*\""]
"args": [
"--gtest_brief=0",
"--gtest_filter=\"*TypeConsistency*\""
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
"name": "Tests - TypeConsistency - Jak 2 - Verbose",
"args": ["--gtest_brief=0", "--gtest_filter=\"*Jak2TypeConsistency*\""]
"args": [
"--gtest_brief=0",
"--gtest_filter=\"*Jak2TypeConsistency*\""
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
"name": "Tests - WithGameTests - Verbose",
"args": ["--gtest_brief=0", "--gtest_filter=\"*WithGameTests*\""]
"args": [
"--gtest_brief=0",
"--gtest_filter=\"*WithGameTests*\""
]
},
{
"type": "default",
@ -113,56 +129,109 @@
"project": "CMakeLists.txt",
"projectTarget": "gk.exe (bin\\gk.exe)",
"name": "Game - Jak 1 - Runtime",
"args": ["-v", "--game", "jak1", "--", "-fakeiso", "-debug"]
"args": [
"-v",
"--game",
"jak1",
"--",
"-fakeiso",
"-debug"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "gk.exe (bin\\gk.exe)",
"name": "Game - Jak 1 - Runtime (boot)",
"args": ["-v", "--game", "jak1", "--", "-boot", "-fakeiso", "-debug"]
"args": [
"-v",
"--game",
"jak1",
"--",
"-boot",
"-fakeiso",
"-debug"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "gk.exe (bin\\gk.exe)",
"name": "Game - Jak 2 - Runtime (no boot)",
"args": ["-v", "--game", "jak2", "--", "-fakeiso", "-debug"]
"args": [
"-v",
"--game",
"jak2",
"--",
"-fakeiso",
"-debug"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "gk.exe (bin\\gk.exe)",
"name": "Game - Jak 2 - Runtime (boot)",
"args": ["-v", "--game", "jak2", "--", "-boot", "-fakeiso", "-debug"]
"args": [
"-v",
"--game",
"jak2",
"--",
"-boot",
"-fakeiso",
"-debug"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "gk.exe (bin\\gk.exe)",
"name": "Game - Jak 2 - Runtime (release)",
"args": ["-v", "--game", "jak2", "--", "-boot", "-fakeiso"]
"args": [
"-v",
"--game",
"jak2",
"--",
"-boot",
"-fakeiso"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "gk.exe (bin\\gk.exe)",
"name": "Game - Jak 3 - Runtime (boot)",
"args": ["-v", "--game", "jak3", "--", "-boot", "-fakeiso", "-debug"]
"args": [
"-v",
"--game",
"jak3",
"--",
"-boot",
"-fakeiso",
"-debug"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc.exe (bin\\goalc.exe)",
"name": "REPL - Jak 1",
"args": ["--user-auto", "--game", "jak1"]
"args": [
"--user-auto",
"--game",
"jak1"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc.exe (bin\\goalc.exe)",
"name": "REPL - Jak 2",
"args": ["--user-auto", "--game", "jak2"]
"args": [
"--user-auto",
"--game",
"jak2"
]
},
{
"type": "default",
@ -262,14 +331,26 @@
"project": "CMakeLists.txt",
"projectTarget": "memory_dump_tool.exe (bin\\memory_dump_tool.exe)",
"name": "Tools - EE Memory Analyze - Jak 1",
"args": ["\"${workspaceRoot}/eeMemory.bin\"", "--output-path", "\"${workspaceRoot}\"", "--game", "jak1"]
"args": [
"\"${workspaceRoot}/eeMemory.bin\"",
"--output-path",
"\"${workspaceRoot}\"",
"--game",
"jak1"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "memory_dump_tool.exe (bin\\memory_dump_tool.exe)",
"name": "Tools - EE Memory Analyze - Jak 2",
"args": ["\"${workspaceRoot}/eeMemory.bin\"", "--output-path", "\"${workspaceRoot}\"", "--game", "jak2"]
"args": [
"\"${workspaceRoot}/eeMemory.bin\"",
"--output-path",
"\"${workspaceRoot}\"",
"--game",
"jak2"
]
},
{
"type": "default",
@ -286,35 +367,53 @@
"project": "CMakeLists.txt",
"projectTarget": "extractor.exe (bin\\extractor.exe)",
"name": "Tools - Extractor - Full",
"args": ["\"E:\\ISOs\\Jak\\Jak 1.iso\""]
"args": [
"\"E:\\ISOs\\Jak\\Jak 1.iso\""
]
},
{
"type" : "default",
"project" : "CMakeLists.txt",
"projectTarget" : "lsp.exe (bin\\lsp.exe)",
"name" : "Tools - LSP",
"args" : []
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "lsp.exe (bin\\lsp.exe)",
"name": "Tools - LSP",
"args": []
},
{
"type" : "default",
"project" : "CMakeLists.txt",
"projectTarget" : "type_searcher.exe (bin\\type_searcher.exe)",
"name" : "Tools - Type Searcher",
"args" : ["--game", "jak2", "--output-path", "./search-results.json", "--size", 255, "--fields", "[{\\\"type\\\":\\\"quaternion\\\",\\\"offset\\\":48}]"]
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "type_searcher.exe (bin\\type_searcher.exe)",
"name": "Tools - Type Searcher",
"args": [
"--game",
"jak2",
"--output-path",
"./search-results.json",
"--size",
255,
"--fields",
"[{\\\"type\\\":\\\"quaternion\\\",\\\"offset\\\":48}]"
]
},
{
"type" : "default",
"project" : "CMakeLists.txt",
"projectTarget" : "formatter.exe (bin\\formatter.exe)",
"name" : "Tools - Formatter - Inplace",
"args" : ["--write", "--file", "C:\\Users\\xtvas\\Repos\\opengoal\\jak-project\\decompiler_out\\jak3\\mood-h_disasm.gc"]
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "formatter.exe (bin\\formatter.exe)",
"name": "Tools - Formatter - Inplace",
"args": [
"--write",
"--file",
"C:\\Users\\xtvas\\Repositories\\opengoal\\jak-project\\goal_src\\jak1\\engine\\anim\\joint.gc"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
"name": "Tests - Formatter",
"args": ["--gtest_brief=0", "--gtest_filter=\"*FormatterTests*\""]
"args": [
"--gtest_brief=0",
"--gtest_filter=\"*FormatterTests*\""
]
}
]
}

View file

@ -33,14 +33,16 @@ int hang_indentation_width(const FormatterTreeNode& curr_node) {
return 1 + hang_indentation_width(first_elt);
}
// TODO - this doesn't account for paren's width contribution!
int get_total_form_inlined_width(const FormatterTreeNode& curr_node) {
if (curr_node.token) {
return curr_node.token->length();
}
int width = 1;
for (const auto& ref : curr_node.refs) {
width += get_total_form_inlined_width(ref);
for (int i = 0; i < curr_node.refs.size(); i++) {
width += get_total_form_inlined_width(curr_node.refs.at(i));
if (i != curr_node.refs.size() - 1) {
width += 1; // add the space between elements
}
}
return width + 1;
}
@ -104,7 +106,7 @@ void apply_formatting_config(
if (curr_node.formatting_config.has_constant_pairs) {
for (int i = 0; i < (int)curr_node.refs.size(); i++) {
auto& child_ref = curr_node.refs.at(i);
const auto type = child_ref.metadata.node_type;
const auto& type = child_ref.metadata.node_type;
if (constant_types.find(type) == constant_types.end() &&
constant_pairs::is_element_second_in_constant_pair(curr_node, child_ref, i)) {
child_ref.formatting_config.parent_mutable_extra_indent = 2;
@ -151,10 +153,26 @@ void apply_formatting_config(
max_columns = field.refs.size();
}
}
// if only one field has a value in the max col position, it looks weird for it to be indented
bool ignore_final_column_width = true;
int fields_with_atleast_max_col = 0;
for (const auto& field : curr_node.refs) {
if ((int)field.refs.size() == max_columns) {
fields_with_atleast_max_col++;
if (fields_with_atleast_max_col > 1) {
ignore_final_column_width = false;
break;
}
}
}
// Now find the column max widths
std::vector<int> column_max_widths = {};
for (int col = 0; col < max_columns; col++) {
column_max_widths.push_back(0);
// -2 because its the indentation before the final column that we want to skip
if (ignore_final_column_width && col == max_columns - 2) {
continue;
}
for (const auto& field : curr_node.refs) {
if ((int)field.refs.size() > col) {
const auto width = get_total_form_inlined_width(field.refs.at(col));
@ -264,13 +282,15 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
// Add new line entry
if (ref.token) {
// Cleanup block-comments
std::string val = ref.token_str();
if (ref.metadata.node_type == "block_comment") {
// TODO - change this sanitization to return a list of lines instead of a single new-lined
// line
val = comments::format_block_comment(ref.token_str());
const auto comment_lines = comments::format_block_comment(ref.token_str());
for (const auto& line : comment_lines) {
form_lines.push_back(line);
}
form_lines.push_back(val);
} else {
form_lines.push_back(ref.token_str());
}
if (!curr_node.metadata.is_top_level && i == (int)curr_node.refs.size() - 1 &&
(ref.metadata.is_comment)) {
// if there's an inline comment at the end of a form, we have to force the paren to the next
@ -306,6 +326,13 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
if (next_ref.token) {
form_lines.at(form_lines.size() - 1) += fmt::format(" {}", next_ref.token.value());
i++;
// We have to handle hang-consolidation here or else it will never be reached above!
if (i == (int)curr_node.refs.size() - 1 && form_lines.size() > 1 &&
(curr_node.formatting_config.hang_forms ||
curr_node.formatting_config.combine_first_two_lines)) {
form_lines.at(0) += fmt::format(" {}", form_lines.at(1));
form_lines.erase(form_lines.begin() + 1);
}
} else if (can_node_be_inlined(next_ref, cursor_pos)) {
const auto& lines = apply_formatting(next_ref, {}, cursor_pos); // TODO - cursor pos
for (const auto& line : lines) {
@ -379,7 +406,14 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
curr_form += str_util::repeat(curr_node.formatting_config.parent_mutable_extra_indent, " ");
}
if (inline_form) {
form_lines = {fmt::format("{}", fmt::join(form_lines, " "))};
// NOTE - not sure about this, if we are inlining a form, it always makes sense to eliminate
// trailing whitespace the only issue i can foresee is related to strings that span multiple
// lines.
std::vector<std::string> new_form_lines = {};
for (const auto& form_line : form_lines) {
new_form_lines.push_back(str_util::ltrim(form_line));
}
form_lines = {fmt::format("{}", fmt::join(new_form_lines, " "))};
} else {
for (int i = 0; i < (int)form_lines.size(); i++) {
if (i > 0) {

View file

@ -36,21 +36,28 @@ bool should_insert_blank_line(const FormatterTreeNode& containing_node,
if (node.metadata.is_comment && node.metadata.num_blank_lines_following == 0) {
return false;
}
// If the next form is a comment and is inline, don't insert a comment
// If the next form is a comment and is inline, don't insert a new line
if ((index + 1) < (int)containing_node.refs.size() &&
containing_node.refs.at(index + 1).metadata.is_comment &&
containing_node.refs.at(index + 1).metadata.is_inline) {
return false;
}
// TODO - only if the form doesn't fit on a single line
if (node.formatting_config.elide_top_level_newline) {
if ((index + 1) < (int)containing_node.refs.size() &&
containing_node.refs.at(index + 1).metadata.is_comment) {
return true;
}
return false;
}
return true;
}
} // namespace blank_lines
namespace comments {
std::string format_block_comment(const std::string& comment) {
std::vector<std::string> format_block_comment(const std::string& comment) {
// Normalize block comments, remove any trailing or leading whitespace
// Only allow annotations on the first line, like #|@file
// Don't mess with internal indentation as the user might intend it to be a certain way.
@ -71,12 +78,18 @@ std::string format_block_comment(const std::string& comment) {
// Remove trailing whitespace
comment_contents = str_util::rtrim(comment_contents);
// remove |#
// TODO - check suffix
if (str_util::ends_with(comment_contents, "|#")) {
comment_contents.pop_back();
comment_contents.pop_back();
}
comment_contents = str_util::rtrim(comment_contents);
new_comment += fmt::format("\n{}\n|#", comment_contents);
return new_comment;
std::vector<std::string> lines = {new_comment};
const auto contents_as_lines = str_util::split_string(comment_contents, "\n");
for (const auto& line : contents_as_lines) {
lines.push_back(line);
}
lines.push_back("|#");
return lines;
}
} // namespace comments

View file

@ -36,7 +36,7 @@ bool should_insert_blank_line(const FormatterTreeNode& containing_node,
//
// Reference - https://github.com/kkinnear/zprint/blob/main/doc/options/comments.md
namespace comments {
std::string format_block_comment(const std::string& comment);
std::vector<std::string> format_block_comment(const std::string& comment);
}
// Paired elements in a list will be kept in-line rather than the default new-line indentation

View file

@ -3,22 +3,103 @@
namespace formatter_rules {
namespace config {
static FormFormattingConfig new_inlinable_simple_flow_rule() {
return {.config_set = true, .hang_forms = false};
}
static FormFormattingConfig new_permissive_flow_rule() {
return {.config_set = true, .hang_forms = false, .combine_first_two_lines = true};
}
static FormFormattingConfig new_flow_rule(int start_index) {
static FormFormattingConfig new_flow_rule(int start_index, bool has_constant_pairs = false) {
return {.config_set = true,
.hang_forms = false,
.inline_until_index = [start_index](const std::vector<std::string>& /*curr_lines*/) {
.inline_until_index =
[start_index](const std::vector<std::string>& /*curr_lines*/) { return start_index; },
.has_constant_pairs = has_constant_pairs};
}
static FormFormattingConfig new_inlineable_flow_rule(int start_index,
bool has_constant_pairs = false) {
return {.config_set = true,
.hang_forms = false,
.inline_until_index =
[start_index](const std::vector<std::string>& curr_lines) {
int total_width = 0;
for (const auto& line : curr_lines) {
total_width += line.length();
// an empty line implies a new-line was forced, this is bleeding implementation
// details, but fine for now
if (line.empty()) {
return start_index;
}};
}
}
if (total_width <= 120) {
return (int)curr_lines.size();
}
return start_index;
},
.has_constant_pairs = has_constant_pairs};
}
static FormFormattingConfig new_defstate_rule(int start_index, bool has_constant_pairs = false) {
FormFormattingConfig cfg = {
.config_set = true,
.hang_forms = false,
.inline_until_index =
[start_index](const std::vector<std::string>& /*curr_lines*/) { return start_index; },
.has_constant_pairs = has_constant_pairs};
// TODO - might be nice to have a function that returns a config based on a given index, instead
// of hardcoding them!
std::vector<int> state_handler_indexes = {4, 6, 8, 10,
12}; // NOTE - not all of these have to be defined
for (const auto& index : state_handler_indexes) {
auto temp_config = std::make_shared<FormFormattingConfig>();
temp_config->config_set = true;
temp_config->prevent_inlining = true;
temp_config->hang_forms = false;
temp_config->inline_until_index = [](const std::vector<std::string>& /*curr_lines*/) {
return 2;
};
temp_config->parent_mutable_extra_indent = 2;
cfg.index_configs.emplace(index, temp_config);
}
return cfg;
}
static FormFormattingConfig new_defmethod_rule(int start_index, bool has_constant_pairs = false) {
return {.config_set = true,
.hang_forms = false,
.inline_until_index =
[start_index](const std::vector<std::string>& curr_lines) {
if (curr_lines.size() >= 2 && curr_lines.at(1) == "new") {
// defmethod was changed to omit the type name for everything except the `new`
// method, so special case.
return start_index + 1;
}
return start_index;
},
.has_constant_pairs = has_constant_pairs};
}
static FormFormattingConfig new_defnum_rule() {
auto temp_list_config = std::make_shared<FormFormattingConfig>();
temp_list_config->force_inline = true;
temp_list_config->hang_forms = false;
return {
.config_set = true,
.hang_forms = false,
.inline_until_index = [](const std::vector<std::string>& /*curr_lines*/) { return 2; },
.has_constant_pairs = true,
.default_index_config = temp_list_config,
};
}
static FormFormattingConfig new_deftype_rule(
int start_index,
const std::vector<int>& inlining_preventation_indices) {
FormFormattingConfig cfg;
cfg.has_constant_pairs = true;
cfg.config_set = true;
cfg.hang_forms = false;
cfg.inline_until_index = [start_index](std::vector<std::string> curr_lines) {
@ -88,23 +169,39 @@ static FormFormattingConfig new_pair_rule(bool combine_first_two_expr) {
return cfg;
}
static FormFormattingConfig new_top_level_inline_form(bool elide_new_line) {
return {.force_inline = true, .elide_top_level_newline = elide_new_line};
}
const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config = {
{"case", new_pair_rule(true)},
{"cond", new_pair_rule(false)},
{"defmethod", new_flow_rule(3)},
{"in-package", new_top_level_inline_form(true)},
{"bundles", new_top_level_inline_form(true)},
{"require", new_top_level_inline_form(true)},
{"defenum", new_defnum_rule()},
{"defmethod", new_defmethod_rule(3)},
{"deftype", new_deftype_rule(3, {3, 4, 5, 6})},
{"defun", new_flow_rule(3)},
{"defun-debug", new_flow_rule(3)},
{"defbehavior", new_flow_rule(4)},
{"if", new_permissive_flow_rule()},
{"if", new_inlineable_flow_rule(2)},
{"define", new_permissive_flow_rule()},
{"define-extern", new_permissive_flow_rule()},
{"defmacro", new_flow_rule(3)},
{"defstate", new_defstate_rule(3, true)},
{"behavior", new_flow_rule(2)},
{"dotimes", new_flow_rule(2)},
{"let", new_binding_rule(4)},
{"let*", new_binding_rule(5)},
{"rlet", new_binding_rule(5)},
{"when", new_flow_rule(2)},
{"countdown", new_flow_rule(2)},
{"until", new_flow_rule(2)},
{"while", new_flow_rule(2)},
{"begin", new_flow_rule(0)},
{"with-pp", new_flow_rule(0)},
{"local-vars", new_inlinable_simple_flow_rule()},
{"with-dma-buffer-add-bucket", new_flow_rule(2)}};
} // namespace config
} // namespace formatter_rules

View file

@ -7,7 +7,6 @@
#include <unordered_map>
#include <vector>
// TODO - some way to apply a config to all list elements (index configs with -1?)
namespace formatter_rules {
namespace config {
struct FormFormattingConfig {
@ -36,6 +35,8 @@ struct FormFormattingConfig {
bool determine_column_widths_for_list_elements = false;
std::vector<int> list_element_column_widths = {};
bool elide_top_level_newline = false;
};
extern const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config;

View file

@ -12,3 +12,39 @@ Separate Top Level
(println "test")
(println "test")
===
Consolidate Top Level
===
(in-package goal)
(bundles "ENGINE.CGO" "GAME.CGO")
(require "engine/draw/drawable-h.gc")
(require "kernel/gstate.gc")
---
(in-package goal)
(bundles "ENGINE.CGO" "GAME.CGO")
(require "engine/draw/drawable-h.gc")
(require "kernel/gstate.gc")
===
Consolidate Top Level - Ignore and space out comment
===
(in-package goal)
(bundles "ENGINE.CGO" "GAME.CGO")
(require "engine/draw/drawable-h.gc")
(require "kernel/gstate.gc")
;; Some comment
---
(in-package goal)
(bundles "ENGINE.CGO" "GAME.CGO")
(require "engine/draw/drawable-h.gc")
(require "kernel/gstate.gc")
;; Some comment

View file

@ -105,7 +105,7 @@ Block Comment - Allow Annotations
(println "test")
===
Block Comment - In Form - TODO Improve
Block Comment - In Form
===
(println
@ -120,7 +120,7 @@ Block Comment - In Form - TODO Improve
#|
block comment
test
|#
|#
"test")
===
@ -139,7 +139,7 @@ At the end of a form
)
===
Block at the end of a form - TODO Improve
Block at the end of a form
===
(println
@ -152,11 +152,11 @@ Block at the end of a form - TODO Improve
(println "hello world"
#|
wow look at that block comment
|#
|#
)
===
Inline at the end of a form - TODO-A handle hanging in this instance better
Inline at the end of a single element form
===
(println
@ -165,7 +165,6 @@ Inline at the end of a form - TODO-A handle hanging in this instance better
---
(println
"hello world" ;; this is a comment
(println "hello world" ;; this is a comment
)

View file

@ -42,3 +42,36 @@ Multiline condition hang
(or (and (-> this opened-with-start?) (not (cpad-hold? 0 start)) (not (cpad-hold? 0 start)))
(and (not (-> this opened-with-start?)) (not (cpad-hold? 0 select)))))
(set! (-> this ignore-menu-toggle?) #f))
===
Consolidation of if
===
(if (and
(-> this data s2-0) ;; entry is populated
(= (-> this data s2-0 type) arg1) ;; type is right
(or (name= arg0 (-> this data s2-0 name)) (string-charp= arg0 (&-> (-> this data s2-0 name) data s3-0))) ;; name is right. also seek past ag name, and try again.
)
(return (the-as joint (-> this data s2-0))))
---
(if (and (-> this data s2-0) ;; entry is populated
(= (-> this data s2-0 type) arg1) ;; type is right
(or (name= arg0 (-> this data s2-0 name)) (string-charp= arg0 (&-> (-> this data s2-0 name) data s3-0))) ;; name is right. also seek past ag name, and try again.
)
(return (the-as joint (-> this data s2-0))))
===
Consolidation of if 2
===
(if (or (not s5-1) (= (-> s5-1 name) 'default))
(login this) ;; not part of level load, just normal login.
)
---
(if (or (not s5-1) (= (-> s5-1 name) 'default))
(login this) ;; not part of level load, just normal login.
)

View file

@ -0,0 +1,86 @@
===
With Bitfield and Type Info
===
(defenum
process-mask
:bitfield
#t
:type
uint32
(execute 0) ;; 1
(draw 1) ;; 2
(pause 2) ;; 4
(menu 3) ;; 8
(progress 4) ;; 16
(actor-pause 5) ;; 32
(sleep 6) ;; 64
(sleep-code 7) ;; 128
(process-tree 8) ;; 256 not an actual process, just a "tree node" for organization
(heap-shrunk 9) ;; 512
(going 10) ;; 1024
(movie 11) ;; 2048
(movie-subject 12) ;; 4096
(target 13) ;; 8192
(sidekick 14) ;; 16384
(crate 15) ;; 32768
(collectable 16) ;; 65536
(enemy 17) ;; 131072
(camera 18) ;; 262144
(platform 19) ;; 524288
(ambient 20) ;; 1048576
(entity 21) ;; 2097152
(projectile 22) ;; 4194304
(attackable 23) ;; 8388608
(death 24) ;; 16777216
)
---
(defenum process-mask
:bitfield #t
:type uint32
(execute 0) ;; 1
(draw 1) ;; 2
(pause 2) ;; 4
(menu 3) ;; 8
(progress 4) ;; 16
(actor-pause 5) ;; 32
(sleep 6) ;; 64
(sleep-code 7) ;; 128
(process-tree 8) ;; 256 not an actual process, just a "tree node" for organization
(heap-shrunk 9) ;; 512
(going 10) ;; 1024
(movie 11) ;; 2048
(movie-subject 12) ;; 4096
(target 13) ;; 8192
(sidekick 14) ;; 16384
(crate 15) ;; 32768
(collectable 16) ;; 65536
(enemy 17) ;; 131072
(camera 18) ;; 262144
(platform 19) ;; 524288
(ambient 20) ;; 1048576
(entity 21) ;; 2097152
(projectile 22) ;; 4194304
(attackable 23) ;; 8388608
(death 24) ;; 16777216
)
===
Form heads that overlap with built-in forms
===
(defenum pc-prof-event
(begin
0)
(end 1)
(instant 2))
---
(defenum pc-prof-event
(begin 0)
(end 1)
(instant 2))

View file

@ -82,3 +82,18 @@ Basic behavior
(quaternion-copy! (-> gp-0 quat) (-> arg0 quat))
(vector-identity! (-> gp-0 scale))
(the-as symbol (send-event *camera* 'teleport-to-transformq gp-0))))
===
Methods - new
===
(defmethod new align-control
((allocation symbol) (type-to-make type) (proc process-drawable))
"Create a new align-control."
(+ 1 1))
---
(defmethod new align-control ((allocation symbol) (type-to-make type) (proc process-drawable))
"Create a new align-control."
(+ 1 1))

View file

@ -81,3 +81,70 @@ begin
(begin
"hello"
(println "world"))
===
Inlining flowed form
===
(or something (begin (+ 1 2) (= 2 2)))
---
(or something (begin (+ 1 2) (= 2 2)))
===
Long array creation
===
(let ((arr (new
'static
'array
uint32
16
#x7b2191b ;; = 6 ^ 129112349
#x7b21914 ;; = 9 ^ 129112349
#x7b21916 ;; = 11 ^ 129112349
#x7b21913 ;; = 14 ^ 129112349
#x7b21909 ;; = 20 ^ 129112349
#x7b21908 ;; = 21 ^ 129112349
#x7b2190a ;; = 23 ^ 129112349
#x7b21907 ;; = 26 ^ 129112349
#x7b2191b ;; = 6 ^ 129112349
#x7b21917 ;; = 10 ^ 129112349
#x7b21916 ;; = 11 ^ 129112349
#x7b2190c ;; = 17 ^ 129112349
#x7b21909 ;; = 20 ^ 129112349
#x7b2190b ;; = 22 ^ 129112349
#x7b2190a ;; = 23 ^ 129112349
#x7b21900 ;; = 29 ^ 129112349
)))
(dotimes (i 16)
(set! (-> (scratchpad-object terrain-context) work foreground joint-work frm-jmp-table i)
(the-as (function none) (-> arr i)))))
---
(let ((arr (new 'static
'array
uint32
16
#x7b2191b ;; = 6 ^ 129112349
#x7b21914 ;; = 9 ^ 129112349
#x7b21916 ;; = 11 ^ 129112349
#x7b21913 ;; = 14 ^ 129112349
#x7b21909 ;; = 20 ^ 129112349
#x7b21908 ;; = 21 ^ 129112349
#x7b2190a ;; = 23 ^ 129112349
#x7b21907 ;; = 26 ^ 129112349
#x7b2191b ;; = 6 ^ 129112349
#x7b21917 ;; = 10 ^ 129112349
#x7b21916 ;; = 11 ^ 129112349
#x7b2190c ;; = 17 ^ 129112349
#x7b21909 ;; = 20 ^ 129112349
#x7b2190b ;; = 22 ^ 129112349
#x7b2190a ;; = 23 ^ 129112349
#x7b21900 ;; = 29 ^ 129112349
)))
(dotimes (i 16)
(set! (-> (scratchpad-object terrain-context) work foreground joint-work frm-jmp-table i)
(the-as (function none) (-> arr i)))))

View file

@ -1,52 +1,92 @@
===
TODO - Basic State
Basic State
===
(defstate active (enemy)
:virtual #t
:event enemy-event-handler
:enter (behavior ()
(defstate joint-exploder-shatter (joint-exploder)
:enter
(behavior ()
(set-time! (-> self state-time)))
:trans
(behavior ()
(let* ((f1-0 (the float (- (current-time) (-> self state-time))))
(f0-2 (- 1.0 (/ f1-0 (the float (-> self tuning duration)))))
(f1-2 (- 1.0 (/ f1-0 (* 0.75 (the float (-> self tuning duration)))))))
(if (< f1-2 0.0) (set! f1-2 0.0))
(set-vector! (-> self scale-vector) f0-2 f1-2 f0-2 1.0))
(dotimes (v1-8 5)
(set! (-> self lists v1-8 pre-moved?) #f))
(dotimes (gp-0 5)
(let ((s5-0 (-> self lists gp-0)))
(when (>= (-> s5-0 head) 0)
(when (not (-> s5-0 pre-moved?))
(joint-exploder-method-25 self s5-0)
(if (nonzero? gp-0) (joint-exploder-method-28 self s5-0))))))
(let ((gp-1 (new 'stack-no-clear 'bounding-box)))
(let ((v1-26 (-> self root trans))) (set! (-> gp-1 min quad) (-> v1-26 quad)) (set! (-> gp-1 max quad) (-> v1-26 quad)))
(dotimes (s5-1 5)
(let ((s4-0 (-> self lists s5-1)))
(if (-> s4-0 bbox-valid?) (add-box! gp-1 (-> s4-0 bbox)))
(if (nonzero? s5-1) (joint-exploder-method-22 self s4-0))))
(let ((s5-2 (-> self draw bounds)))
(set-vector! s5-2
(* 0.5 (+ (-> gp-1 min x) (-> gp-1 max x)))
(* 0.5 (+ (-> gp-1 min y) (-> gp-1 max y)))
(* 0.5 (+ (-> gp-1 min z) (-> gp-1 max z)))
1.0)
(let ((f0-12 (+ 16384.0 (vector-vector-distance s5-2 (-> gp-1 max)))))
(vector-! s5-2 s5-2 (-> self root trans))
(set! (-> s5-2 w) f0-12))))
0)
:code
(behavior ()
(set-time! (-> self state-time))
(logclear! (-> self enemy-flags) (enemy-flag cam-attack-mode))
(when (logtest? (-> self enemy-flags) (enemy-flag enable-on-active))
(logclear! (-> self enemy-flags) (enemy-flag enable-on-active))
(let ((gp-0 (-> self on-active)))
(if gp-0
(script-eval gp-0 :vector (-> self root trans))
)
)
)
(when (not (logtest? (enemy-flag chase-startup) (-> self enemy-flags)))
(if (logtest? (-> self enemy-flags) (enemy-flag actor-pause-backup))
(logior! (-> self mask) (process-mask actor-pause))
(logclear! (-> self mask) (process-mask actor-pause))
)
)
)
:trans (behavior ()
(when (time-elapsed? (-> self state-time) (seconds 0.1))
(let ((v1-3 (-> self focus aware)))
(cond
((< (the-as int v1-3) 1)
(go-virtual idle)
)
((< 1 (the-as int v1-3))
(go-virtual notice)
)
)
)
)
)
:code (behavior ()
(ja-channel-push! 1 (seconds 0.1))
(sleep-code)
)
:post (behavior ()
(idle-control-method-10 (-> self idle-anim-player) self)
(enemy-simple-post)
)
)
(until (time-elapsed? (-> self state-time) (-> self tuning duration))
(suspend)
(ja :num! (loop!))))
:post
ja-post)
---
TODO
(defstate joint-exploder-shatter (joint-exploder)
:enter
(behavior ()
(set-time! (-> self state-time)))
:trans
(behavior ()
(let* ((f1-0 (the float (- (current-time) (-> self state-time))))
(f0-2 (- 1.0 (/ f1-0 (the float (-> self tuning duration)))))
(f1-2 (- 1.0 (/ f1-0 (* 0.75 (the float (-> self tuning duration)))))))
(if (< f1-2 0.0) (set! f1-2 0.0))
(set-vector! (-> self scale-vector) f0-2 f1-2 f0-2 1.0))
(dotimes (v1-8 5)
(set! (-> self lists v1-8 pre-moved?) #f))
(dotimes (gp-0 5)
(let ((s5-0 (-> self lists gp-0)))
(when (>= (-> s5-0 head) 0)
(when (not (-> s5-0 pre-moved?))
(joint-exploder-method-25 self s5-0)
(if (nonzero? gp-0) (joint-exploder-method-28 self s5-0))))))
(let ((gp-1 (new 'stack-no-clear 'bounding-box)))
(let ((v1-26 (-> self root trans))) (set! (-> gp-1 min quad) (-> v1-26 quad)) (set! (-> gp-1 max quad) (-> v1-26 quad)))
(dotimes (s5-1 5)
(let ((s4-0 (-> self lists s5-1)))
(if (-> s4-0 bbox-valid?) (add-box! gp-1 (-> s4-0 bbox)))
(if (nonzero? s5-1) (joint-exploder-method-22 self s4-0))))
(let ((s5-2 (-> self draw bounds)))
(set-vector! s5-2
(* 0.5 (+ (-> gp-1 min x) (-> gp-1 max x)))
(* 0.5 (+ (-> gp-1 min y) (-> gp-1 max y)))
(* 0.5 (+ (-> gp-1 min z) (-> gp-1 max z)))
1.0)
(let ((f0-12 (+ 16384.0 (vector-vector-distance s5-2 (-> gp-1 max)))))
(vector-! s5-2 s5-2 (-> self root trans))
(set! (-> s5-2 w) f0-12))))
0)
:code
(behavior ()
(set-time! (-> self state-time))
(until (time-elapsed? (-> self state-time) (-> self tuning duration))
(suspend)
(ja :num! (loop!))))
:post ja-post)

View file

@ -105,3 +105,91 @@ Types - With Methods and States
pov-camera-playing
pov-camera-start-playing
pov-camera-startup))
===
With flags
===
(deftype process-tree (basic)
((name basic :offset-assert 4)
(mask process-mask :offset-assert 8)
(parent (pointer process-tree) :offset-assert 12)
(brother (pointer process-tree) :offset-assert 16)
(child (pointer process-tree) :offset-assert 20)
(ppointer (pointer process) :offset-assert 24)
(self process-tree :offset-assert 28))
(:methods
(new (symbol type basic) _type_)
(activate (_type_ process-tree basic pointer) process-tree) ;; 9
(deactivate (_type_) none) ;; 10
(init-from-entity! (_type_ entity-actor) none) ;; 11
(run-logic? (_type_) symbol) ;; 12
(process-tree-method-13 () none) ;; 13
)
:size-assert
#x20
:method-count-assert
14
:no-runtime-type ;; already defined by kscheme. Don't do it again.
)
---
(deftype process-tree (basic)
((name basic :offset-assert 4)
(mask process-mask :offset-assert 8)
(parent (pointer process-tree) :offset-assert 12)
(brother (pointer process-tree) :offset-assert 16)
(child (pointer process-tree) :offset-assert 20)
(ppointer (pointer process) :offset-assert 24)
(self process-tree :offset-assert 28))
(:methods
(new (symbol type basic) _type_)
(activate (_type_ process-tree basic pointer) process-tree) ;; 9
(deactivate (_type_) none) ;; 10
(init-from-entity! (_type_ entity-actor) none) ;; 11
(run-logic? (_type_) symbol) ;; 12
(process-tree-method-13 () none) ;; 13
)
:size-assert #x20
:method-count-assert 14
:no-runtime-type ;; already defined by kscheme. Don't do it again.
)
===
Single value column
===
(deftype joint-control-channel (structure)
((parent joint-control)
(command symbol)
(frame-interp float)
(frame-group art-joint-anim)
(frame-num float)
(num-func (function joint-control-channel float float float))
(param float 2)
(group-sub-index int16)
(group-size int16)
(dist meters)
(eval-time uint32)
(inspector-amount float))
(:methods
(debug-print-frames (_type_) _type_)))
---
(deftype joint-control-channel (structure)
((parent joint-control)
(command symbol)
(frame-interp float)
(frame-group art-joint-anim)
(frame-num float)
(num-func (function joint-control-channel float float float))
(param float 2)
(group-sub-index int16)
(group-size int16)
(dist meters)
(eval-time uint32)
(inspector-amount float))
(:methods
(debug-print-frames (_type_) _type_)))

View file

@ -56,7 +56,7 @@ std::vector<TestDefinition> get_test_definitions(const fs::path& file_path) {
if (!curr_test.name.empty() && line.empty()) {
i++;
while (true) {
if (contents.at(i) == "---") {
if (str_util::trim(contents.at(i)) == "---") {
i++;
curr_test.input = str_util::trim(curr_test.input);
break;

View file

@ -205,7 +205,7 @@ module.exports = grammar({
seq(field('numberOfArgs', $._format_token), '*'),
'?',
"Newline",
seq(repeat(choice($._format_token, ',')), /[$mrRbBdDgGxXeEoOsStTfHhJjKkLlNnVwWyYzZ]/),
seq(repeat(choice($._format_token, ',')), /[$mrRbBdDgGxXeEoOsStTfFHhJjKkLlNnVwWyYzZ]/),
),
format_specifier: $ =>
prec.left(seq(

View file

@ -646,7 +646,7 @@
},
{
"type": "PATTERN",
"value": "[$mrRbBdDgGxXeEoOsStTfHhJjKkLlNnVwWyYzZ]"
"value": "[$mrRbBdDgGxXeEoOsStTfFHhJjKkLlNnVwWyYzZ]"
}
]
}

View file

@ -722,46 +722,18 @@ static inline bool sym_kwd_lit_character_set_2(int32_t c) {
}
static inline bool aux_sym_format_directive_type_token11_character_set_1(int32_t c) {
return (c < 'R'
? (c < 'G'
return (c < 'V'
? (c < 'J'
? (c < 'B'
? c == '$'
: c <= 'E')
: (c <= 'L' || c == 'O'))
: (c <= 'T' || (c < 'r'
? (c < 'b'
? (c >= 'X' && c <= 'Z')
: c <= 'o')
: (c <= 't' || (c >= 'x' && c <= 'z')))));
}
static inline bool aux_sym_format_directive_type_token11_character_set_2(int32_t c) {
return (c < 'R'
? (c < 'G'
? (c < 'B'
? c == '$'
: c <= 'E')
: (c <= 'L' || c == 'O'))
: (c <= 'T' || (c < 'r'
? (c < 'b'
? (c >= 'V' && c <= 'Z')
: c <= 'o')
: (c <= 't' || (c >= 'x' && c <= 'z')))));
}
static inline bool aux_sym_format_directive_type_token11_character_set_3(int32_t c) {
return (c < 'R'
? (c < 'G'
? (c < 'B'
? c == '$'
: (c <= 'B' || (c >= 'D' && c <= 'E')))
: (c <= 'H' || (c < 'N'
? (c >= 'J' && c <= 'L')
: c <= 'O')))
: (c <= 'T' || (c < 'j'
? (c < 'b'
? (c >= 'V' && c <= 'Z')
: (c <= 'b' || (c >= 'd' && c <= 'h')))
: (c <= 'B' || (c >= 'D' && c <= 'H')))
: (c <= 'L' || (c < 'R'
? (c >= 'N' && c <= 'O')
: c <= 'T')))
: (c <= 'Z' || (c < 'j'
? (c < 'd'
? c == 'b'
: c <= 'h')
: (c <= 'o' || (c < 'w'
? (c >= 'r' && c <= 't')
: c <= 'z')))));
@ -864,8 +836,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) {
if (('[' <= lookahead && lookahead <= ']')) ADVANCE(68);
if (('{' <= lookahead && lookahead <= '}')) ADVANCE(68);
if (lookahead == '$' ||
('B' <= lookahead && lookahead <= 'E') ||
('G' <= lookahead && lookahead <= 'L') ||
('B' <= lookahead && lookahead <= 'L') ||
lookahead == 'N' ||
lookahead == 'O' ||
('R' <= lookahead && lookahead <= 'T') ||
@ -914,7 +885,14 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) {
if (lookahead == '(' ||
lookahead == ')') ADVANCE(56);
if (('0' <= lookahead && lookahead <= '9')) ADVANCE(27);
if (aux_sym_format_directive_type_token11_character_set_1(lookahead)) ADVANCE(65);
if (lookahead == '$' ||
('B' <= lookahead && lookahead <= 'L') ||
lookahead == 'O' ||
('R' <= lookahead && lookahead <= 'T') ||
('X' <= lookahead && lookahead <= 'Z') ||
('b' <= lookahead && lookahead <= 'o') ||
('r' <= lookahead && lookahead <= 't') ||
('x' <= lookahead && lookahead <= 'z')) ADVANCE(65);
END_STATE();
case 2:
if (lookahead == '\n') ADVANCE(49);
@ -953,7 +931,14 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) {
if (lookahead == '(' ||
lookahead == ')') ADVANCE(56);
if (('0' <= lookahead && lookahead <= '9')) ADVANCE(27);
if (aux_sym_format_directive_type_token11_character_set_2(lookahead)) ADVANCE(65);
if (lookahead == '$' ||
('B' <= lookahead && lookahead <= 'L') ||
lookahead == 'O' ||
('R' <= lookahead && lookahead <= 'T') ||
('V' <= lookahead && lookahead <= 'Z') ||
('b' <= lookahead && lookahead <= 'o') ||
('r' <= lookahead && lookahead <= 't') ||
('x' <= lookahead && lookahead <= 'z')) ADVANCE(65);
END_STATE();
case 3:
if (lookahead == '"') ADVANCE(67);
@ -983,7 +968,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) {
if (lookahead == '~') ADVANCE(43);
if (('+' <= lookahead && lookahead <= '-')) ADVANCE(7);
if (('0' <= lookahead && lookahead <= '9')) ADVANCE(27);
if (aux_sym_format_directive_type_token11_character_set_3(lookahead)) ADVANCE(65);
if (aux_sym_format_directive_type_token11_character_set_1(lookahead)) ADVANCE(65);
END_STATE();
case 7:
if (lookahead == '#') ADVANCE(9);
@ -3147,7 +3132,9 @@ static const TSParseActionEntry ts_parse_actions[] = {
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#ifdef TREE_SITTER_HIDE_SYMBOLS
#define TS_PUBLIC
#elif defined(_WIN32)
#define TS_PUBLIC __declspec(dllexport)
#else
#define TS_PUBLIC __attribute__((visibility("default")))

View file

@ -66,9 +66,12 @@ extern "C" {
/// Increase the array's size by `count` elements.
/// New elements are zero-initialized.
#define array_grow_by(self, count) \
(_array__grow((Array *)(self), count, array_elem_size(self)), \
memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)), \
(self)->size += (count))
do { \
if ((count) == 0) break; \
_array__grow((Array *)(self), count, array_elem_size(self)); \
memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \
(self)->size += (count); \
} while (0)
/// Append all elements from one array to the end of another.
#define array_push_all(self, other) \