The main intent why i wanted to rewrite the parsing is to delay
creating literals until compiler/environment needs it.
So, a new workflow is following:
During parsing, parser only looks after correct syntax. Encoding of
all semantic constructs is delegated to encoder instance.
Encoder responsible for watching the scope & producing lambdas on-the-fly.
The result of parsing is lambda, ready for consuming by transforming compiler.
Now, why encoding literals rocks:
It was very inconvenient that old Scanner drops knowledge about
literal type at early stage, and returns a simple #literal ,
so i used to encode it like:
context literalValue: value , where value could be anything - a
char, a number, a string or array.
And then, when i need to convert literal to oop in simulated memory,
it ends up with something like:
literalFor: anObject
anObject isSymbol ifTrue: [
^ self symbolFor: anObject
].
anObject isInteger ifTrue: [^ anObject ].
anObject isString ifTrue: [ ^ self stringFor: anObject ].
anObject == true ifTrue: [
^ objects at: #true ifAbsent: [ objects at: #true put: self defineTrue]
].
anObject == false ifTrue: [
^ objects at: #false ifAbsent: [ objects at: #false put: self defineFalse]
].
self error: 'unable to convert literal'.
----
As you may see, there is one kind of literals missing - array literal..
Which makes conversion code even more complex and stinky, because each
value in array could be in own turn a literal which would require
separate conversion.
But now this could be dropped! I know exactly what literal kind is
parsed, and encode them by using different lambdas:
#integerLiteral:
#floatLiteral:
#charLiteral:
#stringLiteral:
... and so on.
This makes a whole convesion is much more straightforward without
duplicating a logic (why we would test literal type, if we know it
from very start - at parsing stage!)
A concrete, strict directives always better than murky code with
numerous checks, they leave no space for errors :)
--
Best regards,
Igor Stasenko AKA sig.