/**
  * 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)
 {
     $access = \cast($node, 'xp.compiler.ast.MemberAccessNode');
     // Verify type
     // * var: Might have method
     // * primitive, array, map, int: Definitely don't have fields
     $type = $scope->typeOf($access->target);
     if ($type->isVariable()) {
         return ['T203', 'Member access (var).' . $access->name . '() verification deferred until runtime'];
     } else {
         if (!$type->isClass()) {
             return ['T305', 'Using member access on unsupported type ' . $type->compoundName()];
         }
     }
     // Verify target method exists
     $target = new \xp\compiler\types\TypeInstance($scope->resolveType($type));
     if ($target->hasField($access->name)) {
         $member = $target->getField($access->name);
     } else {
         if ($target->hasProperty($access->name)) {
             $member = $target->getProperty($access->name);
         } else {
             return ['T404', 'No such field $' . $access->name . ' in ' . $target->name()];
         }
     }
     // Verify visibility
     if (!($member->modifiers & MODIFIER_PUBLIC)) {
         $enclosing = $scope->resolveType($scope->declarations[0]->name);
         if ($member->modifiers & MODIFIER_PRIVATE && !$enclosing->equals($target) || $member->modifiers & MODIFIER_PROTECTED && !($enclosing->equals($target) || $enclosing->isSubclassOf($target))) {
             return ['T403', sprintf('Accessing %s %s::$%s from %s', implode(' ', \lang\reflect\Modifiers::namesOf($member->modifiers)), $target->name(), $member->name, $enclosing->name())];
         }
     }
 }
Beispiel #2
0
 /**
  * Resolves a class member, which is either a field, a class constant
  * or the `ClassName::class` syntax, which returns the class' literal.
  *
  * @param  lang.XPClass $class
  * @param  var[] $token A token as returned by `token_get_all()`
  * @param  string $context
  * @return var
  */
 protected function memberOf($class, $token, $context)
 {
     if (T_VARIABLE === $token[0]) {
         $field = $class->getField(substr($token[1], 1));
         $m = $field->getModifiers();
         if ($m & MODIFIER_PUBLIC) {
             return $field->get(null);
         } else {
             if ($m & MODIFIER_PROTECTED && $class->isAssignableFrom($context)) {
                 return $field->setAccessible(true)->get(null);
             } else {
                 if ($m & MODIFIER_PRIVATE && $class->getName() === $context) {
                     return $field->setAccessible(true)->get(null);
                 } else {
                     throw new IllegalAccessException(sprintf('Cannot access %s field %s::$%s', implode(' ', Modifiers::namesOf($m)), $class->getName(), $field->getName()));
                 }
             }
         }
     } else {
         if (T_CLASS === $token[0]) {
             return $class->literal();
         } else {
             return $class->getConstant($token[1]);
         }
     }
 }
Beispiel #3
0
 /**
  * Creates a string representation of this method
  *
  * @return  string
  */
 public function toString()
 {
     $signature = '';
     foreach ($this->parameters as $parameter) {
         $signature .= ', ' . $parameter->toString();
     }
     return sprintf('%s<%s __construct(%s)>', nameof($this), implode(' ', \lang\reflect\Modifiers::namesOf($this->modifiers)), substr($signature, 2));
 }
Beispiel #4
0
 /**
  * Creates a string representation of this Operator
  *
  * @return  string
  */
 public function toString()
 {
     $signature = '';
     foreach ($this->parameters as $parameter) {
         $signature .= ', ' . $parameter->compoundName();
     }
     return sprintf('%s<%s %s %s(%s)>', nameof($this), implode(' ', \lang\reflect\Modifiers::namesOf($this->modifiers)), $this->returns->compoundName(), $this->symbol, substr($signature, 2));
 }
 /**
  * Executes this check
  *
  * @param   xp.compiler.types.TypeName 
  * @param   string name method name
  * @param   xp.compiler.types.Scope scope
  * @return  string[] error or null
  */
 protected function verifyMethod($type, $name, $scope)
 {
     // Verify target method exists
     $target = new \xp\compiler\types\TypeInstance($scope->resolveType($type));
     if (!$target->hasMethod($name)) {
         return ['T404', 'No such method ' . $name . '() in ' . $target->name()];
     }
     // Verify visibility
     $method = $target->getMethod($name);
     if (!($method->modifiers & MODIFIER_PUBLIC)) {
         $enclosing = $scope->resolveType($scope->declarations[0]->name);
         if ($method->modifiers & MODIFIER_PRIVATE && !$enclosing->equals($target) || $method->modifiers & MODIFIER_PROTECTED && !($enclosing->equals($target) || $enclosing->isSubclassOf($target))) {
             return ['T403', sprintf('Invoking %s %s::%s() from %s', implode(' ', \lang\reflect\Modifiers::namesOf($method->modifiers)), $target->name(), $method->name, $enclosing->name())];
         }
     }
 }
 /**
  * Prints package
  *
  * @param   lang.reflect.Package package
  */
 protected static function printPackage($package)
 {
     Console::writeLine('package ', $package->getName(), ' {');
     // Child packages
     foreach ($package->getPackages() as $child) {
         Console::writeLine('  package ', $child->getName());
     }
     // Classes
     $order = array('interface' => array(), 'enum' => array(), 'class' => array());
     foreach ($package->getClasses() as $class) {
         $mod = $class->getModifiers();
         if ($class->isInterface()) {
             $type = 'interface';
             $mod = $mod ^ MODIFIER_ABSTRACT;
         } else {
             if ($class->isEnum()) {
                 $type = 'enum';
             } else {
                 $type = 'class';
             }
         }
         $name = self::displayNameOf($class);
         $order[$type][] = implode(' ', Modifiers::namesOf($mod)) . ' ' . $type . ' ' . self::displayNameOf($class);
     }
     foreach ($order as $type => $classes) {
         if (empty($classes)) {
             continue;
         }
         Console::writeLine();
         sort($classes);
         foreach ($classes as $name) {
             Console::writeLine('  ', $name);
         }
     }
     Console::writeLine('}');
 }
Beispiel #7
0
 /**
  * Creates a string representation of this field
  *
  * @return  string
  */
 public function toString()
 {
     return sprintf('%s<%s %s $%s>', nameof($this), implode(' ', \lang\reflect\Modifiers::namesOf($this->modifiers)), $this->type->compoundName(), $this->name);
 }
 public function staticModifierNames()
 {
     $this->assertEquals(array('public', 'static'), \lang\reflect\Modifiers::namesOf(MODIFIER_STATIC));
 }
Beispiel #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)));
 }
 protected function assertProperty($modifiers, $name, $type, $actual)
 {
     $this->assertEquals(['modifiers' => Modifiers::namesOf($modifiers), 'name' => $name, 'type' => $type], ['modifiers' => Modifiers::namesOf($actual->modifiers), 'name' => $actual->name, 'type' => $actual->type]);
 }
 public function staticModifierNames()
 {
     $this->assertEquals(['public', 'static'], Modifiers::namesOf(MODIFIER_STATIC));
 }
Beispiel #12
0
 /**
  * Emit a constructor
  *
  * @param   xp.compiler.emit.Buffer b
  * @param   xp.compiler.ast.ConstructorNode constructor
  */
 protected function emitConstructor($b, $constructor)
 {
     $b->append(implode(' ', Modifiers::namesOf($constructor->modifiers)));
     $b->append(' function __construct');
     // Begin
     $this->enter(new MethodScope($constructor));
     $this->scope[0]->setType(new VariableNode('this'), $this->scope[0]->declarations[0]->name);
     array_unshift($this->method, '__construct');
     // Meta data
     $this->metadata[0][1]['__construct'] = $this->meta($constructor->comment, $constructor->annotations, [DETAIL_ARGUMENTS => [], DETAIL_RETURNS => null, DETAIL_THROWS => []]);
     // Arguments, initializations, body
     if (null !== $constructor->body) {
         $signature = $this->emitParameters($b, (array) $constructor->parameters, '{');
         if ($this->inits[0][false]) {
             foreach ($this->inits[0][false] as $init) {
                 $b->append($init);
             }
             $this->inits[0][false] = [];
         }
         $this->emitAll($b, $constructor->body);
         $b->append('}');
     } else {
         $signature = $this->emitParameters($b, (array) $constructor->parameters, ';');
     }
     // Finalize
     array_shift($this->method);
     $this->leave();
     // Register type information
     $c = new Constructor();
     $c->parameters = $signature;
     $c->modifiers = $constructor->modifiers;
     $this->types[0]->constructor = $c;
 }