mirror of
https://github.com/open-goal/jak-project
synced 2026-08-21 23:00:45 -04:00
Dependency graph work - Part 1 - Preliminary work (#3505)
Relates to #1353 This adds no new functionality or overhead to the compiler, yet. This is the preliminary work that has: - added code to the compiler in several spots to flag when something is used without being properly required/imported/whatever (disabled by default) - that was used to generate project wide file dependencies (some circulars were manually fixed) - then that graph underwent a transitive reduction and the result was written to all `jak1` source files. The next step will be making this actually produce and use a dependency graph. Some of the reasons why I'm working on this: - eliminates more `game.gp` boilerplate. This includes the `.gd` files to some extent (`*-ag` files and `tpage` files will still need to be handled) this is the point of the new `bundles` form. This should make it even easier to add a new file into the source tree. - a build order that is actually informed from something real and compiler warnings that tell you when you are using something that won't be available at build time. - narrows the search space for doing LSP actions -- like searching for references. Since it would be way too much work to store in the compiler every location where every symbol/function/etc is used, I have to do ad-hoc searches. By having a dependency graph i can significantly reduce that search space. - opens the doors for common shared code with a legitimate pattern. Right now jak 2 shares code from the jak 1 folder. This is basically a hack -- but by having an explicit require syntax, it would be possible to reference arbitrary file paths, such as a `common` folder. Some stats: - Jak 1 has about 2500 edges between files, including transitives - With transitives reduced at the source code level, each file seems to have a modest amount of explicit requirements. Known issues: - Tracking the location for where `defmacro`s and virtual state definitions were defined (and therefore the file) is still problematic. Because those forms are in a macro environment, the reader does not track them. I'm wondering if a workaround could be to search the reader's text_db by not just the `goos::Object` but by the text position. But for the purposes of finishing this work, I just statically analyzed and searched the code with throwaway python code.
This commit is contained in:
+7
-4
@@ -422,11 +422,14 @@
|
||||
&key (exit *no-state*)
|
||||
&key (code *no-state*)
|
||||
&key (post *no-state*)
|
||||
&rest body
|
||||
)
|
||||
"Define a new state!"
|
||||
|
||||
(with-gensyms (new-state)
|
||||
(let ((defstate-type (first parents)))
|
||||
(let ((defstate-type (first parents))
|
||||
(docstring ""))
|
||||
(when (and (> (length body) 1) (string? (first body)))
|
||||
(set! docstring (first body)))
|
||||
(when (not (null? *defstate-type-stack*))
|
||||
(fmt #t "*defstate-type-stack* leaked! An error probably happened in a previous defstate. stack is: {}"
|
||||
*defstate-type-stack*)
|
||||
@@ -489,8 +492,8 @@
|
||||
;; This way it can check the individual function types, make sure they make sense, and create
|
||||
;; a state with the appropriate type.
|
||||
,(if virtual
|
||||
`(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)
|
||||
`(define-state-hook ,state-name ,defstate-type ,new-state :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
||||
`(define-virtual-state-hook ,state-name ,defstate-type ,new-state ,docstring ,(eq? virtual 'override) :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
||||
`(define-state-hook ,state-name ,defstate-type ,new-state ,docstring :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
+7
-3
@@ -478,11 +478,15 @@
|
||||
&key (exit *no-state*)
|
||||
&key (code *no-state*)
|
||||
&key (post *no-state*)
|
||||
&rest body
|
||||
)
|
||||
"Define a new state!"
|
||||
|
||||
(with-gensyms (new-state)
|
||||
(let ((defstate-type (first parents)))
|
||||
(let ((defstate-type (first parents))
|
||||
(docstring ""))
|
||||
(when (and (> (length body) 1) (string? (first body)))
|
||||
(set! docstring (first body)))
|
||||
(when (not (null? *defstate-type-stack*))
|
||||
(fmt #t "*defstate-type-stack* leaked! An error probably happened in a previous defstate. stack is: {}"
|
||||
*defstate-type-stack*)
|
||||
@@ -545,8 +549,8 @@
|
||||
;; This way it can check the individual function types, make sure they make sense, and create
|
||||
;; a state with the appropriate type.
|
||||
,(if virtual
|
||||
`(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)
|
||||
`(define-state-hook ,state-name ,defstate-type ,new-state :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
||||
`(define-virtual-state-hook ,state-name ,defstate-type ,new-state ,docstring ,(eq? virtual 'override) :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
||||
`(define-state-hook ,state-name ,defstate-type ,new-state ,docstring :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
+12
-5
@@ -146,11 +146,15 @@
|
||||
&key (exit *no-state*)
|
||||
&key (code *no-state*)
|
||||
&key (post *no-state*)
|
||||
&rest body
|
||||
)
|
||||
"Define a new state!"
|
||||
|
||||
(with-gensyms (new-state)
|
||||
(let ((defstate-type (first parents)))
|
||||
(let ((defstate-type (first parents))
|
||||
(docstring ""))
|
||||
(when (and (> (length body) 1) (string? (first body)))
|
||||
(set! docstring (first body)))
|
||||
(when (not (null? *defstate-type-stack*))
|
||||
(fmt #t "*defstate-type-stack* leaked! An error probably happened in a previous defstate. stack is: {}"
|
||||
*defstate-type-stack*)
|
||||
@@ -217,23 +221,26 @@
|
||||
`(begin
|
||||
(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)
|
||||
(define-virtual-state-hook ,state-name ,defstate-type ,new-state ,docstring ,(eq? virtual 'override) :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
||||
)
|
||||
)
|
||||
(virtual
|
||||
`(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)
|
||||
`(begin
|
||||
(set! (-> ,new-state parent) #f)
|
||||
(define-virtual-state-hook ,state-name ,defstate-type ,new-state ,docstring ,(eq? virtual 'override) :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
||||
)
|
||||
)
|
||||
(parent
|
||||
`(begin
|
||||
(inherit-state ,new-state (the state ,parent))
|
||||
(set! (-> ,new-state parent) (the state ,parent))
|
||||
(define-state-hook ,state-name ,defstate-type ,new-state :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
||||
(define-state-hook ,state-name ,defstate-type ,new-state ,docstring :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
||||
)
|
||||
)
|
||||
(#t
|
||||
`(begin
|
||||
(set! (-> ,new-state parent) #f)
|
||||
(define-state-hook ,state-name ,defstate-type ,new-state :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
||||
(define-state-hook ,state-name ,defstate-type ,new-state ,docstring :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user