Neon with AST parser and Format-preserving Printing

David Grudl
Nette Core | 7790

NEON has a completely rewritten parser that generates an AST tree. Even the export uses AST trees. This gives the library a few new features.

This already works in version 3.3.0, only the classes listed are marked as @internal because the interface may still change.

AST parser

Parsing text into AST nodes can be done using:

$input = '
hello: world
arr: [1, 2, 3]

$decoder = new Nette\Neon\Decoder;
$node = $decoder->parseToNode($input);

Finish processing and return a PHP value can be done with toValue():

$data = $node->toValue();  // ['hello' => 'world', 'arr' => [1, 2, 3]]

Or conversely, to generate the NEON format can be done using toString():

$output = $node->toString();

Which returns a string essentially identical to $input.

You can iterate (traverse) over individual nodes and modify their values. For example, this is how to add a key of the form key# to all elements in the array if they don't have a key:

use Nette\Neon\Node;

$visitor = function (Node $node) {
	if ($node instanceof Node\ArrayNode) {
		foreach ($node->items as $i => $item) {
			$item->key ??= new Node\LiteralNode("key$i");

$node = $decoder->parseToNode($input);
$traverser = new Nette\Neon\Traverser;
$node = $traverser->traverse($node, $visitor);
echo $node->toString();

This would change the original $input to:

hello: world
arr: {key0: 1, key1: 2, key2: 3}

Format-preserving Printing

The new parser gives the possibility to create format-preserving printing as well. This is implemented in the test branch for now.

Source file foo.neon:

# List of users
users: [1, 2, 3, 4]
# Revision v0.0.1

We update its contents while preserving the formatting:

// read & parse content
$content = file_get_contents('foo.neon');
$data = Nette\Neon\Neon::decode($content);

// update data
$data->users[] = 5;

// create updated file
$output = Nette\Neon\Neon::update($content, $data);
file_put_contents('foo.neon', $output);

Writes a new foo.neon:

# List of users
users: [1, 2, 3, 4, 5]
# Revision v0.0.1
Nette Core | 1164