/** * Compile class from source and return compiled type * * @param string src * @return xp.compiler.types.TypeReflection */ protected function compile($src) { $unique = 'FixtureClassFor' . $this->getClass()->getSimpleName() . ucfirst($this->name); $r = $this->emitter->emit(Syntax::forName('xp')->parse(new MemoryInputStream(sprintf($src, $unique))), $this->scope); $r->executeWith([]); return new TypeReflection(\lang\XPClass::forName($r->type()->name())); }
/** * Constructor * * @param io.File file * @param xp.compiler.Syntax s Syntax to use, determined via source file's syntax otherwise * @throws lang.IllegalArgumentException in case the syntax cannot be determined */ public function __construct(File $file, Syntax $s = null) { $this->file = $file; try { $this->syntax = $s ?: Syntax::forName($this->file->getExtension()); } catch (IllegalArgumentException $e) { throw new IllegalArgumentException('Cannot determine syntax for "' . $this->file->getFileName() . '"', $e); } }
/** * Get parse tree for a given qualified class name by looking it * up in the source path. * * @param string qualified * @return xp.compiler.io.Source */ public function findClass($qualified) { $name = DIRECTORY_SEPARATOR . strtr($qualified, '.', DIRECTORY_SEPARATOR); foreach ($this->sourcePaths as $path) { foreach (Syntax::available() as $ext => $syntax) { if (!file_exists($uri = $path . $name . '.' . $ext)) { continue; } return new FileSource(new File($uri), $syntax); // FIXME: Use class loader / resources } } return null; }
/** * Returns file targets from a folder * * @param string uri * @param bool recursive * @return xp.compiler.io.FileSource[] */ protected static function fromFolder($uri, $recursive) { static $filter = null; if (null === $filter) { $filter = new AnyOfFilter(); foreach (Syntax::available() as $ext => $syntax) { $filter->add(new ExtensionEqualsFilter($ext)); } } $files = []; $it = new FilteredIOCollectionIterator(new FileCollection($uri), $filter, $recursive); foreach ($it as $element) { $files[] = new FileSource(new File($element->getURI())); } return $files; }
/** * Constructor * * @param string syntax * @param string fragment * @param bool return whether to add return statement if not present in fragment * @throws lang.IllegalArgumentException */ public function __construct($syntax, $fragment, $return = false) { $this->syntax = \xp\compiler\Syntax::forName($syntax); // Add "return" statement if not present. TODO: If other languages are added // in which the string "return" is not the return statement, then this needs // to be rewritten $this->fragment = rtrim($fragment, ';') . ';'; if ($return && !(strstr($fragment, 'return ') || strstr($fragment, 'return;'))) { $this->fragment = 'return ' . $this->fragment; } // Verify template $name = $this->syntax->name(); if (!isset(self::$TEMPLATE[$name])) { throw new \lang\IllegalArgumentException('No command line code template for syntax "' . $name . '"'); } $this->template = self::$TEMPLATE[$name]; }
/** * Define class from a given name and source * * @param string type * @param string class * @param var parent either a string or a lang.XPClass * @param string src * @param string[] imports * @return lang.XPClass */ protected static function define($type, $class, $parent, $src, array $imports = []) { $emitter = self::emitter(); $emitter->clearMessages(); $syntax = Syntax::forName('xp'); $class = 'Source' . $class; $scope = new TaskScope(new CompilationTask(new FileSource(new File(__FILE__), $syntax), new NullDiagnosticListener(), new FileManager(), $emitter)); // Parent class if ($parent instanceof XPClass) { $extends = (new XPClass(self::class))->getPackage()->getName() . '.' . $parent->getName(); $scope->addResolved($extends, new TypeReflection($parent)); $scope->addTypeImport($extends); } else { $extends = $parent; } // Emit $r = $emitter->emit($syntax->parse(new MemoryInputStream(implode("\n", $imports) . ' public ' . $type . ' ' . $class . ' ' . ($extends ? ' extends ' . $extends : '') . $src), $class), $scope); \xp::gc(); // DEBUG $r->writeTo(\util\cmd\Console::$out->getStream()); $r->executeWith([]); return XPClass::forName($r->type()->name()); }
/** * Parse source * * @param string $source * @return xp.compiler.ast.ParseTree */ protected function parse($source) { return Syntax::forName('php')->parse(new \io\streams\MemoryInputStream($source), $this->name); }
/** * Parse sourcecode * * @param string $source * @return xp.compiler.ast.TypeDeclarationNode */ private function parse($source) { return Syntax::forName('xp')->parse(new MemoryInputStream($source))->declaration; }
/** * Returns a given package's contents * * @param string $package * @return string[] */ public function packageContents($package) { static $syntaxes = ''; // Calculate syntax regex for matching on files if (!$syntaxes) { foreach (Syntax::available() as $syntax) { $syntaxes .= '|' . $syntax->name(); } $syntaxes = '/\\.(' . substr($syntaxes, 1) . ')$/'; } // List directory contents, replacing compileable source files with // class file names. These of course don't exist yet, but will be // compiled on demand $return = []; $dir = strtr($package, '.', DIRECTORY_SEPARATOR); foreach ($this->files->getSourcePaths() as $path) { if (!is_dir($d = $path . $dir . DIRECTORY_SEPARATOR)) { continue; } $handle = opendir($d); while ($e = readdir($handle)) { if ('.' === $e || '..' === $e) { continue; } else { if (is_dir($d . $e)) { $return[] = $e . '/'; } else { if (strstr($e, \xp::CLASS_FILE_EXT)) { $return[] = $e; } else { if ('module.xp' === $e) { $return[] = $e; } else { $return[] = preg_replace($syntaxes, \xp::CLASS_FILE_EXT, $e); } } } } } closedir($handle); } return $return; }
/** * Sets up this testcase * * @return void */ public function setUp() { $this->fixture = new TaskScope(new CompilationTask(new FileSource(new File(__FILE__), Syntax::forName('xp')), new NullDiagnosticListener(), new FileManager(), new V54Emitter())); }
public static function useXpSyntax() { self::$syntax = Syntax::forName('xp'); }
/** * Compile class from source and return compiled type * * @param string src * @return xp.compiler.types.Types */ protected function compile($src) { $r = $this->emitter->emit(Syntax::forName('xp')->parse(new MemoryInputStream($src)), $this->scope); return $r->type(); }
/** * Compile class from source and return compiled type * * @param string src * @return xp.compiler.types.Types */ protected function compile($src) { $r = $this->emitter->emit(Syntax::forName('xp')->parse(new MemoryInputStream($src)), $this->scope); $r->executeWith([]); return XPClass::forName($r->type()->name()); }
/** * Returns a subtask (overloaded) * * @param var arg either a xp.compiler.io.Source or a fully qualified class name * @return xp.compiler.task.CompilationTask * @throws lang.IllegalArgumentException for argument type mismatches * @throws lang.ElementNotFoundException if class given and class cannot be found */ public function newSubTask($arg) { if ($arg instanceof Source) { $source = $arg; } else { if (is_string($arg)) { if (!($source = $this->manager->findClass($arg))) { throw new ElementNotFoundException(sprintf("Cannot find class %s, tried {*.%s} in [\n %s\n]", $arg, implode(', *.', array_keys(Syntax::available())), implode("\n ", $this->manager->getSourcePaths()))); } } else { throw new \lang\IllegalArgumentException('Expected either a string or a Source object'); } } return new self($source, $this->listener, $this->manager, $this->emitter, $this->done); }