\Tale\JadeParser

Takes tokens from the Lexer and creates an AST out of it.

This class takes generated tokens from the Lexer sequentially and produces an Abstract Syntax Tree (AST) out of it

The AST is an object-tree containing Node-instances with parent/child relations

This AST is passed to the compiler to generate PHTML out of it

Usage example:

use Tale\Jade\Parser;

$parser = new Parser();

echo $parser->parse($jadeInput);
//Prints a human-readable dump of the parsed nodes

Summary

Methods
Properties
Constants
__construct()
getOptions()
getLexer()
parse()
No public properties found
No constants found
handleToken()
lookUp()
lookUpNext()
expect()
expectNext()
expectEnd()
hasTokens()
nextToken()
getToken()
createNode()
createElement()
handleAssignment()
handleAttribute()
handleAttributeStart()
handleAttributeEnd()
handleBlock()
handleClass()
handleComment()
handleCase()
handleConditional()
handleDo()
handleDoctype()
handleEach()
handleExpression()
handleFilter()
handleId()
handleImport()
handleIndent()
handleTag()
handleMixin()
handleMixinCall()
handleNewLine()
handleOutdent()
handleExpansion()
handleText()
handleWhen()
handleWhile()
throwException()
No protected properties found
N/A
No private methods found
$_options
$_lexer
$_level
$_tokens
$_document
$_currentParent
$_current
$_last
$_inMixin
$_mixinLevel
$_expansion
N/A

Properties

$_options

$_options : array

The options array used for this parser instance.

Type

array

$_lexer

$_lexer : \Tale\Jade\Lexer

The lexer used in this parser instance.

Type

\Tale\Jade\Lexer

$_level

$_level : integer

The level we're currently on.

This does not equal the Lexer-level or Compiler-level, it's an internal level to get the child/parent-relation between nodes right

Type

integer

$_tokens

$_tokens : \Generator

The Generator returned by the ->lex() method of the lexer.

Type

\Generator

$_document

$_document : \Tale\Jade\Parser\Node

The root node of the currently parsed document.

Type

\Tale\Jade\Parser\Node

$_currentParent

$_currentParent : \Tale\Jade\Parser\Node

The parent that currently found childs are appended to.

When an -token is encountered, it moves one parent up ($_currentParent->parent becomes the new $_currentParent)

Type

\Tale\Jade\Parser\Node

$_current

$_current : \Tale\Jade\Parser\Node

The current element in the queue.

Will be appended to $_currentParent when a -token is encountered It will become the current parent, if an -token is encountered

Type

\Tale\Jade\Parser\Node

$_last

$_last : \Tale\Jade\Parser\Node

The last element that was completely put together.

Will be set on a -token ($_current will become last)

Type

\Tale\Jade\Parser\Node

$_inMixin

$_inMixin : boolean

States if we're in a mixin or not.

Used to check for the mixin-block and nested mixins

Type

boolean

$_mixinLevel

$_mixinLevel : integer

The level we're on inside a mixin.

Used to check for the mixin-block and nested mixins

Type

integer

$_expansion

$_expansion : \Tale\Jade\Parser\Node

Stores an expanded node to attach it to the expanding node later.

Type

\Tale\Jade\Parser\Node

Methods

__construct()

__construct(array|null  $options = null, \Tale\Jade\Lexer|null  $lexer = null) 

Creates a new parser instance.

The parser will run the provided input through the lexer and generate an AST out of it.

The AST will be an object-tree consisting of \Tale\Jade\Parser\Node instances

You can take the AST and either compile it with the Compiler or handle it yourself

Possible options are:

lexerOptions: The options for the lexer

Parameters

array|null $options

the options array

\Tale\Jade\Lexer|null $lexer

an existing lexer instance (lexer-option will be ignored)

getOptions()

getOptions() : array

Returns the currently used option-array of the Parser.

Returns

array

getLexer()

getLexer() : \Tale\Jade\Lexer

Returns the currently used Lexer instance.

Returns

\Tale\Jade\Lexer

parse()

parse(string  $input) : \Tale\Jade\Parser\Node

Parses the provided input-string to an AST.

The Abstract Syntax Tree (AST) will be an object-tree consisting of \Tale\Jade\Parser\Node instances.

You can either let the compiler compile it or compile it yourself

The root-node will always be of type 'document', from there on it can contain several kinds of nodes

Parameters

string $input

the input jade string that is to be parsed

Returns

\Tale\Jade\Parser\Node

the root-node of the parsed AST

handleToken()

handleToken(array|null  $token = null) 

Handles any kind of token returned by the lexer dynamically.

The token-type will be translated into a method name e.g.

newLine => handleNewLine attribute => handleAttribute tag => handleTag

First argument of that method will always be the token array

If no token is passed, it will take the current token in the lexer's token generator

Parameters

array|null $token

a token or the current lexer's generator token

Throws

\Tale\Jade\Parser\Exception

when no token handler has been found

lookUp()

lookUp(array  $types) : \Generator

Yields tokens as long as the given types match.

Yields tokens of the given types until a token is encountered, that is not given in the types-array

Parameters

array $types

the token types that are allowed

Returns

\Generator

lookUpNext()

lookUpNext(array  $types) : \Generator

Moves on the token generator by one and does ->lookUp().

Parameters

array $types

the types that are allowed

Returns

\Generator

expect()

expect(array  $types) : \Tale\Jade\Parser\Node|null

Returns the token of the given type if it is in the token queue.

If the given token in the queue is not of the given type, this method returns null

Parameters

array $types

the types that are expected

Returns

\Tale\Jade\Parser\Node|null

expectNext()

expectNext(array  $types) : \Tale\Jade\Parser\Node|null

Moves the generator on by one and does ->expect().

Parameters

array $types

the types that are expected

Returns

\Tale\Jade\Parser\Node|null

expectEnd()

expectEnd(array|null  $relatedToken = null) 

Throws an exception if the next token is not a newLine token.

This states that "a line of instructions should end here"

Notice that if the next token is not a newLine, it gets handled through handleToken automatically

Parameters

array|null $relatedToken

the token to relate the exception to

Throws

\Tale\Jade\Parser\Exception

when the next token is not a newLine token

hasTokens()

hasTokens() : boolean

Returns true, if there are still tokens left to be generated.

If the lexer-generator still has tokens to generate, this returns true and false, if it doesn't

Returns

boolean

nextToken()

nextToken() : $this

Moves the generator on by one token.

(It calls ->next() on the generator, look at the PHP doc)

Returns

$this

getToken()

getToken() : array

Returns the current token in the lexer generator.

Returns

array —

the token array (always one token, as an array)

createNode()

createNode(string  $type, array|null  $token = null) : \Tale\Jade\Parser\Node

Creates a new node instance with the given type.

If a token is given, the location in the code of that token is also passed to the Node instance

If no token is passed, a dummy-token with the current lexer's offset and line is created

Notice that nodes are expando-objects, you can add properties on-the-fly and retrieve them as an array later

Parameters

string $type

the type the node should have

array|null $token

the token to relate this node to

Returns

\Tale\Jade\Parser\Node

The newly created node

createElement()

createElement(array|null  $token = null) : \Tale\Jade\Parser\Node

Creates an element-node with the properties it should have consistently.

This will create the following properties on the Node instance:

Parameters

array|null $token

the token to relate this element to

Returns

\Tale\Jade\Parser\Node

the newly created element-node

handleAssignment()

handleAssignment(array  $token) 

Parses an <assignment>-token into element assignments.

If no there is no $_current element, a new one is created

Assignments are possible on elements and mixinCalls only

After an assignment, an attribute block is required

Parameters

array $token

the -token

Throws

\Tale\Jade\Parser\Exception

handleAttribute()

handleAttribute(array  $token) 

Parses an <attribute>-token into an attribute-node.

That node is appended to the $_current element.

If no $_current element exists, a new one is created

Attributes in elements and mixins always need a valid name

Parameters

array $token

the -token

Throws

\Tale\Jade\Parser\Exception

handleAttributeStart()

handleAttributeStart(array  $token) 

Handles an <attributeStart>-token.

Attributes can only start on elements, assignments, imports, mixins and mixinCalls

After that, all following -tokens are handled. After that, an -token is expected (When I think about it, the Lexer kind of does that already)

Parameters

array $token

the -token

Throws

\Tale\Jade\Parser\Exception

handleAttributeEnd()

handleAttributeEnd(array  $token) 

Handles an <attributeEnd>-token.

It does nothing (right now?)

Parameters

array $token

the -token

handleBlock()

handleBlock(array  $token) 

Handles a <block>-token and parses it into a block-node.

Blocks outside a mixin always need a name! (That's what $_inMixin is for)

Parameters

array $token

the -token

Throws

\Tale\Jade\Parser\Exception

handleClass()

handleClass(array  $token) 

Handles a <class>-token and parses it into an element.

If there's no $_current-node, a new one is created

It will be converted to a regular -node on the element (There is no class-node)

Classes can only exist on elements and mixinCalls

Parameters

array $token

the -token

Throws

\Tale\Jade\Parser\Exception

handleComment()

handleComment(array  $token) 

Handles a <comment>-token and parses it into a comment-node.

The comment node is set as the $_current element

Parameters

array $token

the -token

handleCase()

handleCase(array  $token) 

Handles a <case>-token and parses it into a case-node.

Parameters

array $token

the -token

handleConditional()

handleConditional(array  $token) 

Handles a <conditional>-token and parses it into a conditional-node.

Parameters

array $token

the -token

handleDo()

handleDo(array  $token) 

Handles a <do>-token and parses it into a do-node.

Parameters

array $token

the -token

handleDoctype()

handleDoctype(array  $token) 

Handles a <doctype>-token and parses it into a doctype-node.

Parameters

array $token

the -token

handleEach()

handleEach(array  $token) 

Handles an <each>-token and parses it into an each-node.

Parameters

array $token

the -token

handleExpression()

handleExpression(array  $token) 

Handles an <expression>-token into an expression-node.

If there's a $_current-element, the expression gets appended to the $_current-element. If not, the expression itself becomes the $_current element

Parameters

array $token

the -token

Throws

\Tale\Jade\Parser\Exception

handleFilter()

handleFilter(array  $token) 

Handles a <filter>-token and parses it into a filter-node.

Parameters

array $token

the -token

handleId()

handleId(array  $token) 

Handles an <id>-token and parses it into an element.

If no $_current element exists, a new one is created

IDs can only exist on elements an mixin calls

They will get converted to attribute-nodes and appended to the current element

Parameters

array $token

the -token

Throws

\Tale\Jade\Parser\Exception

handleImport()

handleImport(array  $token) 

Handles an <import>-token and parses it into an import-node.

Notice that "extends" and "include" are basically the same thing. The only difference is that "extends" can only exist at the very beginning of a jade-block

Only "include" can have filters, though. This gets checked in the Compiler, not here

Parameters

array $token

the -token

Throws

\Tale\Jade\Parser\Exception

handleIndent()

handleIndent(array|null  $token = null) 

Handles an <indent>-token.

The $_level will be increased by 1 for each

If there's no $_last element (which is set on a newLine), we do nothing (because there's nothing to indent into)

The $_last node is set as the $_currentParent node and acts as a parent-node for further created nodes (They get appended in handleNewLine)

import-nodes can't be indented into, because they can't have children (poor imports :'( )

The opposite of this is, obviously, handleOutdent with -tokens

Parameters

array|null $token

the -token

Throws

\Tale\Jade\Parser\Exception

handleTag()

handleTag(array  $token) 

Handles a <tag>-token and parses it into a tag-node.

If no $_current element exists, a new one is created A tag can only exist once on an element Only elements can have tags

Parameters

array $token

the -token

Throws

\Tale\Jade\Parser\Exception

handleMixin()

handleMixin(array  $token) 

Handles a <mixin>-token and parses it into a mixin-node.

Mixins can't be inside other mixins. We use $_inMixin and $_mixinLevel for that $_mixinLevel gets reset in handleOutdent

Parameters

array $token

the -token

Throws

\Tale\Jade\Parser\Exception

handleMixinCall()

handleMixinCall(array  $token) 

Handles a <mixinCall>-token and parses it into a mixinCall-node.

Parameters

array $token

the -token

handleNewLine()

handleNewLine() 

Handles a <newLine>-token.

If there's no $_current element, it does nothing If there is one it:

  1. Checks if we have an $_expansion. If we do, append it to $_current and reset $_expansion
  2. Appends the $_current element to the $_currentParent
  3. Set's the $_last element to the $_current element
  4. Resets $_current to null

handleOutdent()

handleOutdent() 

Handles an <outdent>-token.

Decreases the current $_level by 1

Sets the $_currentParent to the ->parent of $_currentParent (Walking up the tree by 1)

If we're in a mixin and we're at or below our mixin-level again, we're not in a mixin anymore

handleExpansion()

handleExpansion(array  $token) 

Handles an <expansion>-token.

If there's no current element, we don't expand anything and throw an exception

If there's no space behind the : and the next token is a -token, we don't treat this as an expansion, but rather as a tag-extension (a:b === </a:b>, a: b === ) This is important for XML and XML-namespaces

Notice that, right now, any element that can also land in $_current can be expanded (so almost all elements there are) It just makes no sense for some elements ("extends", "include")

$_current is reset after the expansion so that we can collect the expanding element and handle it on a newLine or in an indent

Parameters

array $token

the -token

Throws

\Tale\Jade\Parser\Exception

handleText()

handleText(array  $token) 

Handles a <text>-token and parses it into a text-node.

If there's a $_current element, we append it to that element, if not, it becomes the $_current element

Parameters

array $token

the -token

handleWhen()

handleWhen(array  $token) 

Handles a <when>-token and parses it into a when-node.

Parameters

array $token

the -token

handleWhile()

handleWhile(array  $token) 

Handles a <while>-token and parses it into a while-node.

Parameters

array $token

the -token

throwException()

throwException(string  $message, array|null  $relatedToken = null) 

Throws a Parser-Exception.

If a related token is passed, it will also append the location in the input of that token

Parameters

string $message

a meaningful error-message

array|null $relatedToken

the token related to this error

Throws

\Tale\Jade\Parser\Exception