formatter: more improvements and support for things like lambdas

This commit is contained in:
Tyler Wilding 2024-05-18 21:50:34 -04:00
parent 588b27cbcf
commit 0f40f33dfd
No known key found for this signature in database
GPG key ID: BF7B068C2FEFD7EF
9 changed files with 302 additions and 63 deletions

View file

@ -340,6 +340,13 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
form_lines.at(form_lines.size() - 1) += fmt::format(" {}", line); form_lines.at(form_lines.size() - 1) += fmt::format(" {}", line);
} }
i++; 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);
}
} }
if (!curr_node.metadata.is_top_level && next_ref.metadata.node_type == "comment" && if (!curr_node.metadata.is_top_level && next_ref.metadata.node_type == "comment" &&
(i + 1) == (int)curr_node.refs.size()) { (i + 1) == (int)curr_node.refs.size()) {

View file

@ -133,12 +133,24 @@ bool is_element_second_in_constant_pair_new(const FormatterTreeNode& prev_node,
curr_node.node_prefix.value() == "'") { curr_node.node_prefix.value() == "'") {
return true; return true;
} }
// Constant forms special cases (ie. meters) if (!curr_node.refs.empty()) {
if (!curr_node.refs.empty() && // Constant forms special cases (ie. meters)
constant_type_forms.find(curr_node.refs.at(0).token_str()) != if (constant_type_forms.find(curr_node.refs.at(0).token_str()) != constant_type_forms.end()) {
constant_type_forms.end()) { return true;
return true; }
// If they are just a list of symbol names (enum or simple method call)
bool all_symbols = true;
for (const auto& ref : curr_node.refs) {
if (ref.metadata.node_type != "sym_name") {
all_symbols = false;
break;
}
}
if (all_symbols) {
return true;
}
} }
} }
return false; return false;
} }

View file

@ -1,5 +1,7 @@
#include "rule_config.h" #include "rule_config.h"
#include "common/util/string_util.h"
namespace formatter_rules { namespace formatter_rules {
namespace config { namespace config {
@ -27,6 +29,12 @@ static FormFormattingConfig new_inlineable_flow_rule(int start_index,
[start_index](const std::vector<std::string>& curr_lines) { [start_index](const std::vector<std::string>& curr_lines) {
int total_width = 0; int total_width = 0;
for (const auto& line : curr_lines) { for (const auto& line : curr_lines) {
// Check for comments
// TODO - this shows how this isn't really the best strategy but it holds up
if (str_util::contains(line, ";")) {
// Can't inline, there's a comment!
return start_index;
}
total_width += line.length(); total_width += line.length();
// an empty line implies a new-line was forced, this is bleeding implementation // an empty line implies a new-line was forced, this is bleeding implementation
// details, but fine for now // details, but fine for now
@ -49,10 +57,8 @@ static FormFormattingConfig new_defstate_rule(int start_index, bool has_constant
.inline_until_index = .inline_until_index =
[start_index](const std::vector<std::string>& /*curr_lines*/) { return start_index; }, [start_index](const std::vector<std::string>& /*curr_lines*/) { return start_index; },
.has_constant_pairs = has_constant_pairs}; .has_constant_pairs = has_constant_pairs};
// TODO - might be nice to have a function that returns a config based on a given index, instead std::vector<int> state_handler_indexes = {4, 6, 8, 10,
// of hardcoding them! 12, 14}; // NOTE - not all of these have to be defined
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) { for (const auto& index : state_handler_indexes) {
auto temp_config = std::make_shared<FormFormattingConfig>(); auto temp_config = std::make_shared<FormFormattingConfig>();
temp_config->config_set = true; temp_config->config_set = true;
@ -68,21 +74,46 @@ static FormFormattingConfig new_defstate_rule(int start_index, bool has_constant
} }
static FormFormattingConfig new_defmethod_rule(int start_index, bool has_constant_pairs = false) { static FormFormattingConfig new_defmethod_rule(int start_index, bool has_constant_pairs = false) {
return {.config_set = true, // TODO - might be nice to have a function that returns a config based on a given index, instead
.hang_forms = false, // of hardcoding them!
.inline_until_index = // Right now this only works for non-`new` methods (else we may bleed into the body of a normal
[start_index](const std::vector<std::string>& curr_lines) { // method)
if (curr_lines.size() >= 2 && curr_lines.at(1) == "new") { auto arg_list_config = std::make_shared<FormFormattingConfig>();
// defmethod was changed to omit the type name for everything except the `new` arg_list_config->force_inline = true;
// method, so special case. arg_list_config->hang_forms = false;
return start_index + 1; FormFormattingConfig cfg = {.config_set = true,
} .hang_forms = false,
return start_index; .inline_until_index =
}, [start_index](const std::vector<std::string>& curr_lines) {
.has_constant_pairs = has_constant_pairs}; 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};
cfg.index_configs.emplace(2, arg_list_config);
return cfg;
} }
static FormFormattingConfig new_defnum_rule() { static FormFormattingConfig new_lambda_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) {
if (curr_lines.size() >= 2 && curr_lines.at(1) == ":behavior") {
// defmethod was changed to omit the type name for everything
// except the `new` method, so special case.
return start_index + 2;
}
return start_index;
},
.has_constant_pairs = has_constant_pairs};
return cfg;
}
static FormFormattingConfig new_defenum_rule() {
auto temp_list_config = std::make_shared<FormFormattingConfig>(); auto temp_list_config = std::make_shared<FormFormattingConfig>();
temp_list_config->force_inline = true; temp_list_config->force_inline = true;
temp_list_config->hang_forms = false; temp_list_config->hang_forms = false;
@ -179,8 +210,9 @@ const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config
{"in-package", new_top_level_inline_form(true)}, {"in-package", new_top_level_inline_form(true)},
{"bundles", new_top_level_inline_form(true)}, {"bundles", new_top_level_inline_form(true)},
{"require", new_top_level_inline_form(true)}, {"require", new_top_level_inline_form(true)},
{"defenum", new_defnum_rule()}, {"defenum", new_defenum_rule()},
{"defmethod", new_defmethod_rule(3)}, {"defmethod", new_defmethod_rule(3)},
{"lambda", new_lambda_rule(2)},
{"deftype", new_deftype_rule(3, {3, 4, 5, 6})}, {"deftype", new_deftype_rule(3, {3, 4, 5, 6})},
{"defun", new_flow_rule(3)}, {"defun", new_flow_rule(3)},
{"defun-debug", new_flow_rule(3)}, {"defun-debug", new_flow_rule(3)},
@ -188,8 +220,12 @@ const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config
{"if", new_inlineable_flow_rule(2)}, {"if", new_inlineable_flow_rule(2)},
{"#if", new_inlineable_flow_rule(2)}, {"#if", new_inlineable_flow_rule(2)},
{"define", new_permissive_flow_rule()}, {"define", new_permissive_flow_rule()},
{"defmethod-mips2c", new_permissive_flow_rule()},
{"define-extern", new_permissive_flow_rule()}, {"define-extern", new_permissive_flow_rule()},
{"defmacro", new_flow_rule(3)}, {"defmacro", new_flow_rule(3)},
{"defskelgroup", new_flow_rule(2, true)},
{"defpartgroup", new_flow_rule(2, true)},
{"defpart", new_flow_rule(2, true)},
{"defstate", new_defstate_rule(3, true)}, {"defstate", new_defstate_rule(3, true)},
{"behavior", new_flow_rule(2)}, {"behavior", new_flow_rule(2)},
{"dotimes", new_flow_rule(2)}, {"dotimes", new_flow_rule(2)},

View file

@ -10,46 +10,56 @@
# f.write(json.dumps(json_data, indent=2)) # f.write(json.dumps(json_data, indent=2))
import json import json
import math
import subprocess import subprocess
import sys from colorama import just_fix_windows_console, Fore, Back, Style
apply_status = None just_fix_windows_console()
if len(sys.argv) > 1:
apply_status = sys.argv[1]
with open("./scripts/gsrc/format-jak1.json", "r") as f: def format_the_file(apply_status):
formatting_progress = json.load(f) with open("./scripts/gsrc/format-jak1.json", "r") as f:
formatting_progress = json.load(f)
# find the next file # find the next file
curr_file = None curr_file = None
curr_file_index = 0 go_to_next = False
go_to_next = False open_file_in_vscode = False
open_file_in_vscode = False if apply_status == "next":
if apply_status == "next": go_to_next = True
go_to_next = True open_file_in_vscode = True
open_file_in_vscode = True
for index, file in enumerate(formatting_progress): for index, file in enumerate(formatting_progress):
if file['status'] == 'not-formatted': if file['status'] == 'not-formatted':
if go_to_next: if go_to_next:
print(f"Marking {file['path']} as formatted") print(f"Marking {file['path']} as formatted")
formatting_progress[index]['status'] = 'formatted' print(f"{Fore.GREEN} {(index / len(formatting_progress)) * 100:.3f}% {Fore.RESET} Completed")
go_to_next = False formatting_progress[index]['status'] = 'formatted'
go_to_next = False
else:
curr_file = file['path']
if open_file_in_vscode:
subprocess.run(["C:\\Users\\xtvas\\AppData\\Local\\Programs\\Microsoft VS Code\\bin\\code.cmd", file['path']])
break
# format it
print(f"Formatting {curr_file}")
subprocess.run(["./out/build/Debug/bin/formatter", "--write", "--file", curr_file])
# save status
if apply_status is not None and (apply_status == "skip" or apply_status == "next"):
# TODO - add skip support back if i ever want to use it
with open("./scripts/gsrc/format-jak1.json", "w") as f:
f.write(json.dumps(formatting_progress, indent=2))
subprocess.run(["git", "diff", "--shortstat", "origin/master"])
def main():
while True:
user_input = input(Fore.CYAN + "Type 'n' to proceed to the next file or just hit enter to re-format the current file: " + Fore.RESET)
if user_input == 'n':
format_the_file("next")
else: else:
curr_file = file['path'] format_the_file(None)
curr_file_index = index
if open_file_in_vscode:
subprocess.run(["C:\\Users\\xtvas\\AppData\\Local\\Programs\\Microsoft VS Code\\bin\\code.cmd", file['path']])
break
# format it if __name__ == "__main__":
print(f"Formatting {curr_file}") main()
subprocess.run(["./out/build/Debug/bin/formatter", "--write", "--file", curr_file])
# save status
if apply_status is not None and (apply_status == "skip" or apply_status == "next"):
# TODO - add skip support back if i ever want to use it
with open("./scripts/gsrc/format-jak1.json", "w") as f:
f.write(json.dumps(formatting_progress, indent=2))
subprocess.run(["git", "diff", "--shortstat", "origin/master"])

View file

@ -74,4 +74,17 @@ Consolidation of if 2
(if (or (not s5-1) (= (-> s5-1 name) 'default)) (if (or (not s5-1) (= (-> s5-1 name) 'default))
(login this) ;; not part of level load, just normal login. (login this) ;; not part of level load, just normal login.
) )
===
Consolidation of if with comment
===
(if (= (-> obj prim-id) arg0) ;; it's us!
(return obj)
)
---
(if (= (-> obj prim-id) arg0) ;; it's us!
(return obj))

View file

@ -181,4 +181,59 @@ Special case forms
:down-move-to-pitch-ratio-in-air 0.5 :down-move-to-pitch-ratio-in-air 0.5
:up-move-to-pitch-on-ground 0.9 :up-move-to-pitch-on-ground 0.9
:down-move-to-pitch-on-ground 0.9 :down-move-to-pitch-on-ground 0.9
:pitch-off-blend 0.5)) :pitch-off-blend 0.5))
===
Enums
===
(define *warp-jump-mods*
(new 'static
'surface
:name 'jump
:turnv 273066.66
:turnvv 1820444.5
:tiltv 32768.0
:tiltvv 131072.0
:transv-max 65536.0
:target-speed 65536.0
:slip-factor 1.0
:slide-factor 1.0
:slope-up-factor 1.0
:slope-down-factor 1.0
:slope-slip-angle 1.0
:impact-fric 1.0
:bend-factor 1.0
:bend-speed 1.0
:alignv 1.0
:slope-up-traction 1.0
:align-speed 1.0
:mode 'air
:flags
(surface-flags always-rotate-toward-transv)))
---
(define *warp-jump-mods*
(new 'static
'surface
:name 'jump
:turnv 273066.66
:turnvv 1820444.5
:tiltv 32768.0
:tiltvv 131072.0
:transv-max 65536.0
:target-speed 65536.0
:slip-factor 1.0
:slide-factor 1.0
:slope-up-factor 1.0
:slope-down-factor 1.0
:slope-slip-angle 1.0
:impact-fric 1.0
:bend-factor 1.0
:bend-speed 1.0
:alignv 1.0
:slope-up-traction 1.0
:align-speed 1.0
:mode 'air
:flags (surface-flags always-rotate-toward-transv)))

View file

@ -96,4 +96,24 @@ Methods - new
(defmethod new align-control ((allocation symbol) (type-to-make type) (proc process-drawable)) (defmethod new align-control ((allocation symbol) (type-to-make type) (proc process-drawable))
"Create a new align-control." "Create a new align-control."
(+ 1 1)) (+ 1 1))
===
Methods - long arg list
===
(defmethod fill-and-probe-using-line-sphere ((obj collide-cache) (arg0 vector)
(arg1 vector)
(arg2 float)
(arg3 collide-kind)
(arg4 process)
(arg5 collide-tri-result)
(arg6 pat-surface))
(fill-using-line-sphere obj arg0 arg1 arg2 arg3 (the-as process-drawable arg4) arg6)
(probe-using-line-sphere obj arg0 arg1 arg2 arg3 arg5 arg6))
---
(defmethod fill-and-probe-using-line-sphere ((obj collide-cache) (arg0 vector) (arg1 vector) (arg2 float) (arg3 collide-kind) (arg4 process) (arg5 collide-tri-result) (arg6 pat-surface))
(fill-using-line-sphere obj arg0 arg1 arg2 arg3 (the-as process-drawable arg4) arg6)
(probe-using-line-sphere obj arg0 arg1 arg2 arg3 arg5 arg6))

View file

@ -147,4 +147,42 @@ Long array creation
))) )))
(dotimes (i 16) (dotimes (i 16)
(set! (-> (scratchpad-object terrain-context) work foreground joint-work frm-jmp-table i) (set! (-> (scratchpad-object terrain-context) work foreground joint-work frm-jmp-table i)
(the-as (function none) (-> arr i))))) (the-as (function none) (-> arr i)))))
===
!Nested function call
===
(set! (-> this attack-event)
(the-as symbol ((the-as
(function res-lump symbol symbol float structure (pointer res-tag) pointer object)
(method-of-type res-lump get-property-struct)
)
(-> this entity)
'attack-event
'interp
-1000000000.0
'dark-eco-pool
(the-as (pointer res-tag) #f)
*res-static-buf*
)
)
)
---
(set! (-> this attack-event)
(the-as symbol ((the-as
(function res-lump symbol symbol float structure (pointer res-tag) pointer object)
(method-of-type res-lump get-property-struct)
)
(-> this entity)
'attack-event
'interp
-1000000000.0
'dark-eco-pool
(the-as (pointer res-tag) #f)
*res-static-buf*
)
)
)

View file

@ -0,0 +1,48 @@
===
With behavior tag
===
(lambda :behavior
target
()
(println "something"))
---
(lambda :behavior target ()
(println "something"))
===
Without behavior tag
===
(lambda ()
(println "something"))
---
(lambda ()
(println "something"))
===
Too long
===
(lambda ((arg0 part-tracker))
(let ((s5-0 (handle->process (-> arg0 userdata)))) (when s5-0 (let* ((v1-4 (handle->process (-> (the-as eco-collectable s5-0) pickup-handle))) (a2-0 (cond ((not v1-4) (-> arg0 root trans)) ((= (-> v1-4 type) target) (vector<-cspace! (new 'stack-no-clear 'vector) (-> (the-as target v1-4) node-list data 5))) (else (-> (the-as target v1-4) control trans))))) (vector-lerp! (-> arg0 root trans) (-> arg0 offset) a2-0 (/ (the float (- (current-time) (-> arg0 start-time))) (the float (-> (the-as eco-collectable s5-0) collect-effect-time))))))))
---
(lambda ((arg0 part-tracker))
(let ((s5-0 (handle->process (-> arg0 userdata))))
(when s5-0
(let* ((v1-4 (handle->process (-> (the-as eco-collectable s5-0) pickup-handle)))
(a2-0 (cond
((not v1-4) (-> arg0 root trans))
((= (-> v1-4 type) target) (vector<-cspace! (new 'stack-no-clear 'vector) (-> (the-as target v1-4) node-list data 5)))
(else (-> (the-as target v1-4) control trans)))))
(vector-lerp! (-> arg0 root trans)
(-> arg0 offset)
a2-0
(/ (the float (- (current-time) (-> arg0 start-time)))
(the float (-> (the-as eco-collectable s5-0) collect-effect-time))))))))