new object $parse_lib: $libraries;
var $parse_lib boolean_strs = [["yes", "true", "1", "on"], ["no", "false", "0", "off"]];
var $root inited = 1;
public method ._range() {
arg str;
if (str.is_numeric()) {
return toint(str);
} else {
switch (str[1]) {
case "$":
return 'end;
case ".":
return 'current;
case "^":
return 'start;
default:
throw(~range, "Invalid range reference.");
}
}
};
public method ._traceback() {
arg what, [more];
var line;
if (more) {
if (more[1] == more[2])
return more[1] + "." + what + "() line " + more[3];
else
return more[2] + "." + what + "() (" + more[1] + ") line " + more[3];
} else {
return what;
}
};
public method .boolean() {
arg str;
if (str in boolean_strs[1])
return 1;
else if (str in boolean_strs[2])
return 0;
else
throw(~unknown, "Boolean flag not recognized.");
};
public method .get_name() {
arg obj;
var name;
if (!valid(obj))
return ("** Invalid " + toliteral(obj)) + " **";
return obj.objname();
};
public method .getopt() {
arg line, [defaults];
var out, newlist, part, v, opt, t, templates, keys, key, l, x;
// submit: [["template", value], [...]];
// => if value is 1, it will take the next part of the string
// receive: [["template", "flag", bool, value]], [...]];
line = line.explode_quoted();
out = [];
newlist = [];
defaults = (| defaults[1] |) || [];
templates = defaults.slice(1);
x = 1;
l = line.length();
while (1) {
if (x > l)
break;
if (line[x][1] in ["-", "+"]) {
opt = 0;
v = "";
part = line[x].subrange(2);
for t in [1 .. templates.length()] {
if ("=" in part) {
part = part.explode("=");
v = (| part[2] |) || "";
part = part[1];
}
if (part.match_template(templates[t])) {
opt = [templates[t], part, line[x][1] == "+"];
if ((| defaults[t][2] |) && !v) {
if (x + 1 <= l) {
x = x + 1;
if (line[x] == "=") {
if (x + 1 <= l)
x = x + 1;
}
v = line[x];
}
}
opt = opt + [v];
}
}
if (!opt)
opt = [0, part, line[x][1] == "+", ""];
out = out + [opt];
} else {
newlist = newlist + [line[x]];
}
x = x + 1;
}
return [newlist, out];
};
public method .range() {
arg str;
var out;
out = str.split(" *- *");
if (out.length() == 1) {
if ("," in str)
return ['specific, str];
out = [(> ._range(str) <), 'single];
} else if (out.length() == 2) {
out = out.replace(1, (> ._range(out[1]) <));
out = out.replace(2, (> ._range(out[2]) <));
} else {
throw(~range, "Invalid range reference.");
}
return out;
};
public method .ref() {
arg str, [args];
var def, me, obj, reg, member, match, type, second;
me = [@args, sender()][1];
if (args.length() > 1)
match = args[2];
else
match = [me, 'match_environment, []];
if (str == ".") {
// shortcut
obj = (> match[1].(match[2])("", @match[3]) <);
return ['object, obj, obj, 0, 0];
}
if ((reg = regexp(str, "^(.*)<([^>]*)>(.*)$"))) {
def = (> match[1].(match[2])(reg[2], @match[3]) <);
str = reg[1] + reg[3];
}
if ((reg = regexp(str, "([^\.,]*)([\.,]+)([^\( ]*)"))) {
obj = reg[1];
member = reg[3];
type = reg[2];
if (type.length() > 1 && type[1] == "." && !obj) {
type = type.subrange(2);
obj = (> match[1].(match[2])("", @match[3]) <);
} else {
obj = obj ? (> match[1].(match[2])(obj, @match[3]) <) : me;
}
if ("." in type) {
if ("," in type)
second = 'variable;
type = 'method;
} else {
type = 'variable;
}
} else {
obj = (> match[1].(match[2])(str, @match[3]) <);
type = 'object;
}
return [type, obj, def || obj, member, second];
};
public method .traceback() {
arg traceback, [args];
var line, out, pre, lines, cur, x, error;
// $parse_lib.traceback(traceback(), lines, pre);
// -1 lines represents the full error
// pre is set to "! " unless otherwise specified.
lines = [@args, -1][1];
pre = [@args, "! ", "! "][2];
error = [@args, 0, 0, 0][3];
out = [pre + "=> " + traceback[1][2]];
pre = pre + " ";
if (error == 0)
out = [@out, pre + "Thrown by " + ._traceback(@traceback[2].subrange(2))];
else
out = [@out, pre + "Error " + error + " caused by " + ._traceback(@traceback[2].subrange(2))];
for x in [1 .. traceback.length() - 2] {
if (x <= lines || lines == -1) {
line = traceback[x + 2][1] + ": ";
line = line + ._traceback(@traceback[x + 2].subrange(2));
out = [@out, pre + line];
}
}
return out;
};