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

Refactor: Class parser #59

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3862ab5
Initial release: package lang.codedom
thekid Feb 22, 2015
ae76034
Extract functionality out into base classes
thekid Feb 22, 2015
022417e
Verify apidoc comments access works via reflection
thekid Feb 22, 2015
63b3d57
Add thrown exceptions, distinguish between constructor and methods
thekid Feb 22, 2015
46a8685
Refactor: Use new lang.codedom API to parse code
thekid Feb 22, 2015
83de219
Remove DETAIL_COMMENT from class details
thekid Feb 22, 2015
71a1cf1
Remove methods now in lang.codedom.PhpSyntax
thekid Feb 22, 2015
6690434
Normalize package name to dotted form
thekid Feb 22, 2015
d9d4281
Normalize import names to dotted form
thekid Feb 22, 2015
ac4e20b
Adjust to changes in imports
thekid Feb 22, 2015
d9f3736
Replace AnyOf -> Repeated(OneOf())
thekid Feb 22, 2015
2aaa01e
Extract into base class
thekid Feb 22, 2015
9340eea
Initial release: Annotation parser
thekid Feb 22, 2015
cecac62
Refactor: Use new Annotation parser instead of handcrafted one
thekid Feb 22, 2015
34efde9
Remove trailing comma
thekid Feb 22, 2015
00d94d0
Merge implementations of high-performing OneOf and flexible EitherOf
thekid Feb 22, 2015
d09cc97
QA: Reflow code
thekid Feb 22, 2015
1220206
Add isTrait(), isInterface(), isClass()
thekid Feb 24, 2015
5f3f44f
Add body() accessor
thekid Feb 24, 2015
5ccb5ec
Method / Constructor declaration: arguments^Wparameters
thekid Feb 24, 2015
8ba4326
Refactor: Migrate generic types creation to CodeDOM API
thekid Feb 26, 2015
b48a6ff
Use pre-initialized __generic[] type arg lookup
thekid Feb 26, 2015
7db2859
QA: Apidocs
thekid Feb 26, 2015
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
447 changes: 240 additions & 207 deletions src/main/php/lang/GenericTypes.class.php

Large diffs are not rendered by default.

14 changes: 11 additions & 3 deletions src/main/php/lang/XPClass.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,6 @@ public function getDeclaredInterfaces() {
}
return $r;
}


/**
* Retrieves the api doc comment for this class. Returns NULL if
Expand All @@ -476,8 +475,17 @@ public function getDeclaredInterfaces() {
* @return string
*/
public function getComment() {
if (!($details= self::detailsForClass($this->name))) return null;
return $details['class'][DETAIL_COMMENT];
$comment= $this->_reflect->getDocComment();
if (false === $comment) {
$class= $this->_reflect->getName();
return isset(\xp::$meta[$class]['class'][DETAIL_COMMENT]) ? \xp::$meta[$class]['class'][DETAIL_COMMENT]: null;
} else {
return trim(preg_replace('/\n\s+\* ?/', "\n", "\n".substr(
$comment,
4, // "/**\n"
strpos($comment, '* @')- 2 // position of first details token
)));
}
}

/**
Expand Down
43 changes: 43 additions & 0 deletions src/main/php/lang/codedom/AnnotationArray.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php namespace lang\codedom;

use util\Objects;

class AnnotationArray extends \lang\Object {
private $backing;

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

public function resolve($context, $imports) {
$resolved= [];
foreach ($this->backing as $value) {
$k= key($value);
if (0 === $k) {
$resolved[]= current($value)->resolve($context, $imports);
} else {
$resolved[$k]= current($value)->resolve($context, $imports);
}
}
return $resolved;
}

/**
* Creates a string representation
*
* @return string
*/
public function toString() {
return $this->getClassName().'('.Objects::stringOf($this->backing).')';
}

/**
* Returns whether a given value is equal to this code unit
*
* @param var $cmp
* @return bool
*/
public function equals($cmp) {
return $cmp instanceof self && Objects::equal($this->backing, $cmp->backing);
}
}
50 changes: 50 additions & 0 deletions src/main/php/lang/codedom/AnnotationClosure.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php namespace lang\codedom;

use util\Objects;
use lang\IllegalStateException;

class AnnotationClosure extends \lang\Object {
private $signature, $code;

public function __construct($signature, $code) {
$this->signature= $signature;
$this->code= $code;
}

public function resolve($context, $imports) {
$func= eval('return function('.$this->signature.') {'.$this->code.'};');
if (!($func instanceof \Closure)) {
if ($error= error_get_last()) {
set_error_handler('__error', 0);
trigger_error('clear_last_error');
restore_error_handler();
} else {
$error= ['message' => 'Syntax error'];
}
throw new IllegalStateException('In `'.$this->code.'`: '.ucfirst($error['message']));
}
return $func;
}

/**
* Creates a string representation
*
* @return string
*/
public function toString() {
return $this->getClassName().'('.Objects::stringOf($this->backing).')';
}

/**
* Returns whether a given value is equal to this code unit
*
* @param var $cmp
* @return bool
*/
public function equals($cmp) {
return $cmp instanceof self && (
$this->signature === $cmp->signature &&
$this->code === $cmp->code
);
}
}
35 changes: 35 additions & 0 deletions src/main/php/lang/codedom/AnnotationConstant.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php namespace lang\codedom;

class AnnotationConstant extends \lang\Object {
private $name;

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

public function resolve($context, $imports) {
if (defined($this->name)) {
return constant($this->name);
}
raise('lang.ElementNotFoundException', 'Undefined constant "'.$this->name.'"');
}

/**
* Creates a string representation
*
* @return string
*/
public function toString() {
return $this->getClassName().'('.$this->name.')';
}

/**
* Returns whether a given value is equal to this code unit
*
* @param var $cmp
* @return bool
*/
public function equals($cmp) {
return $cmp instanceof self && $this->name === $cmp->name;
}
}
40 changes: 40 additions & 0 deletions src/main/php/lang/codedom/AnnotationDeclaration.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php namespace lang\codedom;

use util\Objects;

class AnnotationDeclaration extends \lang\Object {
private $target, $name, $value;

public function __construct($target, $name, \lang\Generic $value) {
$this->target= $target;
$this->name= $name;
$this->value= $value;
}

/** @return string */
public function target() { return $this->target; }

/** @return string */
public function name() { return $this->name; }

/** @return string */
public function value() { return $this->value; }

public function resolve($context, $imports) {
return $this->value->resolve($context, $imports);
}

/**
* Returns whether a given value is equal to this code unit
*
* @param var $cmp
* @return bool
*/
public function equals($cmp) {
return $cmp instanceof self && (
$this->target === $cmp->target &&
$this->name === $cmp->name &&
Objects::equal($this->value, $cmp->value)
);
}
}
46 changes: 46 additions & 0 deletions src/main/php/lang/codedom/AnnotationInstance.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php namespace lang\codedom;

use lang\Objects;

class AnnotationInstance extends \lang\Object { use ResolvingType;
private $type;

public function __construct($type, $arguments) {
$this->type= $type;
$this->arguments= $arguments;
}

public function resolve($context, $imports) {
$type= $this->typeOf($this->type, $context, $imports);
if ($type->hasConstructor()) {
return $type->getConstructor()->newInstance(array_map(
function($arg) use($context, $imports) { return $arg->resolve($context, $imports); },
$this->arguments
));
} else {
return $type->newInstance();
}
}

/**
* Creates a string representation
*
* @return string
*/
public function toString() {
return $this->getClassName().'(new '.$this->type.'('.Objects::stringOf($this->arguments).'))';
}

/**
* Returns whether a given value is equal to this code unit
*
* @param var $cmp
* @return bool
*/
public function equals($cmp) {
return $cmp instanceof self && (
Objects::equal($this->arguments, $cmp->arguments) &&
Objects::equal($this->type, $cmp->type)
);
}
}
54 changes: 54 additions & 0 deletions src/main/php/lang/codedom/AnnotationMember.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php namespace lang\codedom;

use lang\Objects;
use lang\IllegalAccessException;
use lang\reflect\Modifiers;

class AnnotationMember extends \lang\Object { use ResolvingType;
private $type;

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

public function resolve($context, $imports) {
$type= $this->typeOf($this->type, $context, $imports);
if ('$' === $this->name{0}) {
$field= $type->getField(substr($this->name, 1));
$m= $field->getModifiers();
if ($m & MODIFIER_PUBLIC) {
return $field->get(null);
} else if (($m & MODIFIER_PROTECTED) && $type->isAssignableFrom($context)) {
return $field->setAccessible(true)->get(null);
} else if (($m & MODIFIER_PRIVATE) && $type->getName() === $context) {
return $field->setAccessible(true)->get(null);
} else {
throw new IllegalAccessException(sprintf(
'Cannot access %s field %s::$%s',
implode(' ', Modifiers::namesOf($m)),
$type->getName(),
$field->getName()
));
}
return $type->getField(substr($this->name, 1))->setAccessible(true)->get(null);
} else if ('class' === $this->name) {
return ltrim($type->literal(), '\\');
} else {
return $type->getConstant($this->name);
}
}

/**
* Returns whether a given value is equal to this code unit
*
* @param var $cmp
* @return bool
*/
public function equals($cmp) {
return $cmp instanceof self && (
$this->name === $cmp->name &&
$this->type === $cmp->type
);
}
}
38 changes: 38 additions & 0 deletions src/main/php/lang/codedom/AnnotationPairs.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php namespace lang\codedom;

use util\Objects;

class AnnotationPairs extends \lang\Object {
private $backing;

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

public function resolve($context, $imports) {
$resolved= [];
foreach ($this->backing as $pair) {
$resolved[key($pair)]= current($pair)->resolve($context, $imports);
}
return $resolved;
}

/**
* Creates a string representation
*
* @return string
*/
public function toString() {
return $this->getClassName().'('.Objects::stringOf($this->backing).')';
}

/**
* Returns whether a given value is equal to this code unit
*
* @param var $cmp
* @return bool
*/
public function equals($cmp) {
return $cmp instanceof self && Objects::equal($this->backing, $cmp->backing);
}
}
Loading