Skip to content
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

[WIP] Objects support #8

Merged
merged 1 commit into from
Jan 2, 2013
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 31 additions & 0 deletions lib/PHPPHP/Engine/ClassStore.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace PHPPHP\Engine;

use PHPPHP\Engine\Objects\ClassEntry;

class ClassStore {
/** @var ClassEntry[] */
protected $classes = array();

public function register(ClassEntry $ce) {
$lcname = strtolower($ce->getName());
if (isset($this->classes[$lcname])) {
throw new \RuntimeException(sprintf("Class %s already defined", $ce->getName()));
}
$this->classes[$lcname] = $ce;
}

public function exists($name) {
return isset($this->classes[strtolower($name)]);
}

public function get($name) {
$name = strtolower($name);
if (!isset($this->classes[$name])) {
throw new \RuntimeException(sprintf('Undefined class %s', $name));
}

return $this->classes[$name];
}
}
107 changes: 74 additions & 33 deletions lib/PHPPHP/Engine/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace PHPPHP\Engine;

use PHPPHP\Engine\Objects\ClassEntry;

class Compiler {

protected $operators = array(
Expand All @@ -19,6 +21,7 @@ class Compiler {
'Expr_Cast_Double' => array('UnaryOp', 'PHPPHP\Engine\OpLines\CastDouble', 'expr'),
'Expr_Cast_Int' => array('UnaryOp', 'PHPPHP\Engine\OpLines\CastInt', 'expr'),
'Expr_Cast_String' => array('UnaryOp', 'PHPPHP\Engine\OpLines\CastString', 'expr'),
'Expr_Cast_Object' => array('UnaryOp', 'PHPPHP\Engine\OpLines\CastObject', 'expr'),
'Expr_Eval' => array('UnaryOp', 'PHPPHP\Engine\OpLines\EvalOp', 'expr'),
'Expr_Exit' => array('UnaryOp', 'PHPPHP\Engine\OpLines\ExitOp', 'expr'),
'Expr_BooleanNot' => array('UnaryOp', 'PHPPHP\Engine\OpLines\BooleanNot'),
Expand Down Expand Up @@ -72,6 +75,9 @@ class Compiler {
/** @var OpArray */
protected $opArray;

/** @var ClassEntry */
protected $currentClass;

public function compile(array $ast, Zval\Ptr $returnContext = null) {
$opArray = new OpArray;

Expand Down Expand Up @@ -288,38 +294,7 @@ protected function compile_Stmt_Foreach($node) {
}

protected function compile_Stmt_Function(\PHPParser_Node_Stmt_Function $node) {
$prevOpArray = $this->opArray;
$this->opArray = new OpArray;

foreach ($node->params as $i => $param) {
$arg = Zval::ptrFactory();

if ($param->default) {
$this->opArray[] = new OpLines\RecvInit(
Zval::factory($i), $this->makeZvalFromNode($param->default), $arg
);
} else {
$this->opArray[] = new OpLines\Recv(Zval::factory($i), null, $arg);
}

$var = Zval::variableFactory(Zval::factory($param->name));
$this->opArray->addCompiledVariable($var);
if ($param->byRef) {
$this->opArray[] = new OpLines\AssignRef($var, $arg);
} else {
$this->opArray[] = new OpLines\Assign($var, $arg);
}
}

$this->compileChild($node, 'stmts');

$this->opArray[] = new OpLines\ReturnOp;

$funcData = new FunctionData\User($this->opArray, (bool) $node->byRef);

$prevOpArray[] = new OpLines\FunctionDef(Zval::factory($node->name), $funcData);

$this->opArray = $prevOpArray;
$this->compileFunction($node);
}

protected function compile_Stmt_Global($node) {
Expand Down Expand Up @@ -437,6 +412,72 @@ protected function compile_Stmt_InlineHtml($node) {
$this->opArray[] = new OpLines\EchoOp(Zval::ptrFactory($node->value));
}

protected function compile_Stmt_Class($node) {
$class = new ClassEntry($node->name);
$this->currentClass = $class;
$this->compileChild($node, 'stmts');
$this->currentClass = null;
$this->opArray[] = new OpLines\ClassDef($class);
}

protected function compile_Stmt_Property($node) {
}

protected function compile_Stmt_ClassMethod($node) {
$this->compileFunction($node);
}

public function compile_Expr_New($node, $returnContext = null) {
$this->opArray[] = new OpLines\NewOp(Zval::ptrFactory($node->class->toString()), Zval::ptrFactory($node->args), $returnContext);
}

public function compile_Expr_MethodCall($node, $returnContext = null) {
$var = Zval::ptrFactory();
$this->compileChild($node, 'var', $var);
$op = new OpLines\MethodCall(Zval::ptrFactory($node->name), Zval::ptrFactory($node->args), $returnContext);
$op->setObjectOp($var);
$this->opArray[] = $op;
}

protected function compileFunction($node) {
$prevOpArray = $this->opArray;
$this->opArray = new OpArray;

foreach ($node->params as $i => $param) {
$arg = Zval::ptrFactory();

if ($param->default) {
$this->opArray[] = new OpLines\RecvInit(
Zval::factory($i), $this->makeZvalFromNode($param->default), $arg
);
} else {
$this->opArray[] = new OpLines\Recv(Zval::factory($i), null, $arg);
}

$var = Zval::variableFactory(Zval::factory($param->name));
$this->opArray->addCompiledVariable($var);
if ($param->byRef) {
$this->opArray[] = new OpLines\AssignRef($var, $arg);
} else {
$this->opArray[] = new OpLines\Assign($var, $arg);
}
}

$this->compileChild($node, 'stmts');

$this->opArray[] = new OpLines\ReturnOp;

$funcData = new FunctionData\User($this->opArray, (bool) $node->byRef);

if ($this->currentClass) {
$this->currentClass->addMethod($node->name, $funcData);
} else {
$prevOpArray[] = new OpLines\FunctionDef(Zval::factory($node->name), $funcData);
}

$this->opArray = $prevOpArray;
}

protected function makeZvalFromNodeStrict(\PHPParser_Node $node) {
$zval = $this->makeZvalFromNode($node);

Expand Down Expand Up @@ -470,4 +511,4 @@ protected function makeZvalFromNode(\PHPParser_Node $node) {
return null;
}
}
}
}
9 changes: 8 additions & 1 deletion lib/PHPPHP/Engine/CoreExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace PHPPHP\Engine;

use PHPPHP\Engine\Objects\ClassEntry;

final class CoreExtension extends Extension\Base {

protected $name = 'Core';
Expand Down Expand Up @@ -57,4 +59,9 @@ protected function getConstants() {
);
}

}
protected function getClasses() {
return array(
new ClassEntry('stdClass'),
);
}
}
8 changes: 7 additions & 1 deletion lib/PHPPHP/Engine/Executor.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ class Executor {

protected $functionStore;
protected $constantStore;
protected $classStore;

public function __construct(FunctionStore $functionStore, ConstantStore $constantStore) {
public function __construct(FunctionStore $functionStore, ConstantStore $constantStore, ClassStore $classStore) {
$this->executorGlobals = new ExecutorGlobals;
$this->parser = new Parser;
$this->compiler = new Compiler;
$this->functionStore = $functionStore;
$this->constantStore = $constantStore;
$this->classStore = $classStore;

$this->extensions = new \SplObjectStorage;
}
Expand Down Expand Up @@ -96,6 +98,10 @@ public function getConstantStore() {
return $this->constantStore;
}

public function getClassStore() {
return $this->classStore;
}

public function registerExtension(Extension $extension) {
if (!$this->extensions->contains($extension)) {
$extension->register($this);
Expand Down
10 changes: 9 additions & 1 deletion lib/PHPPHP/Engine/Extension/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ public function register(\PHPPHP\Engine\Executor $executor) {
foreach ($this->getConstants() as $name => $value) {
$constantStore->register($name, Engine\Zval::factory($value));
}
$classStore = $executor->getClassStore();
foreach ($this->getClasses() as $ce) {
$classStore->register($ce);
}
}

public function getName() {
Expand All @@ -42,4 +46,8 @@ abstract protected function loadFunctions();
protected function getConstants() {
return array();
}
}

protected function getClasses() {
return array();
}
}
48 changes: 48 additions & 0 deletions lib/PHPPHP/Engine/Objects/ClassEntry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace PHPPHP\Engine\Objects;

use PHPPHP\Engine\ExecuteData;
use PHPPHP\Engine\Objects\ClassInstance;
use PHPPHP\Engine\FunctionData;
use PHPPHP\Engine\Zval\Ptr;
use PHPPHP\Engine\Zval;

class ClassEntry
{
private $name;
private $methods = array();

public function __construct($name)
{
$this->name = $name;
}

public function getName()
{
return $this->name;
}

public function instanciate(ExecuteData $data, array $properties, array $args = array())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*nit instantiate

{
return new ClassInstance($this, $properties);
}

public function addMethod($name, FunctionData $method)
{
$this->methods[$name] = $method;
}

public function callMethod(ExecuteData $data, ClassInstance $ci, $name, array $args, Ptr $result = null)
{
if (!isset($this->methods[$name])) {
throw new \RuntimeException(sprintf('Call to undefined method %s::%s()', $this->getName(), $name));
}
$method = $this->methods[$name];
if (!$result) {
$result = Zval::ptrFactory();
}
$method->execute($data->executor, $args, $result);
}
}

44 changes: 44 additions & 0 deletions lib/PHPPHP/Engine/Objects/ClassInstance.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace PHPPHP\Engine\Objects;

use PHPPHP\Engine\ExecuteData;
use PHPPHP\Engine\Zval\Ptr;
use PHPPHP\Engine\Objects\ClassEntry;
use PHPPHP\Engine\Zval;

class ClassInstance
{
private $ce;
private $properties = array();

public function __construct(ClassEntry $ce, array $properties) {
$this->ce = $ce;
$this->properties = $properties;

array_map(function($property) {
$property->addRef();
}, $this->properties);
}

public function getProperty($name) {
if (!isset($this->properties[$name])) {
$value = Zval::ptrFactory();
$this->properties[$name] = $value;
} else {
$value = $this->properties[$name];
}
return $value;
}

public function callMethod(ExecuteData $data, $name, array $args, Ptr $result = null) {
$this->ce->callMethod($data, $this, $name, $args, $result);
}

public function __destruct() {
array_map(function($property) {
$property->delRef();
}, $this->properties);
}
}

13 changes: 13 additions & 0 deletions lib/PHPPHP/Engine/OpLines/CastObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace PHPPHP\Engine\OpLines;

class CastObject extends \PHPPHP\Engine\OpLine {

public function execute(\PHPPHP\Engine\ExecuteData $data) {
$this->result->setValue($this->op1->toObject($data));

$data->nextOp();
}

}
16 changes: 16 additions & 0 deletions lib/PHPPHP/Engine/OpLines/ClassDef.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace PHPPHP\Engine\OpLines;

use PHPPHP\Engine\FunctionData;

class ClassDef extends \PHPPHP\Engine\OpLine {

public function execute(\PHPPHP\Engine\ExecuteData $data) {
$ce = $this->op1;

$data->executor->getClassStore()->register($ce);

$data->nextOp();
}
}
20 changes: 20 additions & 0 deletions lib/PHPPHP/Engine/OpLines/MethodCall.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace PHPPHP\Engine\OpLines;

class MethodCall extends \PHPPHP\Engine\OpLine {

private $objectOp;

public function setObjectOp($objectOp) {
$this->objectOp = $objectOp;
}

public function execute(\PHPPHP\Engine\ExecuteData $data) {
$object = $this->objectOp->toObject($data);
$methodName = $this->op1->toString();
$args = $this->op2->toArray();
$object->callMethod($data, $methodName, $args, $this->result);
$data->nextOp();
}
}