Skip to content
This repository was archived by the owner on Sep 9, 2019. It is now read-only.

Commit b42c03d

Browse files
committed
Implement "xp compile [sources]"
1 parent a37d1d7 commit b42c03d

File tree

3 files changed

+215
-0
lines changed

3 files changed

+215
-0
lines changed

ChangeLog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ XP Compiler ChangeLog
55

66
## 6.0.0 / ????-??-??
77

8+
* Implemented "compile" subcommand for new xp-framework/rfc#303 runners
9+
(@thekid)
810
* **Heads up**: Removed support for extension methods at runtime. They no
911
longer exist in XP7 as per xp-framework/rfc#298
1012
(@thekid)

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"xp-framework/rdbms": "^6.0",
2121
"xp-framework/http": "^6.0"
2222
},
23+
"bin": ["bin/xp.xp-lang.compiler.compile"],
2324
"autoload" : {
2425
"files" : ["src/main/php/autoload.php"]
2526
}
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
<?php namespace xp\compiler;
2+
3+
use io\File;
4+
use io\Folder;
5+
use io\collections\FileCollection;
6+
use io\collections\iterate\FilteredIOCollectionIterator;
7+
use io\collections\iterate\ExtensionEqualsFilter;
8+
use io\collections\iterate\AnyOfFilter;
9+
use util\Properties;
10+
use lang\ResourceProvider;
11+
use lang\reflect\Package;
12+
use xp\compiler\diagnostic\DefaultDiagnosticListener;
13+
use xp\compiler\diagnostic\QuietDiagnosticListener;
14+
use xp\compiler\diagnostic\VerboseDiagnosticListener;
15+
use xp\compiler\io\FileSource;
16+
use xp\compiler\io\CommandLineSource;
17+
use xp\compiler\io\FileManager;
18+
use util\log\Logger;
19+
use util\log\LogCategory;
20+
use util\log\LogLevel;
21+
use util\log\ConsoleAppender;
22+
use util\cmd\Console;
23+
use lang\ClassLoader;
24+
25+
/**
26+
* Compiles and optimizes PHP and XP language source code
27+
* ========================================================================
28+
*
29+
* - Compile a single file, writing output to **Test.class.php**:
30+
* ```sh
31+
* $ xp compile Test.xp
32+
* ```
33+
* - Compile all files in the given folders, write output to **target/**:
34+
* ```sh
35+
* $ xp compile -o target src/main/xp src/test/xp
36+
* ```
37+
* - Fast compilation, ignores missing apidocs, no optimization
38+
* ```sh
39+
* $ xp compile -p rad Test.php
40+
* ```
41+
* - Emit sourcecode compatible with PHP 5.4 (default is *PHP 5.5*):
42+
* ```sh
43+
* $ xp compile -E php5.4 Test.xp
44+
* ```
45+
*
46+
* The option `-v` will show verbose diagnostics, `-q` will suppress all
47+
* output except errors.
48+
*
49+
* Supports PHP [*.php*] and XP [*.xp*] syntax.
50+
*/
51+
class CompileRunner extends \lang\Object {
52+
53+
static function __static() {
54+
ResourceProvider::getInstance(); // Register res:// protocol
55+
}
56+
57+
/**
58+
* Displays usage
59+
*
60+
* @return int exitcode
61+
*/
62+
protected static function usage() {
63+
Console::$err->writeLine('XP Compiler: `xp compile [sources]`. xp help compile has the details!');
64+
return 1;
65+
}
66+
67+
/**
68+
* Returns file targets from a folder
69+
*
70+
* @param string uri
71+
* @param bool recursive
72+
* @return xp.compiler.io.FileSource[]
73+
*/
74+
protected static function fromFolder($uri, $recursive) {
75+
static $filter= null;
76+
77+
if (null === $filter) {
78+
$filter= new AnyOfFilter();
79+
foreach (Syntax::available() as $ext => $syntax) {
80+
$filter->add(new ExtensionEqualsFilter($ext));
81+
}
82+
}
83+
84+
$files= [];
85+
$it= new FilteredIOCollectionIterator(new FileCollection($uri), $filter, $recursive);
86+
foreach ($it as $element) {
87+
$files[]= new FileSource(new File($element->getURI()));
88+
}
89+
return $files;
90+
}
91+
92+
/**
93+
* Creates and returns a file manager which publically exposed compiled
94+
* types via the "declared" member, indexed by their name.
95+
*
96+
* @return xp.compiler.io.FileManager
97+
*/
98+
protected static function declaringFileManager() {
99+
return newinstance('xp.compiler.io.FileManager', [], '{
100+
public $declared= [];
101+
public function write($r, \io\File $target) {
102+
$r->executeWith([]);
103+
$this->declared[]= \lang\XPClass::forName($r->type()->name());
104+
}
105+
}');
106+
}
107+
108+
/**
109+
* Entry point method
110+
*
111+
* @param string[] args
112+
*/
113+
public static function main(array $args) {
114+
if (empty($args)) {
115+
return self::usage();
116+
}
117+
118+
foreach (ClassLoader::getLoaders() as $loader) {
119+
if ($loader instanceof JitClassLoader) ClassLoader::removeLoader($loader);
120+
}
121+
122+
// Set up compiler
123+
$compiler= new Compiler();
124+
$manager= new FileManager();
125+
$manager->setSourcePaths(\xp::$classpath);
126+
127+
// Handle arguments
128+
$profiles= ['default'];
129+
$emitter= 'php5.5';
130+
$result= function($success) { return $success ? 0 : 1; };
131+
$files= [];
132+
$listener= new DefaultDiagnosticListener(Console::$out);
133+
for ($i= 0, $s= sizeof($args); $i < $s; $i++) {
134+
if ('-?' === $args[$i] || '--help' === $args[$i]) {
135+
return self::usage();
136+
} else if ('-cp' === $args[$i]) {
137+
\lang\ClassLoader::registerPath($args[++$i]);
138+
} else if ('-sp' === $args[$i]) {
139+
$manager->addSourcePath($args[++$i]);
140+
} else if ('-v' === $args[$i]) {
141+
$listener= new VerboseDiagnosticListener(Console::$out);
142+
} else if ('-q' === $args[$i]) {
143+
$listener= new QuietDiagnosticListener(Console::$out);
144+
} else if ('-t' === $args[$i]) {
145+
$levels= LogLevel::NONE;
146+
foreach (explode(',', $args[++$i]) as $level) {
147+
$levels |= LogLevel::named($level);
148+
}
149+
$compiler->setTrace(create(new LogCategory('xcc'))->withAppender(new ConsoleAppender(), $levels));
150+
} else if ('-E' === $args[$i]) {
151+
$emitter= $args[++$i];
152+
} else if ('-p' === $args[$i]) {
153+
$profiles= explode(',', $args[++$i]);
154+
} else if ('-o' === $args[$i]) {
155+
$output= $args[++$i];
156+
$folder= new Folder($output);
157+
$folder->exists() || $folder->create();
158+
$manager->setOutput($folder);
159+
} else if ('-N' === $args[$i]) {
160+
$dir= $args[++$i];
161+
$manager->addSourcePath($dir);
162+
$files= array_merge($files, self::fromFolder($dir, false));
163+
} else if (is_dir($args[$i])) {
164+
$dir= $args[$i];
165+
$manager->addSourcePath($dir);
166+
$files= array_merge($files, self::fromFolder($dir, true));
167+
} else {
168+
$files[]= new FileSource(new File($args[$i]));
169+
}
170+
}
171+
172+
// Check
173+
if (empty($files)) {
174+
Console::$err->writeLine('*** No files given (-? will show usage)');
175+
return 2;
176+
}
177+
178+
// Setup emitter
179+
sscanf($emitter, '%[^0-9]%d.%d', $language, $major, $minor);
180+
try {
181+
$emit= \lang\XPClass::forName('xp.compiler.emit.Emitter')->cast(Package::forName('xp.compiler.emit')
182+
->getPackage($language)
183+
->loadClass(($major ? ('V'.$major.$minor) : '').'Emitter')
184+
->newInstance()
185+
);
186+
} catch (\lang\ClassCastException $e) {
187+
Console::$err->writeLine('*** Not an emitter implementation: ', $e->compoundMessage());
188+
return 4;
189+
} catch (\lang\IllegalAccessException $e) {
190+
Console::$err->writeLine('*** Cannot use emitter named "', $emitter, '": ', $e->compoundMessage());
191+
return 4;
192+
} catch (\lang\Throwable $e) {
193+
Console::$err->writeLine('*** No emitter named "', $emitter, '": ', $e->compoundMessage());
194+
return 4;
195+
}
196+
197+
// Load compiler profile configurations
198+
try {
199+
$reader= new CompilationProfileReader();
200+
foreach ($profiles as $configuration) {
201+
$reader->addSource(new Properties('res://xp/compiler/'.$configuration.'.xcp.ini'));
202+
}
203+
$emit->setProfile($reader->getProfile());
204+
} catch (\lang\Throwable $e) {
205+
Console::$err->writeLine('*** Cannot load profile configuration(s) '.implode(',', $profiles).': '.$e->getMessage());
206+
return 3;
207+
}
208+
209+
// Compile files and pass return value to result handler
210+
return $result($compiler->compile($files, $listener, $manager, $emit), array_slice($args, $i + 1));
211+
}
212+
}

0 commit comments

Comments
 (0)