Permalink
Fetching contributors…
Cannot retrieve contributors at this time
442 lines (409 sloc) 12 KB
#! winxed
// Winxed compiler driver.
// Parses command line options, calls the compiler backend
// and eventually runs the generated program.
$load "Getopt/Obj.pbc";
$include_const "iglobals.pasm";
$include_const "libpaths.pasm";
$include_const "except_severity.pasm";
function extname(string filename, string ext)
{
// Strip a possible .winxed extension from filename,
// add ext, and return the result.
int l = length(filename);
return (l > 7 && substr(filename, -7) == ".winxed") ?
substr(filename, 0, l - 7) + ext :
filename + ext;
}
// Use the OS pmc for file operations.
function getOS()
{
var os;
try {
loadlib("os");
os = new ["OS"];
}
catch() { }
return os;
}
class WinxedDriverOptions : ["Getopt", "Obj"]
{
var name;
var options;
var opts;
function WinxedDriverOptions(var argv, int unused)
{
var options = [
[ "stage=s", "Compiler stage to use" ],
[ "c", "Compile only. Same as --target=pir" ],
[ "e=s", "Evaluate" ],
[ "o=s", "Object name" ],
[ "L=s", "Add to parrot library search path" ],
[ "I=s", "Add to parrot include search path" ],
[ "X=s", "Add to parrot dynext search path" ],
[ "debug", "Set debug mode" ],
[ "noan", "No code annotations" ],
[ "nowarn", "No warnings" ],
[ "target=s", "Set target type: pir, pbc or run. Default is run." ],
[ "help", "Show this help" ],
[ "version", "Show version and exit" ]
];
self.options = options;
for (var o in options)
self.push_string(o[0]);
self.notOptStop(1);
self.name = argv.shift();
self.opts = self.get_options(argv);
}
function getbool(string option)
{
var opts = self.opts;
var value = opts[option];
return value != null;
}
function getstring(string option, string default[optional])
{
var opts = self.opts;
var value = opts[option];
return value != null ? string(value) : default;
}
function showhelp()
{
say("Usage: ", self.name, " [options] [program] [args]");
say(" Available options:");
int l= 0;
int i;
var o;
for (o in self.options) {
i = length(o[0]);
if (i > l)
l = i;
}
l = l + 4;
string filler = " ";
for (o in self.options) {
string s= o[0];
if (length(s) > 1 && substr(s, 1, 1) != "=")
s = "--" + s;
else
s = "-" + s;
say(" ", s, substr(filler, 0, l - length(s)), "-> ", o[1]);
}
}
}
function driver_main(var argv)
{
const int
DEFAULT_STAGE = 3,
CUSTOM_STAGE = -1;
var options = new WinxedDriverOptions(argv, 0);
int help = options.getbool("help");
int version = options.getbool("version");
string opt_stage = options.getstring("stage");
int compileonly = options.getbool("c");
int debug = options.getbool("debug");
int noan = options.getbool("noan");
int nowarn = options.getbool("nowarn");
string eval = options.getstring("e");
string libs = options.getstring("L");
string incs = options.getstring("I");
string dyns = options.getstring("X");
string obj = options.getstring("o", "");
string target = options.getstring("target");
if (help) {
options.showhelp();
return;
}
var env = new [ "Env" ];
// Path for stage pbc files
string winxedpath = env["WINXED_PATH"];
int stage = DEFAULT_STAGE;
if (opt_stage == null) {
string envstage = env["WINXED_STAGE"];
if (envstage != "")
opt_stage = envstage;
}
if (opt_stage != null) {
if (opt_stage.is_integer(opt_stage))
stage = opt_stage;
else
stage = CUSTOM_STAGE;
}
if (version && (stage == 0 || stage == 1)) {
cry("--version not available in stages 0 and 1");
exit(1);
}
const int
TargetDefault = 0,
TargetRun = 1,
TargetPir = 2,
TargetPbc = 3,
TargetConst = 4;
int targettype = TargetDefault;
if (target != null) {
switch (target) {
case "pir":
targettype = TargetPir;
break;
case "pbc":
targettype = TargetPbc;
break;
case "run":
targettype = TargetRun;
break;
case "include":
targettype = TargetConst;
break;
default:
throw "Invalid target: " + target;
}
}
if (compileonly) {
if (targettype != TargetDefault)
throw "Conflicting options";
targettype = TargetPir;
}
if (targettype == TargetDefault)
targettype = TargetRun;
string srcfile;
if (eval == null && ! version) {
int argc= argv;
if (argc < 1) {
say("ERROR: No program specified");
options.showhelp();
return;
}
srcfile = argv.shift();
}
string pirfile;
if (obj != "" && targettype == TargetPir || targettype == TargetConst)
pirfile = obj;
else {
if (eval != null)
pirfile = "__eval__.pir";
else
pirfile = extname(srcfile, ".pir");
}
var os = getOS();
// Call backend compiler
string winxedbin;
switch (stage) {
case 0:
winxedbin = "winxedst0";
break;
case 1:
winxedbin = "winxedst1";
break;
case 2:
winxedbin = "winxedst2";
break;
case 3:
winxedbin = "winxedst3";
break;
case CUSTOM_STAGE:
winxedbin = opt_stage;
break;
default:
throw "Invalid stage " + stage + ". Must be 0, 1, 2 or 3 .";
}
int retval = 0;
int use_pbc = stage > 1 || stage == CUSTOM_STAGE;
if (use_pbc) {
// Set the -I value now so the $include directive can use it.
if (incs != null) {
var interp = getinterp();
var lpaths = interp[IGLOBALS_LIB_PATHS];
var pathlib = lpaths[PARROT_LIB_PATH_INCLUDE];
pathlib.push(string(incs));
}
try {
load_bytecode(winxedbin + ".pbc");
} catch () { }
var compiler = compreg("winxed");
if (compiler == null) {
if (winxedpath != null && winxedpath != "") {
winxedbin = winxedpath + "/" + winxedbin;
try {
load_bytecode(winxedbin + ".pbc");
}
catch (e) {
if (__DEBUG__)
cry("Cannot load ", winxedbin, ": ", e["message"]);
}
compiler = compreg("winxed");
}
if (compiler == null)
throw "Cannot load stage " + winxedbin;
}
if (version) {
var ver = compiler.version_string();
if (ver == null)
ver = "CANNOT GET VERSION";
say(ver);
exit(0);
}
string ctarget = targettype == TargetConst ? "include" : "pir";
var opts = {
"target": ctarget,
"debug": debug,
"noan": noan,
"nowarn": nowarn
};
string pircode;
if (eval == null) {
var output;
var file;
if (pirfile == "-" &&
(targettype == TargetPir || targettype == TargetConst))
output = getstdout();
else {
file = open(pirfile, "w");
output = file;
}
opts["output"] = output;
compiler.compile_from_file(srcfile, opts:[named,flat]);
if (file != null)
file.close();
}
else {
eval = "function main[main](var argv){" + eval + ";}";
pircode = compiler.compile(eval, opts:[named,flat]);
if (pirfile == "-" &&
(targettype == TargetPir || targettype == TargetConst))
print(pircode);
else {
var file = open(pirfile, "w");
file.print(pircode);
file.close();
}
}
}
else {
string cmd[]; // Command to execute
if (stage == 1) {
cmd.push("parrot");
cmd.push("winxedst1.pbc");
}
else {
// First look in WINXED_PATH.
// If not, simple heuristic: if the compiler is in the current
// directory and has no extension, use it.
// If not, assume it's in the PATH or we are on Windows.
var check = null;
if (winxedpath != null && winxedpath != "" &&os != null) {
string checkbin = winxedpath + "/" + winxedbin;
check = os.stat(checkbin);
if (check == null) {
checkbin = winxedpath + "\\" + winxedbin + ".exe";
check = os.stat(checkbin);
}
if (check != null)
winxedbin = checkbin;
}
if (check == null) {
if (os != null)
check = os.stat(winxedbin);
if (check != null)
winxedbin = "./" + winxedbin;
}
cmd.push(winxedbin);
}
if (targettype == TargetConst)
throw "target include unavailable in stage 0";
if (debug)
cmd.push("--debug");
if (noan)
cmd.push("--noan");
if (nowarn && stage != 0)
cmd.push("--nowarn");
if (eval != null) {
cmd.push("-e");
cmd.push(eval);
}
cmd.push("-o");
cmd.push(pirfile);
if (eval == null)
cmd.push(srcfile);
retval = spawnw(cmd);
retval = (retval >> 8) & 0xFF;
}
if (retval)
exit(retval);
string runit[] = [ "parrot" ];
switch (targettype) {
case TargetRun:
// Execute result
if (libs != null) {
runit.push("-L");
runit.push(libs);
}
if (incs != null) {
runit.push("-I");
runit.push(incs);
}
if (dyns != null) {
runit.push("-X");
runit.push(dyns);
}
runit.push(pirfile);
for (string a in argv)
runit.push(a);
retval = spawnw(runit);
// Delete the generated pir file.
try {
os.rm(pirfile);
}
catch (e)
{
cry("WARNING: cannot delete temporary PIR file: ", e["message"]);
}
break;
case TargetPbc:
// Call parrot to ceate the pbc
string objfile;
if (obj != "")
objfile = obj;
else
objfile = extname(srcfile, ".pbc");
runit.push("-o");
runit.push(objfile);
runit.push(pirfile);
retval = spawnw(runit);
// Delete the generated pir file.
try {
os.rm(pirfile);
}
catch (e)
{
cry("WARNING: cannot delete temporary PIR file: ", e["message"]);
}
break;
default:
; // Otherwise, nothing to do.
}
retval = (retval >> 8) & 0xFF;
exit(retval);
}
function main [main] (var argv)
{
int r;
try {
driver_main(argv);
}
catch (e) {
int severity = e["severity"];
if (severity == EXCEPT_EXIT) {
int exit_code = e["exit_code"];
exit(exit_code);
}
int type = e["type"];
var payload = e["payload"];
if (type == __WINXED_ERROR__ && payload != null)
cry(payload.filename, ":", payload.line, ": ", payload.message);
else
cry(e["message"]);
r = 1;
}
exit(r);
}
// End