Log Call
Now that we have our basic tokens being parsed, it's time to tackle something a little more difficult.
Looking at our DSL again:
print hello
Taking a look at this we can immediately see that we want to print the thing after our print
call.
As we haven't really defined language semantics, we're able to do that right now. Let's assume that we want to log everything on the same line as our print statement.
if (currentToken.type === TokenType.Log) {
let nextNode = tokens[currentIndex++]
const children: ASTNode[] = []
// Process
return {
type: ASTNodeType.Log,
children
}
}
First, we set up nextNode
to reference the next.. node :)
Then we'll define an array of child nodes - the nodes that we will actually be logging.
while (nextNode.type !== TokenType.LineBreak) {
// Process
nextNode = tokens[currentIndex]
}
Now, we're going to continuously loop over our current tokens. That is, until we find one that is a line break.
Once we hit our line break, we know that we're at the end of our log statement.
const next = process()
if (next) {
children.push(next)
}
To get our actual child node, we need to now call process()
. As we've already incremented currentIndex
, the entire loop will run again (and potentially again and again.. depending on the complexity of the language that we end up) while iterating and generating our child tree.
Once we have this, we need to check it's not null, and then add it to our array of children.
This would be a perfect place to add some validation, what happens if the node we get back is null? We'll cover adding checks in a later section of the guide.
Final Code
if (currentToken.type === TokenType.Log) {
let nextNode = tokens[currentIndex++]
const children: ASTNode[] = []
while (nextNode.type !== TokenType.LineBreak) {
const next = process()
if (next) {
children.push(next)
}
nextNode = tokens[currentIndex]
}
return {
type: ASTNodeType.Log,
children
}
}