Replies: 2 comments
-
I'm not very content with the syntax for accessing main variables (ie. variables in the main program body, outside of user defined functions) from functions. I've implemented the
I'm considering the possibility to use uppercase identifiers for main variables. Upper-case identifiers would always resolve to main variables, while mixed-case and lowercase variables would always be local -- it wouldn't be possible to access a lower/mixed-case main variable from a function. There are several benefits: uppercase identifiers would stand out in the program, reasoning about variable scope would be easier, and
What looks better to you, @francois? (It just dawned on me that perhaps you initially planned to only share the global. ie. memory-backed variables between functions and main program body - am I right?) |
Beta Was this translation helpful? Give feedback.
-
Implemented in the March 2023 update, closing. |
Beta Was this translation helpful? Give feedback.
-
I’d like to improve on user defined functions in these ways:
Variable scope
Currently we have two variable scopes: “global” variables, marked with the
$
prefix and stored in memory cells/banks, and other variables, without a specific prefix and mapped directly to processor variables (let’s call these “main variables”). Variables in user defined functions, including function parameters, are actually main variables at the moment. I’d like to make these variables local by default.We still need to make main variables accessible to functions in some way. I’d like to avoid using a prefix to mark local variables – local variables should be the default inside functions. So I plan to use
main.variable
syntax inside functions to access a main variable. Unfortunately,main
will become a keyword this way. Other possibilities:global.variable
: this might also be suitable, but we use the term for memory-based variables already. Also,global
would become a keyword.@@variable
: we can’t use a single@
, as this is reserved to some Mindustry constants and variables.@@
also denotes a class variable in Ruby, which is not entirely out of place for this use – if we consider the entire program as a single class.Local variables will be mapped to processor variables by using a
__fnX
prefix, so variablelocal
becomes, say,__fn0local
. The index after__fn
will be increased for each processed user function. This ensures isolation of variables between different functions.Stack management
Currently, function parameters and return values are passed using the stack and stack pointer is also stored in the stack memory.
I plan to store stack pointer in a special variable
__sp
. I also plan to pass parameters, return values and return address using__fn
or__tmp
processor variables instead of the stack. While parameters are passed on many existing processors on stack, the Mindustry processor lacks instructions to manage the stack and accessing variables on stack is cumbersome. Instead, local variables, parameters and the return address will be pushed on stack before function calls and popped afterwards. This also allows to pass non-numerical values to functions, although they’ll get destroyed once another function call is made. (I haven't figured out a way to resolve this issue.)Calling mechanism
Several different mechanisms to realize function calls will be supported:
inline def
. These functions are embedded at each place they’re used. For every emplacement a new__fnX
prefix will be allocated. Local variables won’t be saved when calling other functions, as inline function must not be called recursively.To identify recursive functions, a directed graph of function calls will be constructed (we’ll traverse the node tree and only process function calls and function declarations to create the graph). Functions that lie on a cycle are recursive, functions that don’t lie on a cycle are stackless.
Parts of the function call graph not accessible from main program body will be pruned; these functions won’t be compiled (currently inaccessible code eliminator optimizes away unused functions, but is unable to detect an unused function which calls itself).
If there are no recursive functions, we won’t require a stack to be allocated. If a function declared as inline is found out to be recursive, a compile error occurs.
Possible optimizations and validations
To assist in function optimizations, I envision creating virtual instructions
call
,return
,push
andpop
. These would allow the optimizer to understand function calls and their structure. They would be replaced by real instructions before the program gets printed, similar to resolving jump labels.a
andb
are Boolean values might allow expressing a conditiona and not b
asa > b
.)Other changes
return
keyword will be added.return value
sets the value of the function, justreturn
sets it to null.Beta Was this translation helpful? Give feedback.
All reactions