The tags prevent the structs from accidentally becoming compatible
types.
While here, remove a few typedefs for structs that are single-purpose,
since there is no point in abstracting from the actual representation of
these types.
The variable name "str" did not make it clear enough that the pointer is
constantly moving, to parse the given string. The name "p" expresses
this more clearly.
Accessing the fields List.first, List.last, ListNode.prev, ListNode.next
and ListNode.datum in read-only mode should be more efficient than a
whole function call.
All modifications to the lists or their nodes must still happen via
function calls.
This change reduces the code size, makes the code faster to execute and
allows Lst_ForEach to be written inline without the visual overhead of
function calls.
Since the callback function returns a terminating condition, this is not
really a foreach loop.
Many of the calls to Lst_ForEachUntil don't make use of the terminating
condition, and several don't modify the list structurally, which means
they don't need this complicated implementation.
In a follow-up commit, Lst_ForEach will be added back with a much
simpler implementation that iterates over the list naively, without a
terminating condition and without taking the iteration state from
Lst_Open/Lst_Next/Lst_Close into account. The migration to this simpler
implementation will be done step by step since each callback function
needs to be examined closely.
It was the last remaining use of that function outside of lst.c.
While here, clean up the code of add_wait_dep by removing unreachable
code (the GNode lists never contain NULL, only the GNode.commands lists
do that).
Now that the tests work as intended, the debug information is no longer
necessary. It was only intended to track down the cause of the
unexpected behavior.
Previously, the ::= modifier had returned an error value, which caused
the variable expression to be preserved. This behavior was not useful
in this case; it had only been intended to be used for undefined
variables.
To fix it, distinguish between parse errors, undefined variables and
regular empty strings.
I had expected that using the ::+= modifier instead of the ::= modifier
would work, since the assignment modifier for COUNTER no longer contains
a reference to itself. But instead of ending up at 4, the counter even
goes up to 6.
There had been two separate global variables for the .END node, and in
parallel mode, only the one in jobs.c was initialized.
The code in JobRun heads over to Compat_Make without calling Compat_Run
first, which left the variable ENDNode uninitialized.
This way, it can access the ApplyModifierState, which will be used in a
follow-up commit to reduce the code duplication around the error
handling for missing delimiters.
These two flags have nothing to do with a variable. They are only used
while evaluating a variable expression.
While here, rename the flags and make their documentation more precise.
The word "path" is commonly used either as an abbreviation for pathname
(a string consisting of several directory or file names) or as an
abbreviation for search path (a list of directory names used for
searching files), but not for a single directory.
These typedefs are only intended to help human readers, they do not
provide any type-safety. They also make the pointers explicit, which
had been hidden before by the typedef for Lst and LstNode. Typing a few
'*' is less work than finding out which of the many types are pointers
and which aren't.
In meta.c, the variable "ln" served two completely different purposes,
which have been split again. Register allocation is the job of the
compiler, not of the human source code reader.
Having a pure bitset was wrong.
Instead, there are several alternatives (parse error, eval error, undef
error), and each of them can either have an error message printed (good)
or not (bad). In addition, there are VPE_OK for successful expression
evaluation and VPE_UNKNOWN (only used during migration to the correct
error handling scheme).