Skip to content

Commit

Permalink
Move declare() to parent class
Browse files Browse the repository at this point in the history
  • Loading branch information
thekid committed Jun 4, 2023
1 parent b980f30 commit b635068
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 21 deletions.
28 changes: 8 additions & 20 deletions src/test/php/lang/ast/unittest/emit/AnnotationSupport.class.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php namespace lang\ast\unittest\emit;

use lang\{Reflection, IllegalArgumentException};
use lang\IllegalArgumentException;
use test\{Assert, Expect, Test, Values};

/**
Expand All @@ -11,18 +11,6 @@
*/
abstract class AnnotationSupport extends EmittingTest {

/**
* Declares annotations, optionally including a type
*
* @param string $declaration
* @return lang.reflection.Type
*/
private function declare($declaration) {
return Reflection::type($this->type(
$declaration.(strstr($declaration, '<T>') ? '' : ' class <T> { }')
));
}

/**
* Returns annotations present in the given type
*
Expand Down Expand Up @@ -127,13 +115,13 @@ public function single_quoted_string_inside_non_constant_expression() {
public function has_access_to_class() {
Assert::equals(
['Expect' => [true]],
$this->annotations($this->declare('#[Expect(self::SUCCESS)] class <T> { const SUCCESS = true; }'))
$this->annotations($this->declare('#[Expect(self::SUCCESS)] class %T { const SUCCESS = true; }'))
);
}

#[Test]
public function method() {
$t= $this->declare('class <T> { #[Test] public function fixture() { } }');
$t= $this->declare('class %T { #[Test] public function fixture() { } }');
Assert::equals(
['Test' => []],
$this->annotations($t->method('fixture'))
Expand All @@ -142,7 +130,7 @@ public function method() {

#[Test]
public function field() {
$t= $this->declare('class <T> { #[Test] public $fixture; }');
$t= $this->declare('class %T { #[Test] public $fixture; }');
Assert::equals(
['Test' => []],
$this->annotations($t->property('fixture'))
Expand All @@ -151,7 +139,7 @@ public function field() {

#[Test]
public function param() {
$t= $this->declare('class <T> { public function fixture(#[Test] $param) { } }');
$t= $this->declare('class %T { public function fixture(#[Test] $param) { } }');
Assert::equals(
['Test' => []],
$this->annotations($t->method('fixture')->parameter(0))
Expand All @@ -160,7 +148,7 @@ public function param() {

#[Test]
public function params() {
$t= $this->declare('class <T> { public function fixture(#[Inject(["name" => "a"])] $a, #[Inject] $b) { } }');
$t= $this->declare('class %T { public function fixture(#[Inject(["name" => "a"])] $a, #[Inject] $b) { } }');
Assert::equals(
['Inject' => [['name' => 'a']]],
$this->annotations($t->method('fixture')->parameter(0))
Expand All @@ -181,7 +169,7 @@ public function multiple_class_annotations() {

#[Test]
public function multiple_member_annotations() {
$t= $this->declare('class <T> { #[Test, Values([1, 2, 3])] public function fixture() { } }');
$t= $this->declare('class %T { #[Test, Values([1, 2, 3])] public function fixture() { } }');
Assert::equals(
['Test' => [], 'Values' => [[1, 2, 3]]],
$this->annotations($t->method('fixture'))
Expand All @@ -195,7 +183,7 @@ public function multiline_annotations() {
"Timm",
"Mr. Midori",
])]
class <T> { }'
class %T { }'
));
Assert::equals(['Authors' => [['Timm', 'Mr. Midori']]], $annotations);
}
Expand Down
37 changes: 36 additions & 1 deletion src/test/php/lang/ast/unittest/emit/EmittingTest.class.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<?php namespace lang\ast\unittest\emit;

use io\streams\MemoryOutputStream;
use lang\DynamicClassLoader;
use lang\ast\emit\GeneratedCode;
use lang\ast\emit\php\XpMeta;
use lang\ast\{CompilingClassLoader, Emitter, Language, Result, Tokens};
use lang\{DynamicClassLoader, Reflection};
use test\{Args, After, Assert, TestCase};
use util\cmd\Console;

Expand Down Expand Up @@ -72,6 +72,7 @@ protected function emit($code) {
/**
* Declare a type
*
* @deprecated Use `declare()` instead
* @param string $code
* @return lang.XPClass
*/
Expand All @@ -97,6 +98,40 @@ protected function type($code) {
return $this->cl->loadClass($class);
}

/**
* Declare a type with a unique type name (which may be referenced by `%T`)
* and return a reflection instance referencing it.
*
* @param string $code
* @return lang.reflection.Type
*/
protected function declare($code) {
$name= 'T'.(self::$id++);
$declaration= strstr($code, '%T')
? str_replace('%T', $name, $code)
: $code.' class '.$name.' { }'
;

$tree= $this->language->parse(new Tokens($declaration, static::class))->tree();
if (isset($this->output['ast'])) {
Console::writeLine();
Console::writeLine('=== ', static::class, ' ===');
Console::writeLine($tree);
}

$out= new MemoryOutputStream();
$this->emitter->emitAll(new GeneratedCode($out, ''), $tree->children());
if (isset($this->output['code'])) {
Console::writeLine();
Console::writeLine('=== ', static::class, ' ===');
Console::writeLine($out->bytes());
}

$class= ($package= $tree->scope()->package) ? strtr(substr($package, 1), '\\', '.').'.'.$name : $name;
$this->cl->setClassBytes($class, $out->bytes());
return Reflection::type($this->cl->loadClass0($class));
}

/**
* Run code
*
Expand Down

0 comments on commit b635068

Please sign in to comment.