Over this past weekend, I realized that there’s room for a few small alterations to the language that will greatly increase its flexibility in non-standard usage scenarios, without needlessly cluttering the grammar.
Local identifiers will be split into two unified types, extending the
functioncall parameter logic: any generic variable assignment, like
x = 5;, will be assumed to target a context-specific scope (
function), with the values being dereferenced when the context ends. An assignment may explicitly target the global namespace by prefixing it with the keyword
global, as in
global x = 5;. When unqualified references are provided, like
g += x;, the resolution order will be to first consult the local variable-set, then the global variable-set, if noting was found locally; the local variable-set may be bypassed by qualifying either identifier with the
global keyword, like
g += (global x); (note that the parentheses are just for legibility’s sake (they’re optional), though this is legal only for expressions, not for assignment-targets). For the precise, there’s also a
local qualifier, which does the opposite, improving clarity in cases where variable names are reused and allowing the global table to be ignored when resolving values, which may be good for quick maintenance jobs. Details: r16, r17.
Local sequences will be extended with a series of object-like extensions, using the
functioncall syntax (so no grammar changes are necessary):
.push(value)adds the value to the end of the sequence
.push_front(value)adds the value to the start of the sequence
.insert(int, value)inserts the given value at the specified index, pushing all other values back; bounds-exceptions will cause the sequence to grow the necessary number of
.pop():valueremoves and returns the value to the end of the sequence, granting stack-like functionality
.pop_front():valueremoves and returns the value at the start of the sequence, granting queue-like functionality
.remove(int):valueremoves and returns the value at the specified index, granting list-like functionality; bounds-exceptions will return
.count():intprovides the number of items in the sequence
.get(int):valuegets the value at the 0-based index, providing array-like functionality; bounds-exceptions will return
.set(int, value)sets the value at the 0-based index, providing array-like functionality; bounds-exceptions will cause the sequence to grow the necessary number of
.find(value):intfinds the first occurrence of the given value, testing for equivalence, but using reference (implementation-dependent) as a fallback, for complex objects;
Noneis returned if no match is found
.rfind(value):intthe same thing as
.find(value):int, but it returns the last instance
.union(sequence)adds all values in the given sequence to the working sequence, returning the result as a new sequence
.copy()performs a shallow copy of the sequence, returning a new sequence; this is preferred over performing a union with an empty sequence for clarity’s sake
The role of the parser will be altered slightly, since set-based node/function operations can be done in the PLY layer quite easily, removing a step that doesn’t have any specific need to be handled externally, thereby increasing clarity and removing a point of debugging tedium for maintenance programmers. Details: r15.
Each operation will be able to set an ‘error’ flag-pair,
__error_msg:string, if something goes wrong during execution. This should be cleaner than relying on a bunch of arbitrary variable-assignment patterns, though those patterns will still need to be defined, since programmers will need to know what to expect. Details: r13, r14.