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; };