Skip to content

Refactor value arrays to specialized types #19

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
415 changes: 209 additions & 206 deletions src/main/php/lang/ast/Emitter.class.php

Large diffs are not rendered by default.

140 changes: 85 additions & 55 deletions src/main/php/lang/ast/Parse.class.php

Large diffs are not rendered by default.

120 changes: 63 additions & 57 deletions src/main/php/lang/ast/emit/PHP56.class.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php namespace lang\ast\emit;

use lang\ast\nodes\Value;

/**
* PHP 5.6 syntax
*
Expand Down Expand Up @@ -90,128 +92,132 @@ protected function returnType($name) {
return null;
}

protected function catches($catch) {
$last= array_pop($catch[0]);
protected function emitCatch($catch) {
$last= array_pop($catch->types);
$label= sprintf('c%u', crc32($last));
foreach ($catch[0] as $type) {
$this->out->write('catch('.$type.' $'.$catch[1].') { goto '.$label.'; }');
foreach ($catch->types as $type) {
$this->out->write('catch('.$type.' $'.$catch->variable.') { goto '.$label.'; }');
}

$this->out->write('catch('.$last.' $'.$catch[1].') { '.$label.':');
$this->emit($catch[2]);
$this->out->write('catch('.$last.' $'.$catch->variable.') { '.$label.':');
$this->emit($catch->body);
$this->out->write('}');
}

protected function emitConst($node) {
$this->out->write('const '.$node->value[0].'=');
$this->emit($node->value[2]);
protected function emitConst($const) {
$this->out->write('const '.$const->name.'=');
$this->emit($const->expression);
$this->out->write(';');
}

protected function emitAssignment($node) {
if ('array' === $node->value[0]->arity) {
protected function emitAssignment($assignment) {
if ('array' === $assignment->variable->arity) {
$this->out->write('list(');
foreach ($node->value[0]->value as $expr) {
$this->emit($expr[1]);
foreach ($assignment->variable->value as $pair) {
$this->emit($pair[1]);
$this->out->write(',');
}
$this->out->write(')');
$this->out->write($node->symbol->id);
$this->emit($node->value[1]);
$this->out->write($assignment->operator);
$this->emit($assignment->expression);
} else {
parent::emitAssignment($node);
parent::emitAssignment($assignment);
}
}

protected function emitBinary($node) {
if ('??' === $node->symbol->id) {
protected function emitBinary($binary) {
if ('??' === $binary->operator) {
$this->out->write('isset(');
$this->emit($node->value[0]);
$this->emit($binary->left);
$this->out->write(') ?');
$this->emit($node->value[0]);
$this->emit($binary->left);
$this->out->write(' : ');
$this->emit($node->value[1]);
} else if ('<=>' === $node->symbol->id) {
$this->emit($binary->right);
} else if ('<=>' === $binary->operator) {
$l= $this->temp();
$r= $this->temp();
$this->out->write('('.$l.'= ');
$this->emit($node->value[0]);
$this->emit($binary->left);
$this->out->write(') < ('.$r.'=');
$this->emit($node->value[1]);
$this->emit($binary->right);
$this->out->write(') ? -1 : ('.$l.' == '.$r.' ? 0 : 1)');
} else {
parent::emitBinary($node);
parent::emitBinary($binary);
}
}

/** @see https://wiki.php.net/rfc/context_sensitive_lexer */
protected function emitInvoke($node) {
$expr= $node->value[0];
protected function emitInvoke($invoke) {
$expr= $invoke->expression;
if ('braced' === $expr->arity) {
$t= $this->temp();
$this->out->write('(('.$t.'=');
$this->emit($expr->value);
$this->out->write(') ? '.$t);
$this->out->write('(');
$this->arguments($node->value[1]);
$this->arguments($invoke->arguments);
$this->out->write(') : __error(E_RECOVERABLE_ERROR, "Function name must be a string", __FILE__, __LINE__))');
} else if ('scope' === $expr->arity && 'name' === $expr->value[1]->arity && isset(self::$keywords[strtolower($expr->value[1]->value)])) {
$this->out->write($expr->value[0].'::{\''.$expr->value[1]->value.'\'}');
} else if (
'scope' === $expr->arity &&
'name' === $expr->value->member->arity &&
isset(self::$keywords[strtolower($expr->value->member->value)])
) {
$this->out->write($expr->value->type.'::{\''.$expr->value->member->value.'\'}');
$this->out->write('(');
$this->arguments($node->value[1]);
$this->arguments($invoke->arguments);
$this->out->write(')');
} else {
parent::emitInvoke($node);
parent::emitInvoke($invoke);
}
}

protected function emitNew($node) {
if (null === $node->value[0]) {
$this->out->write('\\lang\\ClassLoader::defineType("class©anonymous'.md5($node->hashCode()).'", ["kind" => "class"');
$definition= $node->value[2];
$this->out->write(', "extends" => '.($definition[2] ? '[\''.$definition[2].'\']' : 'null'));
$this->out->write(', "implements" => '.($definition[3] ? '[\''.implode('\', \'', $definition[3]).'\']' : 'null'));
protected function emitNew($new) {
if ($new->type instanceof Value) {
$this->out->write('\\lang\\ClassLoader::defineType("class©anonymous'.md5(uniqid()).'", ["kind" => "class"');
$definition= $new->type;
$this->out->write(', "extends" => '.($definition->parent ? '[\''.$definition->parent.'\']' : 'null'));
$this->out->write(', "implements" => '.($definition->implements ? '[\''.implode('\', \'', $definition->implements).'\']' : 'null'));
$this->out->write(', "use" => []');
$this->out->write('], \'{');
$this->out->write(str_replace('\'', '\\\'', $this->buffer(function() use($definition) {
foreach ($definition[4] as $member) {
foreach ($definition->body as $member) {
$this->emit($member);
$this->out->write("\n");
}
})));
$this->out->write('}\')->newInstance(');
$this->arguments($definition[1]);
$this->arguments($new->arguments);
$this->out->write(')');
} else {
parent::emitNew($node);
parent::emitNew($new);
}
}

protected function emitFrom($node) {
protected function emitFrom($from) {
$this->out->write('foreach (');
$this->emit($node->value);
$this->emit($from);
$this->out->write(' as $key => $val) yield $key => $val;');
}

/** @see https://wiki.php.net/rfc/context_sensitive_lexer */
protected function emitMethod($node) {
if (isset(self::$keywords[strtolower($node->value[0])])) {
$this->call[in_array('static', $node->value[1])][]= $node->value[0];
$node->value[0]= '__'.$node->value[0];
} else if ('__call' === $node->value[0] || '__callStatic' === $node->value[0]) {
$node->value[0].= '0';
protected function emitMethod($method) {
if (isset(self::$keywords[strtolower($method->name)])) {
$this->call[in_array('static', $method->modifiers)][]= $method->name;
$method->name= '__'.$method->name;
} else if ('__call' === $method->name || '__callStatic' === $method->name) {
$method->name.= '0';
}
parent::emitMethod($node);
parent::emitMethod($method);
}

protected function emitClass($node) {
protected function emitClass($class) {
$this->call= [false => [], true => []];
array_unshift($this->meta, []);
$this->out->write(implode(' ', $node->value[1]).' class '.$this->declaration($node->value[0]));
$node->value[2] && $this->out->write(' extends '.$node->value[2]);
$node->value[3] && $this->out->write(' implements '.implode(', ', $node->value[3]));
$this->out->write(implode(' ', $class->modifiers).' class '.$this->declaration($class->name));
$class->parent && $this->out->write(' extends '.$class->parent);
$class->implements && $this->out->write(' implements '.implode(', ', $class->implements));
$this->out->write('{');
foreach ($node->value[4] as $member) {
foreach ($class->body as $member) {
$this->emit($member);
}

Expand All @@ -231,7 +237,7 @@ protected function emitClass($node) {
}

$this->out->write('static function __init() {');
$this->emitMeta($node->value[0], $node->value[5], $node->value[6]);
$this->out->write('}} '.$node->value[0].'::__init();');
$this->emitMeta($class->name, $class->annotations, $class->comment);
$this->out->write('}} '.$class->name.'::__init();');
}
}
32 changes: 16 additions & 16 deletions src/main/php/lang/ast/emit/PHP70.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,36 +19,36 @@ class PHP70 extends \lang\ast\Emitter {
'iterable' => 71
];

protected function catches($catch) {
$last= array_pop($catch[0]);
protected function emitCatch($catch) {
$last= array_pop($catch->types);
$label= sprintf('c%u', crc32($last));
foreach ($catch[0] as $type) {
$this->out->write('catch('.$type.' $'.$catch[1].') { goto '.$label.'; }');
foreach ($catch->types as $type) {
$this->out->write('catch('.$type.' $'.$catch->variable.') { goto '.$label.'; }');
}

$this->out->write('catch('.$last.' $'.$catch[1].') { '.$label.':');
$this->emit($catch[2]);
$this->out->write('catch('.$last.' $'.$catch->variable.') { '.$label.':');
$this->emit($catch->body);
$this->out->write('}');
}

protected function emitAssignment($node) {
if ('array' === $node->value[0]->arity) {
protected function emitAssignment($assignment) {
if ('array' === $assignment->variable->arity) {
$this->out->write('list(');
foreach ($node->value[0]->value as $expr) {
$this->emit($expr[1]);
foreach ($assignment->variable->value as $pair) {
$this->emit($pair[1]);
$this->out->write(',');
}
$this->out->write(')');
$this->out->write($node->symbol->id);
$this->emit($node->value[1]);
$this->out->write($assignment->operator);
$this->emit($assignment->expression);
} else {
parent::emitAssignment($node);
parent::emitAssignment($assignment);
}
}

protected function emitConst($node) {
$this->out->write('const '.$node->value[0].'=');
$this->emit($node->value[2]);
protected function emitConst($const) {
$this->out->write('const '.$const->name.'=');
$this->emit($const->expression);
$this->out->write(';');
}
}
11 changes: 11 additions & 0 deletions src/main/php/lang/ast/nodes/AssignmentValue.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php namespace lang\ast\nodes;

class AssignmentValue extends Value {
public $variable, $operator, $expression;

public function __construct($variable, $operator, $expression) {
$this->variable= $variable;
$this->operator= $operator;
$this->expression= $expression;
}
}
11 changes: 11 additions & 0 deletions src/main/php/lang/ast/nodes/BinaryValue.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php namespace lang\ast\nodes;

class BinaryValue extends Value {
public $left, $operator, $right;

public function __construct($left, $operator, $right) {
$this->left= $left;
$this->operator= $operator;
$this->right= $right;
}
}
10 changes: 10 additions & 0 deletions src/main/php/lang/ast/nodes/CaseValue.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php namespace lang\ast\nodes;

class CaseValue extends Value {
public $expression, $body;

public function __construct($expression, $body) {
$this->expression= $expression;
$this->body= $body;
}
}
10 changes: 10 additions & 0 deletions src/main/php/lang/ast/nodes/CastValue.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php namespace lang\ast\nodes;

class CastValue extends Value {
public $type, $expression;

public function __construct($type, $expression) {
$this->type= $type;
$this->expression= $expression;
}
}
11 changes: 11 additions & 0 deletions src/main/php/lang/ast/nodes/CatchValue.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php namespace lang\ast\nodes;

class CatchValue extends Value {
public $types, $variable, $body;

public function __construct($types, $variable, $body) {
$this->types= $types;
$this->variable= $variable;
$this->body= $body;
}
}
15 changes: 15 additions & 0 deletions src/main/php/lang/ast/nodes/ClassValue.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php namespace lang\ast\nodes;

class ClassValue extends Value {
public $name, $modifiers, $parent, $implements, $body, $annotations, $comment;

public function __construct($name, $modifiers, $parent, $implements, $body, $annotations, $comment) {
$this->name= $name;
$this->modifiers= $modifiers;
$this->parent= $parent;
$this->implements= $implements;
$this->body= $body;
$this->annotations= $annotations;
$this->comment= $comment;
}
}
11 changes: 11 additions & 0 deletions src/main/php/lang/ast/nodes/ClosureValue.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php namespace lang\ast\nodes;

class ClosureValue extends Value {
public $signature, $use, $body;

public function __construct($signature, $use, $body) {
$this->signature= $signature;
$this->use= $use;
$this->body= $body;
}
}
11 changes: 11 additions & 0 deletions src/main/php/lang/ast/nodes/ConstValue.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php namespace lang\ast\nodes;

class ConstValue extends Value {
public $name, $modifiers, $expression;

public function __construct($name, $modifiers, $expression) {
$this->name= $name;
$this->modifiers= $modifiers;
$this->expression= $expression;
}
}
10 changes: 10 additions & 0 deletions src/main/php/lang/ast/nodes/DoValue.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php namespace lang\ast\nodes;

class DoValue extends Value {
public $expression, $body;

public function __construct($expression, $body) {
$this->expression= $expression;
$this->body= $body;
}
}
12 changes: 12 additions & 0 deletions src/main/php/lang/ast/nodes/ForValue.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php namespace lang\ast\nodes;

class ForValue extends Value {
public $initialization, $condition, $loop, $body;

public function __construct($initialization, $condition, $loop, $body) {
$this->initialization= $initialization;
$this->condition= $condition;
$this->loop= $loop;
$this->body= $body;
}
}
Loading