nojanath / SublimeKSP

Fork of Nils Liberg's SublimeKSP plugin. See README for details.
GNU General Public License v3.0
86 stars 18 forks source link

Optimize functions into callable functions #277

Open eitherys opened 1 year ago

eitherys commented 1 year ago

This is a simple one in concept. We do this all the time at ISW manually, and it's a pain that the compiler can't do it automatically, especially considering it automatically does it for taskfuncs anyway.

The idea:

function foo(age, height, weight) -> result
    // function body FOO here
    result := // something returned
end function

should be preprocessor compiled to:

function foo(age, height, weight) -> result
    sksp.foo.args.age := age
    sksp.foo.args.height := height
    sksp.foo.args.weight := weight

    call _foo
    result := sksp.foo.return
end function

function _foo
    declare local age := sksp.foo.args.age 
    declare local height := sksp.foo.args.height
    declare local weight := sksp.foo.args.weight

    // function body FOO here
   sksp.foo.return := // something returned
end function

if and only if the number of lines inside the original foo is greater than roughly the number of arguments + optional return + 1 (for the call).

For example here with 3 args, 1 return, and 1 call, function foo should be at least 5 lines for this optimization to have been worth it, line-count wise, as all invocations of foo now become this static 5-line invocation instead.

This promotes proper code re-use inside Kontakt scripts and reduces massive compile line counts without laborious refactoring of existing codebases or expanding codebases where functions that didn't need line optimization now do after extending the featureset.

JackWilliams-FractureSounds commented 1 year ago

This is a good concept and would definitely optimize the compiler quite a bit! I would love to see this! We do similar things using macros at Fracture Sounds.

If implemented it could also be modified so that if used witin the init CB it would automatically use the interior function (call functions aren't allowed).

However I don't think this should be part of the preprocessor plugins. Personally, I believe that the preprocessor plugins should only refer to methods that don't modify or parse objects (With the exception of raw string modifications like macros or the Automatic Number Incrementer). In this case you're modifying the function object.

The parser is already assigning tokens/symbols for function arguments and return values. I'm sure we can take advantage of this in a much more effective and manageable manner, rather than causing the same code to be parsed multiple times.

I suggest that within ASTModifierFuntionExpander or in a function following would be the best place for this as some of the call function handling happens here after AST construction.

Interested to hear your thoughts 😅

eitherys commented 1 year ago

Hi Jack,

I have no suggestions, as I never really investigated the inner workings of the compiler and don't know where the feature would live natively. If you are able to implement this natively rather than through code substitution then by all means!

mkruselj commented 1 year ago

I assume this would be another option to toggle, since presumably not everyone would necessarily want this behavior by default? Kind of like the new Combine Duplicate Callbacks option?

mkruselj commented 1 month ago

There is a potential issue that can present itself with this feature request. For example, certain built-in KSP functions cannot be executed from functions (most notably, purge_group()). Converting inline functions to callable functions should respect this somehow.

EDIT: Actually, any built-in KSP function that has its execution constrained to a particular callback type would not work with the functions proposed by this FR. This is because Kontakt internally doesn't seem to keep track from which callback a function is being called.