You signed in with another tab or window.Reload to refresh your session.You signed out in another tab or window.Reload to refresh your session.You switched accounts on another tab or window.Reload to refresh your session.Dismiss alert
TODO: Proper about section. Currently the README is mainly used for information storage for my future usage.
Note for future: Currently there is no way for builtins and operators to efficiently call block arguments (call,loop,if). The current solution is to make them exceptions called directly fromNight, instead of defining them inbuiltin/defs.rs like the other operators and builtin symbols. It's not something vitally important to change, just something that is slightly clunky in my opinion. This most likely won't be changed however, as it would require a major overhaul to some parts of the code.
Lexer
Basic interpreter
Operator structure
Builtin structure
Const symbol definitions
Blocks
Symbol definitions
Register definitions
Mutable scoped registers
Guard statements
Fully decide how arrays will work
Implement basic array support
Implement array support builtins + ops
Implement operators
Implement basic builtins (poc)
Choose + Implement more useful builtins
Basic function composition boilerplate
Implement basic function composition builtins + ops
Considered features
(Implemented) Private/Public Guard Distinctions
For guards, maybe add a way to stop arbitrary blocks executed with thecall op from using certain guarded values?Something like:
(:private1:private2 |:public){ ...}
This also gives more syntactic use for|, which currently is only used for const defs.If I did do this, I'd have to slightly redesign how guarded registers are stored. Currently they it's just aHashSet<String>, which wouldn't properly distinguish between the two types (and also the level they exist in). Maybe add a new instr marker placed aftercall ops pre-execution as a marker? Then have a separateHashSet for inaccessible registers. Probably the simplest solution.
Implemented in a slightly different manner that allows for more choices.
(:private1:public) {-- ... do things:private1|?-- ... do more things}
This will "block" the register$private1 from being accessed in whatever is called by thecall op. Once arrays are implemented, something like
[:private1:private2]|?
will work too.
Dropdef anddefr/!
Definition of symbols and registers could be based on if it is undefined, i.e.,
->dip(:top) : $top:top | ? $top
will work, as$top starts undefined, meaning night will automatically assign the value to the register instead. In this version,pop is unecessary after the definition. Similarly,
(:top){ : $top:top | ? $top}dip
would function as an alternate definition syntax. In this version,def anddefr would no longer exist.
The drawbacks include the fact that you can no longer dynamically define symbols from strings (which was possible viadef anddefr), and that typos will be much harder to notice when it comes to symbols. However, this would definitely clean up some definitions in the code.
For instance, thefor defintion, as can be seen below, would look much cleaner. Additionally, the definition of registers will be much more apparent at first glance. However, since the pattern:reg ! ; has become$reg,:reg ! must become$reg $reg, which looks clunky and is not ideal.
Below is a code snippet wheredefr/! has been ommitted.:reg ! ; has become$reg ;.
You can compare the definition ofdip with the prior example in this feature idea, where register definition implicitly pops for comparison. If this feature is implemented, it remains to be seen which variant will be the standard. Most likely, despite the slight unintuitiveness in my opinion, it remains superior to the alternative$a $a pattern you would need for themults2 definition, where register definition does not preserve on the stack.
There also exists a possibility this change will exist solely for register definitions, and there be no alternative symbol definition besides-> syntactically on implementation of this idea, which may help dodge the issue mentioned above wherein typos can be very difficult to track down.
Finally, this change would warrant a look atundef (and also possiblyundefr) to see how that will be handled.
Implemented as follows:
->dip(:top) ::top !;:top | ? $top
is now
->dip(top) : $top!:top | ? $top
This makes it apparent when a register is being defined vs. pushed while also cleaning up messiness. As of now,def is staying, as isundefr andundef, all of which take string arguments. At some pointdef will probably be changed, although there isn't really a need for inline variable definition as registers exist.
However, allowing for mutable scoped registers at some point will most likely be important.
# Some rules:[a-zA-Z][_0-9a-zA-Z]* ⇒ Symbol (literal one-word string)\$[0-9a-zA-Z][_0-9a-zA-Z]* ⇒ Temp variable[a-zA-Z][_0-9a-zA-Z]* ⇒ Variable name'{anything} ⇒ Literal character\n ⇒ Literal newline is a token, other whitespace ignored/unimportant# Some builtins more preprocessor-directives-> x y ⇒ {y} :x def-> x | y ⇒ y :x def:x | <instr> ⇒ Block register x from being access for the duration of the next instr[:x :y] | <instr> ⇒ Block register[s] x & y from being accessed for the duration of the next instr-> x (word list) { y } ⇒ Specify temp words to unassign after. Acts as guard on registers.-- ⇒ comment