/**
  * Executes this check
  *
  * @param   xp.compiler.ast.Node node
  * @param   xp.compiler.types.Scope scope
  * @return  bool
  */
 public function verify(\xp\compiler\ast\Node $node, \xp\compiler\types\Scope $scope)
 {
     $routine = \cast($node, 'xp.compiler.ast.RoutineNode');
     $qname = $scope->declarations[0]->name->compoundName() . '::' . $routine->getName();
     $empty = $routine->body === null;
     if ($scope->declarations[0] instanceof \xp\compiler\ast\InterfaceNode) {
         if (!$empty) {
             return ['R403', 'Interface methods may not have a body ' . $qname];
         } else {
             if ($routine->modifiers !== MODIFIER_PUBLIC && $routine->modifiers !== 0) {
                 return ['R401', 'Interface methods may only be public ' . $qname];
             }
         }
     } else {
         if (Modifiers::isAbstract($routine->modifiers) && !$empty) {
             return ['R403', 'Abstract methods may not have a body ' . $qname];
         } else {
             if (!Modifiers::isAbstract($routine->modifiers) && $empty) {
                 return ['R401', 'Non-abstract methods must have a body ' . $qname];
             }
         }
         if ($routine->extension && !Modifiers::isStatic($routine->modifiers)) {
             return ['E403', 'Extension methods must be static ' . $qname];
         }
     }
 }
 /**
  * Provide tests from a given package to the test suite. Handles recursion.
  *
  * @param  lang.reflect.Package $package
  * @param  unittest.TestSuite $suite
  * @param  var[] $arguments
  * @return void
  */
 private function provideFrom($package, $suite, $arguments)
 {
     foreach ($package->getClasses() as $class) {
         if ($class->isSubclassOf(TestCase::class) && !Modifiers::isAbstract($class->getModifiers())) {
             $suite->addTestClass($class, $arguments);
         }
     }
     if ($this->recursive) {
         foreach ($package->getPackages() as $package) {
             $this->provideFrom($package, $suite, $arguments);
         }
     }
 }
 /**
  * Returns a list of all classes inside a given package
  *
  * @param   lang.reflect.Package 
  * @param   bool recursive whether to include subpackages
  * @return  lang.XPClass[]
  */
 protected static function testClassesIn(Package $package, $recursive)
 {
     $r = array();
     foreach ($package->getClasses() as $class) {
         if (!$class->isSubclassOf('unittest.TestCase') || Modifiers::isAbstract($class->getModifiers())) {
             continue;
         }
         $r[] = $class;
     }
     if ($recursive) {
         foreach ($package->getPackages() as $package) {
             $r = array_merge($r, self::testClassesIn($package, $recursive));
         }
     }
     return $r;
 }
 /**
  * Provide tests to test suite
  *
  * @param  unittest.TestSuite $suite
  * @param  var[] $arguments
  * @return void
  * @throws lang.IllegalArgumentException if no tests are found
  */
 public function provideTo($suite, $arguments)
 {
     $it = new FilteredIOCollectionIterator(new FileCollection($this->loader->path), new ExtensionEqualsFilter(\xp::CLASS_FILE_EXT), true);
     $l = strlen($this->loader->path);
     $e = -strlen(\xp::CLASS_FILE_EXT);
     $empty = true;
     foreach ($it as $element) {
         $class = $this->loader->loadClass(strtr(substr($element->getUri(), $l, $e), DIRECTORY_SEPARATOR, '.'));
         if ($class->isSubclassOf(TestCase::class) && !Modifiers::isAbstract($class->getModifiers())) {
             $suite->addTestClass($class, $arguments);
             $empty = false;
         }
     }
     if ($empty) {
         throw new IllegalArgumentException('Cannot find any test cases in ' . $this->loader->toString());
     }
 }
Esempio n. 5
0
 /**
  * Get all test cases
  *
  * @param   var[] arguments
  * @return  unittest.TestCase[]
  */
 public function testCasesWith($arguments)
 {
     if (null === ($cl = $this->findLoaderFor($this->folder->getURI()))) {
         throw new IllegalArgumentException($this->folder->toString() . ' is not in class path');
     }
     $l = strlen($cl->path);
     $e = -strlen(\xp::CLASS_FILE_EXT);
     $it = new FilteredIOCollectionIterator(new FileCollection($this->folder), new ExtensionEqualsFilter(\xp::CLASS_FILE_EXT), true);
     $cases = [];
     foreach ($it as $element) {
         $name = strtr(substr($element->getUri(), $l, $e), DIRECTORY_SEPARATOR, '.');
         $class = XPClass::forName($name);
         if (!$class->isSubclassOf('unittest.TestCase') || Modifiers::isAbstract($class->getModifiers())) {
             continue;
         }
         $cases = array_merge($cases, $this->testCasesInClass($class, $arguments));
     }
     if (empty($cases)) {
         throw new IllegalArgumentException('Cannot find any test cases in ' . $this->folder->toString());
     }
     return $cases;
 }
 public function is_abstract()
 {
     $this->assertTrue(\lang\reflect\Modifiers::isAbstract(self::$fixture->getModifiers()));
 }
 public function abstractModifier()
 {
     $this->assertTrue(\lang\reflect\Modifiers::isAbstract(MODIFIER_ABSTRACT));
 }
Esempio n. 8
0
 /**
  * Lists commands
  *
  * @return void
  */
 protected function listCommands()
 {
     $commandsIn = function ($package) {
         $text = '';
         foreach ($package->getClasses() as $class) {
             if ($class->isSubclassOf('util.cmd.Command') && !Modifiers::isAbstract($class->getModifiers())) {
                 $text .= '  $ xpcli ' . $class->getSimpleName() . "\n";
             }
         }
         return $text ?: '  (no commands)';
     };
     self::$err->writeLine('Named commands');
     self::$err->writeLine();
     if ($packages = Commands::allPackages()) {
         foreach (Commands::allPackages() as $package) {
             self::$err->writeLine('* ', $package);
             self::$err->writeLine($commandsIn($package));
         }
         self::$err->writeLine();
     }
     self::$err->writeLine('* Global package');
     self::$err->writeLine($commandsIn(Package::forName(null)));
 }
Esempio n. 9
0
 /**
  * Asserts given modifiers do not contain abstract
  *
  * @param  int $modifiers
  * @return void
  * @throws unittest.AssertionFailedError
  */
 protected function assertNotAbstract($modifiers)
 {
     $this->assertFalse(Modifiers::isAbstract($modifiers), implode(' | ', Modifiers::namesOf($modifiers)));
 }
Esempio n. 10
0
 /**
  * Lists commands
  *
  * @return void
  */
 protected function listCommands()
 {
     $commandsIn = function ($package) {
         $markdown = '';
         foreach ($package->getClasses() as $class) {
             if ($class->isSubclassOf('util.cmd.Command') && !Modifiers::isAbstract($class->getModifiers())) {
                 $markdown .= '  $ xp cmd ' . $class->getSimpleName() . "\n";
             }
         }
         return $markdown ?: '  *(no commands)*';
     };
     $markdown = "# Named commands\n\n";
     if ($packages = Commands::allPackages()) {
         foreach ($packages as $package) {
             $markdown .= '* In package **' . $package->getName() . "**\n\n" . $commandsIn($package);
         }
         $markdown .= "\n";
     }
     $markdown .= "* In global package\n\n" . $commandsIn(Package::forName(null));
     Help::render(self::$err, $markdown, []);
 }
Esempio n. 11
0
 /**
  * Emit an enum declaration
  *
  * Basic form:
  * <code>
  *   public enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }
  * </code>
  *
  * With values:
  * <code>
  *   public enum Coin { penny(1), nickel(2), dime(10), quarter(25) }
  * </code>
  *
  * Abstract:
  * <code>
  *   public abstract enum Operation {
  *     plus {
  *       public int evaluate(int $x, int $y) { return $x + $y; }
  *     },
  *     minus {
  *       public int evaluate(int $x, int $y) { return $x - $y; }
  *     };
  *
  *     public abstract int evaluate(int $x, int $y);
  *   }
  * </code>
  *
  * @param   xp.compiler.emit.Buffer b
  * @param   xp.compiler.ast.EnumNode declaration
  */
 protected function emitEnum($b, $declaration)
 {
     $parent = $declaration->parent ?: new TypeName('lang.Enum');
     $parentType = $this->resolveType($parent);
     $thisType = new TypeDeclaration(new ParseTree($this->scope[0]->package, [], $declaration), $parentType);
     $this->scope[0]->addResolved('self', $thisType);
     $this->scope[0]->addResolved('parent', $parentType);
     // FIXME: ???
     $this->scope[0]->addResolved($declaration->name->name, $thisType);
     $this->scope[0]->imports[$declaration->name->name] = $declaration->name->name;
     $this->enter(new TypeDeclarationScope());
     // Ensure parent class and interfaces are loaded
     $this->emitTypeName($b, 'class', $declaration);
     $b->append(' extends ' . $this->literal($parentType, true));
     array_unshift($this->metadata, [[], []]);
     array_unshift($this->properties, ['get' => [], 'set' => []]);
     $abstract = Modifiers::isAbstract($declaration->modifiers);
     // Meta data
     $this->metadata[0]['class'] = $this->meta($declaration->comment, $declaration->annotations, []);
     // Generics
     if ($declaration->name->isGeneric()) {
         $this->metadata[0]['class'][DETAIL_ANNOTATIONS]['generic']['self'] = $this->genericComponentAsMetadata($declaration->name);
     }
     if ($parent->isGeneric()) {
         $this->metadata[0]['class'][DETAIL_ANNOTATIONS]['generic']['parent'] = $this->genericComponentAsMetadata($parent);
     }
     // Interfaces
     if ($declaration->implements) {
         $b->append(' implements ');
         $s = sizeof($declaration->implements) - 1;
         foreach ($declaration->implements as $i => $type) {
             if ($type->isGeneric()) {
                 $this->metadata[0]['class'][DETAIL_ANNOTATIONS]['generic']['implements'][$i] = $this->genericComponentAsMetadata($type);
             }
             $b->append($this->resolveType($type)->literal(true));
             $i < $s && $b->append(', ');
         }
     }
     // Member declaration
     $b->append(' {');
     // public static self[] values() { return parent::membersOf(__CLASS__) }
     $declaration->body[] = new MethodNode(['modifiers' => MODIFIER_PUBLIC | MODIFIER_STATIC, 'annotations' => null, 'name' => 'values', 'returns' => new TypeName('self[]'), 'parameters' => null, 'throws' => null, 'body' => [new ReturnNode(new StaticMethodCallNode(new TypeName('parent'), 'membersOf', [new StringNode($this->literal($thisType))]))], 'comment' => '(Generated)']);
     // Members
     foreach ((array) $declaration->body as $node) {
         $this->emitOne($b, $node);
     }
     $this->emitProperties($b, $this->properties[0]);
     // Initialization
     $b->append('static function __static() {');
     foreach ($declaration->body as $i => $member) {
         if (!$member instanceof EnumMemberNode) {
             continue;
         }
         $b->append('self::$' . $member->name . '= ');
         if ($member->body) {
             if (!$abstract) {
                 $this->error('E403', 'Only abstract enums can contain members with bodies (' . $member->name . ')');
                 // Continues so declaration is closed
             }
             $unique = new TypeName($declaration->name->name . '··' . $member->name);
             $decl = new ClassNode(0, null, $unique, $declaration->name, [], $member->body);
             $decl->synthetic = true;
             $ptr = new TypeDeclaration(new ParseTree(null, [], $decl), $thisType);
             $this->scope[0]->declarations[] = $decl;
             $b->append('new ' . $unique->name . '(');
         } else {
             $b->append('new self(');
         }
         if ($member->value) {
             $this->emitOne($b, $member->value);
         } else {
             $b->append($i);
         }
         $b->append(', \'' . $member->name . '\');');
     }
     $b->append('}');
     // Finish
     $b->append('}');
     $this->leave();
     $this->registerClass($b, $declaration, $thisType->name());
     array_shift($this->properties);
     array_shift($this->metadata);
     // Register type info
     $this->types[0]->name = $thisType->name();
     $this->types[0]->kind = Types::ENUM_KIND;
     $this->types[0]->literal = $this->declaration($declaration);
     $this->types[0]->parent = $parentType;
     $this->types[0]->modifiers = $declaration->modifiers;
 }