/**
  * 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];
         }
     }
 }
Пример #2
0
 /**
  * Prints methods - static first, rest then
  *
  * @param   lang.reflect.Method[] methods
  */
 protected static function printMethods(array $methods)
 {
     $i = 0;
     foreach ($methods as $method) {
         if (!Modifiers::isStatic($method->getModifiers())) {
             continue;
         }
         Console::writeLine('  ', $method);
         $i++;
     }
     $i && Console::writeLine();
     $i = 0;
     foreach ($methods as $method) {
         if (Modifiers::isStatic($method->getModifiers())) {
             continue;
         }
         Console::writeLine('  ', $method);
         $i++;
     }
 }
Пример #3
0
 /**
  * Convert value based on type
  *
  * @param   lang.Type type
  * @param   [:var] value
  * @return  var
  */
 public function unmarshal($type, $value)
 {
     if (null === $type || $type->equals(Type::$VAR)) {
         // No conversion
         return $value;
     } else {
         if (null === $value) {
             // Valid for any type
             return null;
         } else {
             if ($type instanceof Primitive) {
                 return $type->cast($this->valueOf($value));
             } else {
                 if ($type->equals(XPClass::forName('util.Date'))) {
                     return $type->newInstance($value);
                 } else {
                     if ($type instanceof XPClass) {
                         if ($type->isInstance($value)) {
                             return $value;
                         }
                         foreach ($this->marshallers->keys() as $t) {
                             if ($t->isAssignableFrom($type)) {
                                 return $this->marshallers[$t]->unmarshal($type, $value, $this);
                             }
                         }
                         // Check if a public static valueOf() method exists
                         if ($type->hasMethod('valueOf')) {
                             $valueOf = $type->getMethod('valueOf');
                             if (Modifiers::isStatic($valueOf->getModifiers()) && Modifiers::isPublic($valueOf->getModifiers())) {
                                 if (1 === $valueOf->numParameters()) {
                                     return $valueOf->invoke(null, [$this->unmarshal($this->paramType($valueOf->getParameter(0)), $value)]);
                                 } else {
                                     $param = 0;
                                     $args = [];
                                     foreach ($this->iterableOf($value) as $value) {
                                         $args[] = $this->unmarshal($this->paramType($valueOf->getParameter($param++)), $value);
                                     }
                                     return $valueOf->invoke(null, $args);
                                 }
                             }
                         }
                         // Generic approach
                         $return = $type->newInstance();
                         foreach ($this->iterableOf($value) as $name => $value) {
                             foreach ($this->variantsOf($name) as $variant) {
                                 if ($type->hasField($variant)) {
                                     $field = $type->getField($variant);
                                     $m = $field->getModifiers();
                                     if ($m & MODIFIER_STATIC) {
                                         continue;
                                     } else {
                                         if ($m & MODIFIER_PUBLIC) {
                                             if (null !== ($fType = $field->getType())) {
                                                 $field->set($return, $this->unmarshal($fType, $value));
                                             } else {
                                                 $field->set($return, $value);
                                             }
                                             continue 2;
                                         }
                                     }
                                 }
                                 if ($type->hasMethod('set' . $variant)) {
                                     $method = $type->getMethod('set' . $variant);
                                     if ($method->getModifiers() & MODIFIER_PUBLIC) {
                                         if (null !== ($param = $method->getParameter(0))) {
                                             $method->invoke($return, [$this->unmarshal($param->getType(), $value)]);
                                         } else {
                                             $method->invoke($return, [$value]);
                                         }
                                         continue 2;
                                     }
                                 }
                             }
                         }
                         return $return;
                     } else {
                         if ($type instanceof \lang\ArrayType) {
                             $return = [];
                             foreach ($this->iterableOf($value) as $element) {
                                 $return[] = $this->unmarshal($type->componentType(), $element);
                             }
                             return $return;
                         } else {
                             if ($type instanceof \lang\MapType) {
                                 $return = [];
                                 foreach ($this->iterableOf($value) as $key => $element) {
                                     $return[$key] = $this->unmarshal($type->componentType(), $element);
                                 }
                                 return $return;
                             } else {
                                 if ($type->equals(Type::$ARRAY)) {
                                     $return = [];
                                     foreach ($this->iterableOf($value) as $key => $element) {
                                         $return[$key] = $element;
                                     }
                                     return $return;
                                 } else {
                                     throw new \lang\FormatException('Cannot convert to ' . \xp::stringOf($type));
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
 }
 public function staticModifier()
 {
     $this->assertTrue(\lang\reflect\Modifiers::isStatic(MODIFIER_STATIC));
 }
Пример #5
0
 /**
  * Generates code for (re)implementation of the (abstract) class methods
  * of the base class.
  *
  * @param lang.XPClass baseClass
  */
 private function generateBaseClassMethods($baseClass)
 {
     $bytes = '';
     $reservedMethods = \lang\XPClass::forName('lang.Generic')->getMethods();
     $reservedMethodNames = array_map(function ($i) {
         return $i->getName();
     }, $reservedMethods);
     foreach ($baseClass->getMethods() as $m) {
         // do not overwrite reserved methods, omit static methods
         if (in_array($m->getName(), $reservedMethodNames) || Modifiers::isStatic($m->getModifiers())) {
             continue;
         }
         // Check for already declared methods, do not redeclare them
         // implement abstract methods
         if ($this->overwriteExisting || ($m->getModifiers() & 2) == 2) {
             if (isset($this->added[$m->getName()])) {
                 continue;
             }
             $this->added[$m->getName()] = true;
             $bytes .= $this->generateMethod($m);
         }
     }
     return $bytes;
 }
Пример #6
0
 /**
  * Resolve a static call. Return true if the target is a function
  * (e.g. key()), a xp.compiler.types.Method instance if it's a static 
  * method (Map::key()).
  *
  * @param   string name
  * @return  var
  */
 public function resolveStatic($name)
 {
     foreach ($this->statics[0] as $lookup => $type) {
         if (true === $type && $this->importer->hasFunction($lookup, $name)) {
             return true;
         } else {
             if ($type instanceof Types && $type->hasMethod($name)) {
                 $m = $type->getMethod($name);
                 if (\lang\reflect\Modifiers::isStatic($m->modifiers)) {
                     return $m;
                 }
             }
         }
     }
     return null;
 }
Пример #7
0
 /**
  * Emit a class field
  *
  * @param   xp.compiler.emit.Buffer b
  * @param   xp.compiler.ast.FieldNode field
  */
 protected function emitField($b, $field)
 {
     $static = Modifiers::isStatic($field->modifiers);
     // See whether an initialization is necessary
     $initializable = false;
     if ($field->initialization) {
         if ($field->initialization instanceof Resolveable) {
             try {
                 $init = $field->initialization->resolve();
                 $initializable = true;
             } catch (\lang\IllegalStateException $e) {
                 $this->warn('R100', $e->getMessage(), $field->initialization);
                 $initializable = false;
             }
         }
         if (!$initializable) {
             $init = new Buffer('', $b->line);
             $this->enter(new MethodScope(new MethodNode(['name' => '<init>'])));
             if ($static) {
                 $variable = new StaticMemberAccessNode(new TypeName('self'), $field->name);
             } else {
                 $variable = new MemberAccessNode(new VariableNode('this'), $field->name);
                 $this->scope[0]->setType(new VariableNode('this'), $this->scope[0]->declarations[0]->name);
             }
             $this->emitOne($init, new AssignmentNode(['variable' => $variable, 'expression' => $field->initialization, 'op' => '=']));
             $init->append(';');
             $type = $this->scope[0]->typeOf($variable);
             $this->leave();
             $this->inits[0][$static][] = $init;
             $this->scope[0]->setType($field->initialization, $type);
         }
         // If the field is "var" and we have an initialization, determine
         // the type from there
         if ($field->type->isVariable()) {
             $field->type = $this->scope[0]->typeOf($field->initialization);
         }
     }
     switch ($field->modifiers & (MODIFIER_PUBLIC | MODIFIER_PROTECTED | MODIFIER_PRIVATE)) {
         case MODIFIER_PRIVATE:
             $b->append('private ');
             break;
         case MODIFIER_PROTECTED:
             $b->append('protected ');
             break;
         default:
             $b->append('public ');
             break;
     }
     $static && $b->append('static ');
     $b->append('$' . $field->name);
     $initializable && $b->append('= ')->append(var_export($init, true));
     $b->append(';');
     // Meta data. Add field metadata (type, stored in @type annotation, see
     // lang.reflect.Field and lang.XPClass::detailsForField()).
     $type = $this->resolveType($field->type);
     $this->metadata[0][0][$field->name] = $this->meta($field->comment, $field->annotations, [DETAIL_ANNOTATIONS => ['type' => $type->name()]]);
     // Register type information
     $f = new Field();
     $f->name = $field->name;
     $f->type = new TypeName($type->name());
     $f->modifiers = $field->modifiers;
     $this->types[0]->addField($f);
 }