Development Status of Lexer
Notes
- PHP directive test:
-
phptest -test ShowMePhpFeatures
for a summary of the directive tests- see
test/output/PhpFeatures.md
or view in the terminal
- see
-
phptest -test Directives -run Directive.TestName
- add
-stop_loop 50
to stop after the 50th loop - add
-version 0.1
to run without new code. Default in tests isversion 1.0
- see
test/src/Php
to create new directive test - see
test/Tester.php::runDirectiveTests()
- add
-
- Generate Documentation (memory limit):
-
php -d memory_limit=900M "$scrawl_dir/scrawl"
where$scrawl_dir
is the path to Code Scrawl'sbin
directory
-
Bad stuff
-
function abc() use ($var){}
usesmethod_arglist
instructions. It works, it's just does not create the ideal ast structure.
Versions
- v0.2: has simple (poor) bash lexing and old (incomplete, partially broken) php lexing
- v0.3: I don't know (broken, probably?)
- v0.5: I don't know (broken, probably?)
- v0.6: abandoned intermediate version, I BELIEVE (but not 100% sure)
- v0.7: The up and coming version
- v0.8: get rid of old php grammar. Clean up tests. Document. Maybe some additional polish & niceties for running the lexer.
Grammar Changes
- Feb 14, 2022, PHP: reset
$xpn
onop_block_end()
when ast type isblock_body
. SeePhp->testScrawl2()
Jan 21, 2024
I continued trying to get the feature to work where I create a new person if one does not exist, or I GET the existing person if it does exist. So I'm setting the arg 'Person' to a new Ast w/ a name. Then I'm trying to pass that Person to the push_or_get
method of ArrayAst. But for some reason my newly created Person has a 'People' array entry. The People array entry should be on the Program Ast, not the Person. I'm utterly confused. I have no idea what's happening here.
I added some improved debug output for some common errors.
I'm working in NewLanguage, in ArrayAst, and I think in Main.php (the main stdlib object).
And my Person= !some command
does not seem to be working.
I think my language has some issues that need resolving. But man, i just wanna use my language! Not develop it. I want it to be done!
Ugh!
Note: the push_or_get
method of the ArrayAst is entirely busted. It's just doing a debug dump & exit
ing. That's where I'm getting the output that shows the Person ast with a People array entry. So confusing. No idea.
Jan 17, 2024
in the new language test, for the main test, I'm trying to make it so that I get one person named Reed in the 'People' array & that Reed has multiple pets. I started working on it. I'm in the middle of it, and it isn't working. I don't want to code any more. I'm stopping. Sorry for bad notes. I made local var setting work, i think? I think it was broken? idk. And I think it works, but idk
Jan 15, 2024
See src2/README.md
for documentation. It's under development & needs more work!
I added really nice print debug output. I added some minor features. I modified the test program to be able to process multiple entries, like "Reed's Bear"\n"Reed's Cat"\n"Reed's Dog"
I also added start
and stop
to StdLib\Main
, which have to be explicitly called with the current design. I might want a feature to automatically start successful directives (Directives are successful if all of their commands execute and it does not get stopped/halted).
And I added add_directive_layer
to StdLib\Main
... For some reason :directive_name
doesn't create a new layer. I thought it was supposed to? Maybe its a bug. Maybe I misremember.
Currently, the program is creating a new AST for each person, even if it is the same person.
I would like to make it so I can ... get the existing person IF EXISTS, and create a new person if it does NOT exist
So next time:
- Look at the test program & figure out how to re-use the same person ast rather than create a new person ast for every string parsed. But then if I add different people names, it should create new people.
- Consider the start/stop issue & the add_directive_layer command
- Do what you want. ALSO ALSO: See
- Document!
- Program keeps track of: ast stack, directive stack, state stack (haven't used that yet, i don't think)
Jan 14, 2024
I made some tweaks to the test lang used in the NewLanguage::testMain(). These tweaks revealed some bugs, which I fixed. I added some buffer features. I added hooks.
See src2/README.md
for documentation. It's under development & needs more work!
I need:
- Good Debug information reporting
- Currently the info reported is minimal, and error handling is poor
- Good documentation of:
- How to run the parser
- How to write an stdlib
- hooks
- how to write a programming lanuage
- features of built-in programming languages (such as the PHP Lang)
- Features built-in to the StdLib
- Architecture of the language parser itself
- Architecture of the lexer & runner setup
- Major cleanup
- remove all the old code. Hard-commit to this new custom programming language (Maybe keep old code in an 'old' directory bc I'll wanna use old directives & stuff probably)
- Actually, I might keep the old lexer built-in to the new lexer & keep it as Lexer (one) & Lexer2. This will keep backward-compatibility going.
- Create completely new ASTs for Lexer2, instead of piggy-backing off of Lexer1 ASTs
- Type & docblock most things
- remove all the old code. Hard-commit to this new custom programming language (Maybe keep old code in an 'old' directory bc I'll wanna use old directives & stuff probably)
Dec 28, 2023
It WORKS! The NewLanguage::testMain() test WORKS. (verify output visually, test isn't passing yet bc expectations are not setup correctly)
It freaking works though!
Currently some things are a bit messy. I'm interacting directly with properties on the Program a lot ... I think I should switch those property access/modifications to public methods on Program. Basically everything is public too ... So I'll need to switch many properties & methods to being protected ... it just clutters stuff to have things public that aren't actually needed.
I modified the existing ArrayAst instead of creating a new one ... I need to fix this & make a Lexer2\Ast & Lexer2\ArrayAst.
I'm not sure how I feel about things like head.People.push
... currently, it will return the People property (and will first create it as an ArrayAst if the property doesn't exist), then call push() on People. I think I should have an StdLib object that has handlers for things like that ... maybe. In this particular case, People is being created as an Array ast ... Its possible I would need to create it as something else ... hek idk
the stdlib\main::new() method currently only can create ASTs. I think that's mostly inline with my intent, but I'm not sure. It also doesn't allow custom Ast class names .... idk that's a thing to figure out later.
Okay. So. It WORKS!!!! Next up:
- There are "Next Steps" notes from Dec 26, 2023 ... maybe look at those.
- refactor
- Document
- Test a bit more fully
Dec 27, 2023 LATER
The program is beginning to execute. I have some objects added to it, and am starting to make it functional.
The Buffer (literally a copy+paste of Token) is the Lexer's buffer ... But I just added ends_with()
to it... I made an AstHead
object which is specifically an API for Parser Code to call. I think I need to make a Buffer class that is just the API, separate from the Lexer's Buffer. Because the Lexer's Buffer doesn't interact with the Program & shouldn't.
Need to also handle args that are commands ... currently they're just being passed as an array.
Dec 27, 2023
I refactored the lexer quite a bit. It's currently non-functional. See the src2/ dir, where I've added Buffer, Language interface, Parser, Program, and StdLibLanguage.
I still need to figure out how to correctly setup the program & loop over the characters. The Program already has an execute method that probably works.
Dec 26, 2023
Lexer2 is a complete parser of my new programming language. Its not great code, but it works & thats really all I need.
I have not implemented a runner. The Lexer2 generates an AST. It uses a Command object internally while constructing the AST, but the final AST is fully raw-data. All commands have an entry '--is_command--' => true
. This is because arguments can be commands, but also arguments can be arrays, and there needed to be a very clear way to distinguish between the two.
Potential Exploit:
I the parser could be exploited to enter an --is_command--
array entry somewhere it shouldn't be but ... idk. And Idk if I care to fix that exploit. If you were parsing someone else's code (such as if you ran a website that generates documentation for open-source projects), they could possibly insert a command call that could ... mess up the parsing? Idk. It shouldn't have any ability to exit my code runner, bc the code runner is fully dedicated to parsing strings & all the code has to do with parsing strings. There should be no outside system access, unless the StdLib or a Language's StdLib adds system access.
I think this exploit will be a no-fix. Idk. If it becomes a problem, i'll address it.
Next Steps:
- Refactor the ast generation - it should not be inside the lexer. The actual parsing is probably fine (its messy, but idc). It just needs to be separated from the lexer into a parser.
- Create a runner to execute code from the AST form.
- Create a base-class for building new language parsers + a structure for defining language parser code.
- Write unit tests for parsing operations (& maybe for runner stuff too)
- Figure out what 'context' should be in the Program ast.
- Document how it works
- Document how to use the programming language, and its syntax
- Create an StdLib
- implement any missing features
- object.!MethodReturningObject.method
-
namespace:directive.instruction_set
to directly call an instruction set as if it is a function. (idk how this would work, but I think I need it.).
Dec 24, 2023
I want to think about AST structure and writing out ASTs as code. I also want to prototype some of my ideas. I have 45 minutes.
Let me prototype a ... Directive? Function? Lex file (containing Parser Code)?
Let's process a string: "Reed's Bear"
The input includes the double-quotes. In php, the variable would be $input = '"Reed\'s Bear"';
. The code below will receive this input and output an AST.
What's our starting state? What gets called first? State:
-
Buffer(buffer=", next_char=R)
-
RootAst(...dynamic properties)
- properties may be raw values or may be other ASTs, thus the RootAst is also a (potential) tree of ASTs. The Root Ast should describe the input (type=file|http_request|cli_input|string
and possibly a file path, or environment information, idk... whatever your parser wants.) -
AstStack[]
array of ASTs, as a stack. Used for hierarchical building (i.e. Classes have Properties & Methods which have Paramaters, etc) & can be used for state detection (if root ast is a file, then write file. else, echo output. ). -
HeadAst
AstStack[count(AstStack)-1] is the "Head" ast -
StateStack[]
array of State strings used for state detection & hierarchical ... (this might be better as a method or magic property that essentially is an array of AstStack[].type ... or something.
Parse "Reed\'s Bear"
passed in as a "string" (i.e. unknown source) into Ast:
Program: # There is only one RootAst & it is the Program. So there wouldn't really be a Program array key as demonstrated here.
context={$program_information} # to keep track of what language was parsed to create the AST & what parsers were used.
type=Program
input_type=string
input={$the_actual_input}
People: # People is an array
0: # This is an AST Do I declare indexes? I don't like that
type=Person
name=Reed
Pets: # Pets is an array. (How do we distinguish between AST & array if they both use a colon?)
=Bear # Bear is a string. In a more complex example,
# this could be an AST with a name & breed & color & 0-10 cute score (but that's always 10)
The Program AST is created in PHP (in the Interpreter?), so the Code will not need to create the Program AST.
So what does my parser need to do?
- Get the a-z chars leading up to the 's
- Create a People array on the Program
- Create a Person AST, add it to People, then add it to the stack (it becomes the Head Ast)
- Set Person.name=${capturedAtoZcharacters}
- Capture remaining a-z chars
- Create Pets array on Person Ast (Reed)
- Append ${capturedAtoZcharacters} to Person.Pets
The parser works within the context of the Program, which has:
How will THIS program work?
- When " encountered, start parsing & discard buffer
- When 's encountered: capture a-z in buffer left of 's create people array create person ast w/ name=$capture add it to people add it to the stack Discard the buffer
- When " encountered: capture a-z in buffer create pets array add value w/ name=$capture
Let's say this program is parsing "Pet Owner Names", a revolutionary new coding language that ... let's you encode the names of pet's owners.
It will processed in PHP like:
<?php
$input = '"Reed\'s Bear"';
$lexer = new Lexer();
// main_functions are added to the initial function stack.
$lexer->addLanguage(new Language\PetOwnerNames(), $main_functions = ['main']);
// PetOwnerNames will have:
// - stdlib (usually)
// - Parser Code
//
// if you added PHP, Html, and Docblock languages, you'd pass
// an empty array for the Docblock's main functions
// because PHP will listen for docblocks when it is appropriate.
// The lexer also has an API for manipulating its state (i.e. emptying the directive stack)
$Program = $lexer->parse($input, 'string');
$lexer->parse()
will setup the Program ast. & initialize the context:
- buffer (object representing characters in-memory, already-processed, and to-be-processed)
- root (root ast)
- stack (ast stack)
- function stack (previously directive stack)
- head (head of ast stack)
- state (state stack ... maybe)
Some things must be true:
- The program can be started from any state. Such as a json string
{"Reed":"Bear"}
could be parsed from the colon if the state were correctly setup (ast stack, buffer, and root ast).
Notes:
- What if: Getting to the end of the function will change the function's state. Then it's consistent and it's not that some functions do, some functions don't. Then if you don't want the default START functionality, you add stop. Then again, maybe writing
start
would be more explicit ... but I don't want start to be littered everywhere. - I thiiink if a function returns boolean false, then execution stops. So head.is_root, buffer.ends_with, buffer.match ... those all return true/false & can stop execution. buffer.clear will always return true. What about buffer.next? (idk, so maybe it shouldn't be this simple)
main: # Entry function. (or is it a Directive?)
if_unstarted: (is this a function? a branch?)
head.is_root # 'main' only runs if the head ast is the root ast
# May want 'state.is root' to check what the top of the state stack is.
# (basically just the type of the head ast)
buffer.ends_with " # else execution stops
# 1. Marks main as started. SEE Note 1
buffer.clear
:person_name # previously, this was a 'then' statement.
# calling :person_name will:
# 1. create a new layer on the function stack
# - this pauses main until the new layer is popped and
# main is in the top of the function stack.
# 2. add person_name function to top layer of function stack
# 3. On the next loop, the top layer of the function stack will
# be called, so person_name:if_unstarted: should be executed
if_started:
buffer.ends_with "
buffer.clear
stop
# returns to 'unstarted' state, but remains in the stack.
# Unstarted functions are only run if no functions are started in the stack.
# I might change this. It is confusing?.
# What about more states? paused? stopped?
person_name:
if_unstarted:
head.is_root
buffer.padLeft
buffer.match /\s([a-zA-Z]+)\'s/ # regex to match a-zA-Z followed by a space
head.People.push !new Ast\Person:
name=$1
buffer.clear
pop function_stack
:pet_name # a new function stack is created and pet_name is added to it
# How to add function to current stack?
# function_stack.append :pet_name
# or maybe? append function_stack :pet_name
pet_name:
if_unstarted:
head.is Person
buffer.padLeft
buffer.next
buffer.match /\s([a-zA-Z]+)[^a-zA-Z]/
buffer.reset
head.Pets.push $1
pop function_stack # pop is in stdlib
If main
should always be multiple directives, we can do something like:
main:
is: # Instead of this:main being added to the directive stack, php, html, and xml's mains will be
php:main
html:main
xml:main
To call a ... function? inside another ... directive? (like call :main.handle_word or add string.double_quote.started to the directive stack).
# I'm too tired idk right now, I already have something like this in the lexer
# but I don't understand it
(*I need to work on my terminology of ... unstarted/started ... what is a "function" ... do I use "Directive"? ...)
I don't want to use "Class" because ... they're not classes. main:
above is a grouping of sets of instructions. There are two sets of instructions, and which one runs depends on main:
s state.
It might be nice to be able to just name functions ... and heck maybe even properties on the directives. At that point they're just classes. Except minus SO MANY FEATURES.
so idk. sleep.
Nov 23, 2023
Create branch v0.8-programming-language. Idea: Focus the Lexer around an own-built programming language. Currently the language is written as Directives & the stdlib is in php. This library is centered around the Lexer. Instead, this library could be centered around the programming language.
I'm not sure this idea is worth pursuing, but I think it is worth thinking through the idea & maybe prototyping a little bit.
How would I start this?
Currently, the lexer is looping over a character & it runs through the directives and does things based upon the directives.
What I want is an interpreter that manages program state and executes commands. The program would also have built-in functionality to load input & loop over all of the characters. Currently, the Lexer does that ... But I think that's what is confusing. The Lexer is just the part that should be looping over the characters. Instead the Lexer is managing state AND looping over characters.
I may have some mis-placed concerns in the current code, too. Like, I don't think "Token" really represents what a token is. Really, that's my buffer. Lexer has several traits in it ... that's a mess.
What do I want from this? Lexer Pieces:
- Lexer: Accepts input text, sets up the Program, the Interpreter, and returns an AST
- Lexer StdLib: The standard library for the Lexer, which is exposed to the Interpreter so all Parser Code can call it.
- Buffer: Current list of characters in-memory, remaining characters, can move itself forward/backward. (The Lexer adds the Buffer to the program, then the programming language code can interact with the Buffer.)
- Ast Tree: The tree of ASTs, which will always have a single root AST. Referencing the Tree references the root AST. (this may just be a property on the Lexer.)
- Ast Stack: The stack of ASTs.
Grammar Pieces:
- [Language] Parser Code: Code to be processed by the Interpreter. The code i used by the Lexer to parse a string into an AST. This Parser Code is currently known as Directives.
- [Language] Grammar StdLib: The standard Library for a [Language]'s Parser Code. Parser StdLibs can be shared. Lexer StdLib and Parser StdLibs are both exposed to Parser Code.
Programming Language Pieces: A Program is essentially just a set of StdLibs, Code to run, and input that is passed to it. It produces output. A Program is run by the Interpreter
- Program: A Main function; and A set of StdLibs, Code, and State. Main is passed input & produces Output.
- Interpreter: Processes a Program, calling its Main function once initialized. The Program's Main then uses the Interpreter to process Code. Code modifies State by calling the StdLibs.
- StdLib: A set of built-in features.
In theory, the Program/Interpreter/StdLib could be used to create any paradigm of Program. They would all have the same syntax but could have very different use-cases. The Lexer will create a Program which is centered entirely around building ASTs from input text. A general purpose Program could be created that allows a programmer to arbitrarily assign variables, provides a stack, and allows various modifications to variables.
It may make more sense to specify this Program/Interpreter/StdLib as specifically for Lexing. It could simplify things. Idunno.
The main goal of this programming language thing IS to facilitate lexing, with a particular focus on writing declarative code that is very easy to read & modify.
I've kind of already covered the Declarative code part with the existing Directives. Everything I'm describing here ... most of it anyway ... I've basically already done, but it's one big mish-mash of Lexer use
ing a bunch of traits. This whole idea is really just a MAJOR refactor.
Would such a refactor actually make the lexer easier to work with? Would it actually be easier to write grammars?
Nov 21, 2023
Output ASTs as code. I'd like a proof of concept that starts with ASTs and outputs PHP code. If time allows, I'd like to also allow output of javascript code. (I'm sticking with those two because I know them well)
I need to start with an AST, then add a method to it to output code. If it contains other ASTs, those will also have their output-code methods called.
I'll start with an empty class because I already have good parsing of classes. I'll then add in properties & methods with no body.
WHOO!! PROOF OF CONCEPT WORKS I did:
- Create ClassAst, DocblockAst, and PropertyAst
- Create get_php_code() & get_javascript_code() methods on each to return string code in the target language
- Create test class Translate at
test/run/translate/Translate.php
with a hard-coded ast to js & php test, and a test outputting the code fortest/output/php/tree/SampleClass.js
.
Notes:
- SampleClass.js outputs with the property value wrapped in extra quotes like
dog = '"PandaBearDog"'
. I'm usingvar_export()
bc my sample ast in the first test doesn't have the string quote marks around the value. That AST is probably written incorrectly. Idk. - I'm tired.
- I would like each of the new ASTs to be strongly typed & docblock-commented to describe what each property is.
Oct 21, 2023
Making a .bak file of the current PHP Grammar. Going to maybe make some major changes to the directives. Tempted to start fresh, but kind of know that's gonna be a bad idea. I want to eliminate all of the php components, except for more generic directives. I want all of the logic to be in the Directive definitions.
Oct 18, 2023
I'm basically done with CreateParser.src.md. I maybe should add a better example of a full Directive. I may want to move the breakdown of instructions into its own file. And maybe rename CreateParser. Also, I suppose I haven't actually touched on any of the PHP of creating a Parser. Yeah. I guess I'll need to do that. So yeah, there's work to do yet on CreateParser.src.md
I updated the readme slightly. Commented out the Use an ast & parse code documentation links, but those will need to be made eventually.
Oct 17, 2023
Documented in CreateParser.src.md. Did a little docblocking. Only 7 more instructions to document!!!
Oct 16, 2023
I worked on documentation. I started a new README (DON'T RUN SCRAWL!). I added .docsrc/CreateParser.src.md and documented a fair bit about how the lexer works, as well as several instructions. I documented ALL the instructions that are in the MappedMethods.php file. I need to still document all the instructions in the switch statement in Instructions.php.
At some point it might be nice to refactor this stuff. It's all pretty confusing. But, I'm doing fine going through it and writing documentation, so I guess it doesn't really matter. As long as the documentation is good, it should be fine.
I probably need a new / better format for documenting the instructions, but what I have currently in CreateParser.src.md is quite alright for now.
I didn't add or modify any docblocks, and some of the documentation I found was wrong.
Aug 10, 2023
started in-depth parsing of vars in method body.
added some return types
added some docblocks
added \Tlf\Lexer\Versions
for versioning code
added $signal
to lexer for expressing expectations simply.
added has()
to ast to check for a key
Production by default runs with the old lexing.
Tests, however, by default use Lexer\Versions::_1 (i.e. 1.0
)
To check the var parsing & new signal-stuff see:
-
phptest -test Directives -run Var.Assign.Variable -stop_loop 27
-
phptest -test Directives -run Var.Assign.String
(i broke this some how, but it WAS working) - or to run directive tests without new code:
phptest -test Directives -version 0.1
- code/Php/Operations.php
- code/Php/Words.php
- test/src/Php/Vars.php
TODO
- (May 13, 2022) LilMigrations fails parsing. I believe
foreach()
is the problem, starting line 105. Need to figure out / fix this. - (apr 27, 2022) php method body does not contain blank newlines. It should, though, so i can print it back out just as it is written
- review documentation
- add to documentation:
test/output/PhpFeatures.md
contains a list of directive unit tests (their description, input code, and whether they passed their tests). Looking at this is a good way to see what language features have been implemented - maybe remove nesting a php class inside a namespace ast ... i just don't like it
- am i handling interfaces?
- clean up the php grammar (remove old commented debug code & whatnot)
- create passing BashGrammar tests
- create an easy mode feature like:
$ast = $lexer->easy_mode('php', $string_to_lex)
- delete the old BashGrammar, JsonGrammar, defunct Docblock grammar,
- document directives (use docblocks, but i don't think the lexer can currently get docblocks attached to array keys like i want for this)
- make generic base grammar that works how the PhpGrammar does
- maybe make a StringGrammar as well, since string features are often shared between languages
March 13, 2022
All my tests are passing! I haven't implemented all of the PHP features, but I have the majority of them handled. I haven't added anything that's new in 8.0 or 8.1 & I don't know how I'll handle versioning ...
My directive tests are cleaned up. All my grammar tests are cleaned up. Basically, this thing is now awesome, robust, trustworthy.
It will still probably need features added here & there, but it's finally at a point where I can count on it.
It would be nice (but not necessary) to write a code-scrawl extension that documents all the directive tests for each grammar.
I would like to add an "EasyMode" to simply do like ... $ast = $lexer->easy_mode('php', $string_to_lex)
And I want to clean up this document.
Eventually, I want to catch expression, so a script or function body would have an array of expressions like $var = 'whatever';
and return true;
as well as breaking down if
s/foreach
es (ones with block at least) as expressions containing expressions.
Eventually, i would like to break down each expression so $var = 'whatever'
is generic like: type=set variable, name='var', value='whatever'
Eventually, all this expression breakdown could be used to transpile between different languages.
TODOs (old, but maybe still relevant)
- Finish the
GrammarTesting
documentation (once method bodies are available)
High Priority (internals)
- Make DocblockGrammar work for bash (docblock starts with
##
) - BashGrammar + simple tests. Catch:
- docblocks
- functions
- maybe comments
- nothing else
Low Priority
- rename
previous
tometa
ordata
. I'm thinkingmeta
. & make it its own group if its not - Add meta information to ASTs & OPTIONALLY include meta information when getting an AST tree
- Convert
type
to_type
on ASTs maybe? (its meta information)
- Convert
- add additional command arg expansion features (
[]
and!
) -
abort
feature:- Add an instruction that: Mark a directive as an abortion target
- Add an instruction that: pop directives until a named abortion target is on the top of the stack
- Threaded parsing. Starts as a single thread, then any instruction can create a new thread & now we'll continue processing on the main thread & process on the new thread as well. Ultimately only one thread can "win", so all but the "correct" thread will be discarded
- move the
while
loop inInternals
into its own function likedo_the_actual_lexing($lexer, $token)
or something. - Might just have to create multiple lexer instances to do this.
- move the
- Performance: Use arrays, & do object conversions on directives at the last possible moment. I only want them as objects, so they're easier to work with by reference.
Latest (pretty old list)
- Support return by reference on methods:
public function &global_warming()
(this method launches billionaires to space temporarily & returns a reference to an array detailing the CO2 pollution. (which is bad, because you can just lie and change it to less pollution, now that we're done with the space trip)) - Support all arithmetic operators
- added
none
operation target, which just stops the directive from being processed if it is that operation- Used by the
/*
operation so that the docblock directive still handles it
- Used by the
- Refactored operation stuff & multi-char operations are now functional.
- wrote
operation_match()
method to check if the current buffer is an operation. Simplifies matching multi-char operations. - Operators are refactored, so multi-char operators can be used
- support simple array declaration
- add
Values
trait to test value assignment - parse
trait
s the same way I doclass
es (for the most part) - implemented:
namespace Abc; class Def {}
- get fully qualified name for the class - support & test php class
use TraitName;
- support & test php class
const
s - add a
stop
instruction set tophp_code
directive - catch
<?php
and?>
- Unit test
static
properties and methods - add minimal debugging output to the
wd_
andop_
routing. - clean up notes
- Property & method tests passing (& all other current tests)
- Fix the
methods are inside class modifiers
bug - Add ability to
-run Namespace.*
and run any tests that wildcard match, basically. - Separate php directive tests into traits
- Add word routing to
wd_theword($lexer, $xpn, $ast)
- Rename OtherDirectives to CoreDirectives
- Refactored operations into Handlers, Operations, and Words
- Methods are completely handled! (I think)
- Implement almost complete for properties
- Properties handle string concatenation, but NOT numeric operations
- add operation routing to
op_opname($lexer, $xpn)
- New mechanism of operations & words