예제 #1
0
 protected function generateSourceCode(ParsedType $type, SourceBuffer $buffer, \SplFileInfo $file)
 {
     $extends = array_map(function ($t) {
         return '\\' . ltrim($t, '\\');
     }, $type->getExtends());
     $extends = empty($extends) ? '' : implode(', ', $extends);
     $implements = ['\\' . MergedSourceInterface::class];
     // Double inclusion safeguard:
     if ($type->isClass()) {
         $safe1 = sprintf(' if(!class_exists(%s, false)) { ', var_export($type->getName(), true));
         $safe2 = ' } ';
     } elseif ($type->isInterface()) {
         $safe1 = sprintf(' if(!interface_exists(%s, false)) { ', var_export($type->getName(), true));
         $safe2 = ' } ';
     } else {
         $safe1 = sprintf(' if(!trait_exists(%s, false)) { ', var_export($type->getName(), true));
         $safe2 = ' } ';
     }
     $generator = new SourceGenerator($buffer);
     $generator->populateTypeMarker($type, ParsedType::MARKER_INTRODUCED_INTERFACES, implode(', ', $implements));
     $generator->populateTypeMarker($type, ParsedType::MARKER_INTRODUCED_NAME, $type->getLocalName());
     $generator->populateTypeMarker($type, ParsedType::MARKER_INTRODUCED_SUPERCLASS, $extends);
     $generator->populateTypeMarker($type, ParsedType::MARKER_INTRODUCED_PREPENDED_CODE, $safe1);
     $generator->populateTypeMarker($type, ParsedType::MARKER_INTRODUCED_EXTERNAL_CODE, $safe2);
     $code = trim($generator->generateCode($file->getPathname(), dirname($file->getPathname())));
     $code = preg_replace("'^<\\?(?:php)?'i", '', $code) . "\n";
     return $code;
 }
예제 #2
0
 public function instrumentFile($sourceFile)
 {
     if ($this->manifest === NULL) {
         $this->manifest = $this->kernel->getManifest();
     }
     $parsedFile = $this->manifest->getFile($sourceFile);
     $storage = $parsedFile->getStorage();
     $generator = new SourceGenerator($parsedFile->getBuffer());
     foreach ($storage->getTypes() as $parsedType) {
         $fields = $storage->getFields($parsedType);
         $methods = $storage->getMethods($parsedType);
         $typeInfo = new ParsedTypeInfo($parsedType, $fields, $methods);
         $instrumentation = new Instrumentation($this->manifest);
         $instrumentation->introduceInterface('KoolKode\\K2\\Instrument\\KoolTypeInterface');
         if ($typeInfo->isClass()) {
             // Introduce instance type LSB marker:
             $instrumentation->introduceCode('protected static $K2TypeName = __CLASS__;');
             // Introduce helper method trait:
             $instrumentation->introduceTrait('KoolKode\\K2\\Instrument\\KoolTypeTrait');
             // Implement original source file lookup:
             $introduced = ' public static function K2GetSourceFile() { return ';
             $introduced .= var_export($sourceFile, true) . '; }';
             $instrumentation->introduceCode($introduced);
             // Implement namespace context lookup:
             $introduced = ' public static function K2GetNamespaceContext() { ';
             $introduced .= 'static $ctx; if($ctx === NULL) { ';
             $introduced .= '$ctx = ' . $typeInfo->getNamespaceContext()->compile() . '; ';
             $introduced .= '} return $ctx; }';
             $instrumentation->introduceCode($introduced);
             // Extended class introduction:
             $extends = $parsedType->getExtends();
             if (!empty($extends)) {
                 $generator->populateTypeMarker($parsedType, ParsedType::MARKER_INTRODUCED_SUPERCLASS, '\\' . array_shift($extends));
             }
             $generator->populateTypeMarker($parsedType, ParsedType::MARKER_INTRODUCED_PREPENDED_CODE, ' if(!class_exists(' . var_export($parsedType->getName(), true) . ', false)) { ');
         } elseif ($typeInfo->isInterface()) {
             $generator->populateTypeMarker($parsedType, ParsedType::MARKER_INTRODUCED_EXTENDS, implode(', ', $parsedType->getExtends()));
             $generator->populateTypeMarker($parsedType, ParsedType::MARKER_INTRODUCED_PREPENDED_CODE, ' if(!interface_exists(' . var_export($parsedType->getName(), true) . ', false)) { ');
         } elseif ($typeInfo->isTrait()) {
             $generator->populateTypeMarker($parsedType, ParsedType::MARKER_INTRODUCED_PREPENDED_CODE, ' if(!trait_exists(' . var_export($parsedType->getName(), true) . ', false)) { ');
         }
         foreach ($this->instrumentors as $instrumentor) {
             $instrumentor->instrument($typeInfo, $instrumentation);
         }
         if ($instrumentation->hasInitializationCode()) {
             $this->buildConstructor($typeInfo, $instrumentation);
         }
         $traits = $instrumentation->getIntroducedTraits();
         $traitCode = empty($traits) ? '' : 'use ' . implode(', ', $traits) . '; ';
         $generator->populateTypeMarker($parsedType, ParsedType::MARKER_INTRODUCED_NAME, $typeInfo->getLocalName());
         $generator->populateTypeMarker($parsedType, ParsedType::MARKER_INTRODUCED_INTERFACES, implode(', ', $instrumentation->getIntroducedInterfaces()));
         $generator->populateTypeMarker($parsedType, ParsedType::MARKER_INTRODUCED_CODE, $traitCode . $instrumentation->getIntroducedCode());
         $generator->populateTypeMarker($parsedType, ParsedType::MARKER_INTRODUCED_EXTERNAL_CODE, ' } ' . $instrumentation->getAppendedCode());
         foreach ($typeInfo->getMethods() as $methodInfo) {
             $methodIns = $instrumentation->getMethodInstrumentation($methodInfo);
             if ($methodIns->count()) {
                 $generator->populateMethodMarker($parsedType, $methodInfo->getParsedMethod(), ParsedMethod::MARKER_PREPENDED_CODE, $methodIns->getPrependedCode());
                 $generator->populateMethodMarker($parsedType, $methodInfo->getParsedMethod(), ParsedMethod::MARKER_APPENDED_CODE, $methodIns->getAppendedCode());
             }
         }
     }
     return $generator->generateCode($sourceFile, dirname($sourceFile));
 }