/
ColdCore-3.0a9.02/
ColdCore-3.0a9.02/src/
new object $command_parser: $user_parsers;

var $root created_on = 796680318;
var $root flags = ['methods, 'code, 'core, 'variables];
var $root inited = 1;
var $root managed = [$command_parser];
var $root manager = $command_parser;

public method ._local() {
    arg user, nmatch, match, template, method, info;
    var x, cmd;
    
    cmd = match[2];
    catch any {
        for x in [1 .. nmatch] {
            if (dict_contains(info, x))
                match = match.replace(x + 2, (> .convert_arg(cmd, (info[x])[1], match[x + 2], user, (info[x])[2], user) <));
        }
    } with {
        if (error() == ~syntax)
            return ['error, (((traceback()[1])[2]) + template) + "\""];
        return ['error, (traceback()[1])[2]];
    }
    return ['command, user, method, @match];
};

public method ._remote() {
    arg user, nmatch, definer, match, template, method, info;
    var x, value, that, cmd;
    
    cmd = match[2];
    catch any {
        for x in [1 .. nmatch] {
            if (dict_contains(info, x)) {
                if (((info[x])[1]) == 'this) {
                    that = (> user.match_environment(match[x + 2]) <);
                    if (!(that.is(definer)))
                        return ['error, ((("You cannot " + (match[2])) + " ") + (that.name())) + "."];
                } else {
                    value = (> .convert_arg(cmd, (info[x])[1], match[x + 2], user, ((info[x])[2]) || [definer], user) <);
                }
                match = match.replace(x + 2, value);
            }
        }
    } with {
        if (error() == ~syntax)
            return ['error, (((traceback()[1])[2]) + template) + "\""];
        return ['error, (traceback()[1])[2]];
    }
    if (!that)
        return ['error, "An error was encountered: no target object found."];
    return ['command, that, method, @match];
};

public method .complete() {
    arg cmd, user, obj, match, info;
    var x, method, parsed;
    
    method = info[2];
    info = info[4];
    parsed = info.keys();
    for x in [1 .. match.length()] {
        if (x in parsed)
            match = match.replace(x, (> $command_lib.convert_arg((info[x])[1], match[x], user, ((info[x])[2]) ? ((info[x])[2]) : user, user) <));
    }
    return [user, method, (cmd.explode())[1], @match];
};

public method .convert_arg() {
    arg cmd, type, str, me, argargs, target;
    var obj, args, anc, out, x, y, list;
    
    switch (type) {
        case 'list:
            out = [];
            if (!str)
                return [(> .convert_arg(cmd, argargs[1], "", me, argargs[2], target) <)];
    
            // or do the whole list
            if ("," in str)
                list = str.explode_english_list(",");
            else
                list = explode(str);
            for x in (list) {
                catch ~ambig {
                    out = out.setadd(.convert_arg(cmd, argargs[1], x, me, argargs[2], target));
                } with {
                    if ((| (traceback()[1])[3] |) && (!((argargs[1]) in ['user, 'user_opt]))) {
                        for y in ((traceback()[1])[3])
                            out = out.setadd((> .convert_arg(cmd, argargs[1], tostr(y), me, argargs[2], target) <));
                    } else {
                        rethrow(error());
                    }
                }
            }
            return out;
        case 'any:
            return str;
        case 'any_opt:
            args = $parse_lib.opt(str, @argargs);
            return args;
        case 'object:
            return (> me.match_environment(str) <);
        case 'object_opt:
            args = $parse_lib.opt(str, @argargs);
            if (!(args[1]))
                throw(~syntax, "No reference specified for command \"");
            obj = (> me.match_environment((args[1])[1]) <);
            return [obj, delete(args[1], 1), args[2]];
        case 'objref:
            return (> $parse_lib.ref(str, me) <);
        case 'objref_opt:
            args = $parse_lib.opt(str, @argargs);
            if (!(args[1]))
                throw(~syntax, "No reference specified for command \"");
            obj = (> $parse_lib.ref((args[1])[1], me) <);
            return [obj, delete(args[1], 1), args[2]];
        case 'user:
            if (!str)
                throw(~match, "No user specified.");
            if (str == "me")
                return me;
            return (| $user_db.search(str) |) || throw(~match, ("Unable to find user " + str) + ".");
        case 'user_opt:
            args = $parse_lib.opt(str, @argargs);
            if (!(args[1]))
                throw(~syntax, "Nobody specified for command \"");
            if (str == "me")
                return me;
            return [(> $user_db.search((args[1])[1]) <), args[2]];
        case 'number:
            return (> str.to_number() <);
        case 'number_opt:
            args = $parse_lib.opt(str, @argargs);
            if (!(args[1]))
                throw(~syntax, "No number specified for command \"");
            return [(> str.to_number() <), args[2]];
        case 'descendant:
            obj = (> me.match_environment(str) <);
            anc = argargs ? (argargs[1]) : user;
            if (!(obj.has_ancestor(anc)))
                throw(~parse, strfmt("You cannot %s %s because it is not %s!", cmd, obj.name(), anc.name()));
            return obj;
        case 'descendant_opt:
            args = $parse_lib.opt(str, @argargs);
            if (!(args[1]))
                throw(~syntax, "No descendant specified for command \"");
            obj = (> me.match_environment((args[1])[1]) <);
            anc = argargs ? (argargs[1]) : user;
            if (!(obj.has_ancestor(anc)))
                throw(~parse, strfmt("You cannot %s %s because it is not %s!", cmd, obj.name(), anc.name()));
            return [obj, args[2]];
        default:
            throw(~ack, ("Support for the type '" + type) + " is incomplete!");
    }
};

public method .grasp_for_remote_command() {
    arg str, cmd, args;
    var reg, obj, cdef, match, matched, info;
    
    reg = args.match_regexp("[$#][a-z_0-9][a-z_0-9]*");
    if (!reg)
        return 0;
    obj = (| $object_lib.to_dbref(args.subrange(@reg[1])) |);
    if (!obj)
        return 0;
    info = (| obj.get_command_info('remote, cmd) |);
    if (!info)
        return 0;
    matched = [];
    for cdef in (info) {
        match = args.match_template(cdef[2]);
        if (match != 0)
            matched += [[match.length(), obj, [str, cmd, @match], @cdef.subrange(3)]];
    }
    if (matched) {
        matched = matched.sort(matched.slice(1));
        return ['remote, matched];
    }
    return ['partial, [[str, cmd], info.slice(3)]];
};

public method .handle_error() {
    arg traceback;
    
    return (traceback[1])[2];
};

public method .local() {
    arg user, @matches;
    var parsed, match;
    
    parsed = [];
    for match in (matches) {
        match = ._local(user, @match);
        if ((match[1]) == 'command)
            return match;
        parsed = [match[2]] + parsed;
    }
    return ['error, parsed.compress()];
};

public method .parse() {
    arg u, str, next_parser, @other_parsers;
    var l, cmd, c, p, obj, exits;
    
    cmd = str.explode();
    if (cmd) {
        cmd = [str, cmd[1], ((cmd.subrange(2)).join()) || ""];
        p = [];
        if ((c = (| u.match_in_shortcut_cache(@cmd) |))) {
            if ((c[1]) == 'shortcut)
                return .shortcut(u, @c[2]);
            p = c[2];
        }
        if ((c = (| u.match_in_local_cache(@cmd) |))) {
            if ((c[1]) == 'local)
                return .local(u, @c[2]);
            p += c[2];
        }
        if ((c = (| u.match_in_remote_cache(@cmd) |))) {
            if ((c[1]) == 'remote)
                return .remote(u, @c[2]);
            p += c[2];
        }
        l = u.location();
        if ((c = (| l.match_in_local_cache(@cmd) |))) {
            if ((c[1]) == 'local)
                return .local(l, @c[2]);
            p += c[2];
        }
        if ((c = (| l.match_in_remote_cache(@cmd) |))) {
            if ((c[1]) == 'remote)
                return .remote(u, @c[2]);
            p += c[2];
        }
        if ((c = (| .grasp_for_remote_command(@cmd) |))) {
            if ((c[1]) == 'remote)
                return .remote(u, @c[2]);
            p += c[2];
        }
        if ((exits = (| (u.location()).exits() |) || [])) {
            catch any {
                obj = exits.match_object(str);
                return ['command, obj, 'invoke];
            } with {
                if (error() == ~ambig) {
                    exits = (traceback()[1])[3];
                    return ['error, ((("\"" + str) + "\" can match ") + ((exits.mmap('namef, 'ref)).to_english("", " or "))) + "."];
                }
            }
        }
        if (p)
            return .partial(u, cmd, p);
    }
    return next_parser.parse(u, str, @other_parsers);
};

public method .partial() {
    arg user, args, templates;
    var part, line;
    
    for part in (templates)
        templates = templates.replace(part in templates, toliteral(part));
    if ((templates.length()) == 1)
        line = toliteral(args[2]) + " could match ";
    else if ((templates.length()) == 2)
        line = toliteral(args[2]) + " could match either ";
    else
        line = toliteral(args[2]) + " could match any of ";
    return ['error, (line + (templates.to_english("", " or "))) + "."];
};

public method .remote() {
    arg user, @matches;
    var parsed, match;
    
    parsed = [];
    for match in (matches) {
        match = ._remote(user, @match);
        if ((match[1]) == 'command)
            return match;
        parsed = [match[2]] + parsed;
    }
    return ['error, parsed.compress()];
};

public method .shortcut() {
    arg user, method, parsed;
    
    return ['command, user, method, @parsed];
};