/
CDC-1.2b/
CDC-1.2b/src/
parent $root_evaluator
object $base_evaluator

var $root dbref 'base_evaluator
var $root child_index 1
var $root fertile 0
var $root manager $base_evaluator
var $root owned [$base_evaluator]
var $root owners [$]
var $root writable []
var $root readable ['parameters, 'methods, 'code]
var $prep_evaluator append_str "_stmt"
var $root inited 1
var $has_messages message_info #[["errors.english.usage", [$base_evaluator, $compile_evaluator, $uncompile_evaluator, []]], ["errors.english.usage.list", [$base_evaluator, $compile_evaluator, $uncompile_evaluator, []]]]
var $has_messages messages #[[$base_evaluator, #[["errors.english.usage", <$ctext_class, ['text_stmt, [['error_stmt, [['text_stmt, [['string_type, "Usage is "], ['char_type, "lp"], ['string_type, "english <list> [<empty> [<and> [<sep>]]])"]]]]]]]>], ["errors.english.usage.list", <$ctext_class, ['text_stmt, [['error_stmt, [['string_type, "The first argument to english must be a list."]]]]]>]]]]

method name_stmt
    arg vars, args;
    var name, article, n;
    
    //args[1] is a dbref, or list of dbrefs
    //args[2] is the article. defaults to 'indef
    if (((args[1])[1]) == 'dbref_type) {
        name = args[1];
    } else {
        vars = ._eval_ctext(vars, args[1]);
        name = vars['result];
    }
    if ((listlen(args) > 1) && (((args[2])[1]) != 'string_type)) {
        vars = ._eval_ctext(vars, args[2]);
        article = vars['result];
    } else {
        article = ['string_type, "indef"];
    }
    if ((name[1]) == 'list_type)
        return .apply(vars, name[2], 'name_stmt, article);
    n = name[2];
    if ((vars['delay]) && (n.has_ancestor($user))) {
        return dict_add(vars, 'result, ['name_stmt, [name, article]]);
    } else if (n == (vars['sender])) {
        return dict_add(vars, 'result, ['string_type, "you"]);
    } else {
        catch ~methodnf {
            return dict_add(vars, 'result, ['string_type, n.name(article)]);
        } with handler {
            return dict_add(vars, 'result, ['string_type, tostr(n)]);
        }
    }
.

method get_stmt
    arg vars, args;
    var name;
    
    if (((args[1])[1]) != 'string_type) {
        vars = ._eval_ctext(vars, args[1]);
        name = vars['result];
    } else {
        name = args[1];
    }
    if ((name[1]) != 'string_type)
        return dict_add(vars, 'result, ['string_type, "Variable names must be strings."]);
    if (!((name[2]) in dict_keys(vars)))
        return dict_add(vars, 'result, ['string_type, (">>ERROR: no such variable " + (name[2])) + "<<"]);
    return dict_add(vars, 'result, vars[name[2]]);
.

method format_stmt
    arg vars, args;
    
    return dict_add(vars, 'result, args[1]);
.

method _eval_ctext
    arg vars, term;
    var t, output, result;
    
    if (vars['debug])
        return ._eval_debug(vars, term);
    if (!term) {
        return dict_add(vars, 'result, []);
    } else if ((term[1]) in ['symbol_type, 'dbref_type, 'integer_type, 'string_type]) {
        return dict_add(vars, 'result, term);
    } else {
        catch ~methodnf {
            return .(term[1])(vars, term[2]);
        } with handler {
            output = [];
            for t in (term[2]) {
                vars = ._eval_ctext(vars, t);
                result = vars['result];
                if (type(result) != 'symbol) {
                    if (type(result[1]) == 'list)
                        output = [@output, result[1]];
                    else
                        output = [@output, result];
                }
            }
            return dict_add(vars, 'result, [term[1], output]);
        }
    }
.

method force_stmt
    arg vars, args;
    var t, output, old;
    
    old = vars['force];
    vars = dict_add(vars, 'force, 1);
    output = [];
    for t in (args) {
        vars = ._eval_ctext(vars, t);
        if (output)
            output = [@output, vars['result]];
        else
            output = vars['result];
    }
    vars = dict_add(vars, 'force, old);
    return dict_add(vars, 'result, output);
.

method text_stmt
    arg vars, args;
    var term, output, result, t, start, mid, last, first;
    
    output = [];
    vars = ._eval_series(vars, args);
    result = vars['result];
    output = [result[1]];
    for term in (sublist(result, 2)) {
        if (output) {
            last = output.last();
            if (((term[1]) == 'string_type) && ((last[1]) == 'string_type)) {
                term = ['string_type, (last[2]) + (term[2])];
                output = output.chop();
            }
        }
        output = [@output, term];
    }
    if (listlen(output) == 1) {
        first = output[1];
        if ((first[1]) == 'string_type)
            return dict_add(vars, 'result, first);
    }
    return dict_add(vars, 'result, ['text_stmt, output]);
.

method foreach_stmt
    arg vars, args;
    var name, l, c, output, v;
    
    //args[1] is the name of a variable
    //args[2] is the a list
    //args[3] is the code that will be executed once for each element in the lsit
    vars = ._eval_ctext(vars, args[1]);
    name = vars['result];
    if ((name[1]) != 'string_type)
        return dict_add(vars, 'result, ['string_type, "The first argument to foreach should be a string"]);
    else
        name = name[2];
    vars = ._eval_ctext(vars, args[2]);
    l = vars['result];
    if ((l[1]) != 'list_type)
        return dict_add(vars, 'result, ['string_type, "The second arguemnt to foreach should be a list"]);
    else
        l = l[2];
    c = args[3];
    output = [];
    for v in (l) {
        vars = dict_add(vars, name, v);
        vars = ._eval_ctext(vars, c);
        output = [@output, vars['result]];
    }
    if (listlen(output) > 1)
        output = ['list_type, output];
    else if (listlen(output) == 1)
        output = output[1];
    else
        output = 'success;
    return dict_add(vars, 'result, output);
.

method eval_stmt
    arg vars, args;
    var a, output, line;
    
    vars = ._eval_ctext(vars, args[1]);
    vars = ._eval_ctext(vars, vars['result]);
    return vars;
.

method message_stmt
    arg vars, args;
    var m;
    
    vars = ._eval_ctext(vars, args[1]);
    m = vars['result];
    m = (vars['this]).eval_message(.normalize(m), vars);
    return dict_add(vars, 'result, m.ctext());
.

method delay_stmt
    arg vars, args;
    var t, output, old, old_d;
    
    old = vars['force];
    old_d = vars['delay];
    vars = dict_add(vars, 'force, 0);
    output = [];
    vars = ._eval_ctext(vars, args[1]);
    vars = dict_add(vars, 'force, old);
    if (vars['delay]) {
        vars = dict_add(vars, 'delay, old_d);
        return dict_add(vars, 'result, ['evaluator, [['dbref, this()], vars['result]]]);
    } else {
        vars = dict_add(vars, 'delay, old_d);
        return vars;
    }
.

method evaluator
    arg vars, args;
    
    vars = ((args[1])[2])._eval_ctext(vars, (args[2])[1]);
    vars = dict_add(vars, 'force, 1);
    vars = dict_add(vars, 'delay, 0);
    vars = sender().eval_ctext(vars, vars['result]);
    return vars;
.

method english_stmt
    arg vars, args;
    var list, empty, and, sep, length;
    
    // turns a list in args[1] into an english list
    // args 2 3 4 are optional
    //   see $list.to_english for meanings.
    // generate the defaults
    empty = ['string_type, "nothing"];
    and = ['string_type, " and "];
    sep = ['string_type, ", "];
    length = listlen(args);
    
    //get the list
    catch ~keynf {
        list = args[1];
    } with handler {
        return dict_add(vars, 'result, (.eval_message("errors.english.usage", vars)).ctext());
    }
    vars = ._eval_ctext(vars, list);
    list = vars['result];
    
    //get the optional arguments
    if (length > 1) {
        if (((args[2])[1]) != 'string_type) {
            vars = ._eval_ctext(vars, args[2]);
            empty = vars['result];
            if ((empty[1]) != 'string_type)
                return dict_add(vars, 'result, (.eval_message("errors.english.usage", vars)).ctext());
        } else {
            empty = args[2];
        }
        if (length > 2) {
            vars = ._eval_ctext(vars, args[3]);
            and = vars['result];
            if ((and[1]) != 'string_type)
                return dict_add(vars, 'result, (.eval_message("errors.english.usage", vars)).ctext());
            if (length > 3) {
                vars = ._eval_ctext(vars, args[4]);
                sep = vars['result];
                if ((sep[1]) != 'string_type)
                    return dict_add(vars, 'result, (.eval_message("errors.english.usage", vars)).ctext());
            }
        }
    }
    list = .normalize(list);
    if (type(list) == 'list)
        return dict_add(vars, 'result, .fix_values(._english_stmt(list, .normalize(empty), .normalize(and), .normalize(sep))));
    else
        return dict_add(vars, 'result, .fix_values(list));
.

method gt_stmt
    arg vars, args;
    var left, right;
    
    vars = ._eval_ctext(vars, args[1]);
    left = .normalize(vars['result]);
    vars = ._eval_ctext(vars, args[2]);
    right = .normalize(vars['result]);
    if (left > right)
        return dict_add(vars, 'result, ['integer_type, 1]);
    else
        return dict_add(vars, 'result, ['integer_type, 0]);
.

method if_stmt
    arg vars, args;
    var output, index, length, statements;
    
    index = 1;
    output = [];
    while (listlen(args) > index) {
        vars = ._eval_ctext(vars, args[index]);
        if (._truth(vars['result]))
            return ._eval_ctext(vars, args[index + 1]);
        else
            index = index + 1;
    }
    return ._eval_ctext(vars, args.last());
.

method list_stmt
    arg vars, args;
    var method, a, ars;
    
    //call methods on $list
    // args[1] is the method
    // args[2].. are the arguments
    vars = ._eval_ctext(vars, args[1]);
    method = vars['result];
    if ((method[1]) == 'string_type)
        method = tosym(method[2]);
    else
        method = method[1];
    if (type(method) != 'symbol)
        return dict_add(vars, 'result, ['string_type, ">>ERROR: methods should be a symbol or string."]);
    ars = [];
    for a in (sublist(args, 2)) {
        vars = ._eval_ctext(vars, a);
        ars = [@ars, .normalize(vars['result])];
    }
    if (ars)
        return dict_add(vars, 'result, .fix_values($list.(method)(@ars)));
    else
        return dict_add(vars, 'result, .fix_values($list.(method)()));
.

method char_type
    arg vars, args;
    
    if ((args[1]) != 'string_type)
        return ['string_type, ">>ERROR: Character must be a constant string."];
    switch (args) {
        case "lp":
            return ['string_type, "("];
        case "amp":
            return [string_type, "&"];
        case "quote":
            return ['string_type, "\""];
        case "per":
            return ['string_type, "%"];
        default:
            return ['string_type, (">>ERROR: Unknown character " + args) + "<<"];
    }
.

method server_name_stmt
    arg vars, args;
    
    return dict_add(vars, 'result, .fix_values($motd.server_name()));
.

method eval_debug
    arg vars, term;
    var t, output, result, start, offset, debugger, end, off;
    
    offset = tick();
    debugger = vars['debug];
    debugger.tell("Debuger: " + ($uncompile_evaluator.uncompile(term)));
    off = (| vars['offset] |) || 0;
    vars = dict_add(vars, 'offset, 0);
    start = tick();
    if (!term) {
        return dict_add(vars, 'result, []);
    } else if ((term[1]) in ['symbol_type, 'dbref_type, 'integer_type, 'string_type]) {
        return dict_add(vars, 'result, term);
    } else {
        catch ~methodnf {
            return .(term[1])(vars, term[2]);
        } with handler {
            output = [];
            for t in (term[2]) {
                vars = ._eval_ctext(vars, t);
                result = vars['result];
                if (type(result) != 'symbol)
                    output = [@output, result];
            }
            return dict_add(vars, 'result, [term[1], output]);
        }
    }
    end = tick();
    debugger.tell("Debugger: " + ($uncompile_evalautor.uncompile(result)));
    debugger.tell("Debuuger: Time: " + tostr(end - start));
    offset = ((((vars['offset]) + start) - offset) + end) - tick();
    return dict_add(vars, 'offset, offset);
.

method _eval_debug
    arg vars, term;
    var start, debugger, end, method, depth, useful, breakdown, unc, waste, off;
    
    //debugger init
    off = tick();
    debugger = vars['debug];
    method = (| tostr(term[1]) |) || "empty";
    depth = (| vars['depth] |) || 0;
    vars = dict_add(vars, 'depth, depth + 1);
    unc = $uncompile_evaluator.eval_ctext(term);
    vars = dict_add(vars, 'useful, 0);
    vars = dict_add(vars, 'waste, 0);
    if (depth == 0)
        vars = dict_add(vars, 'debug_data, #[]);
    debugger.tell($list.join(tostr(depth) + " ", unc));
    start = tick();
    
    //evaluator
    if (!term) {
        vars = dict_add(vars, 'result, ['string_type, ""]);
    } else if ((term[1]) in ['symbol_type, 'dbref_type, 'integer_type, 'string_type]) {
        vars = dict_add(vars, 'result, term);
    } else {
        catch ~methodnf {
            vars = .(term[1])(vars, term[2]);
        } with handler {
            vars = ._eval_debug_series(vars, term[2]);
            vars = dict_add(vars, 'result, [term[1], vars['result]]);
        }
    }
    
    //debugger clean up
    end = tick();
    useful = ((end - start) - (vars['waste])) - (vars['useful]);
    
    //.debug(end-start, useful, vars['waste], vars['useful]);
    vars = dict_add(vars, 'depth, depth);
    vars = dict_add(vars, 'debug_data, ._update_breakdown(vars['debug_data], method, useful));
    unc = $uncompile_evaluator.eval_ctext(vars['result]);
    debugger.tell($list.join(((tostr(depth) + " time ") + tostr(useful)) + " ", unc));
    if (depth == 0)
        debugger.tell(._breakdown(vars['debug_data]));
    vars = dict_add(vars, 'useful, ((end - start) + (vars['useful])) - (vars['waste]));
    return dict_add(vars, 'waste, ((((vars['waste]) + start) - off) + tick()) - end);
.

method _update_breakdown
    arg data, method, total;
    var nums;
    
    nums = (| data[method] |) || [0, 0];
    data = dict_add(data, method, [(nums[1]) + total, (nums[2]) + 1]);
    return data;
.

method _breakdown
    arg data;
    var breakdown, method;
    
    breakdown = ["Breakdown:"];
    for method in (dict_keys(data))
        breakdown = [@breakdown, ((((" " + tostr(method)) + ": ") + tostr((data[method])[1])) + " ") + tostr((data[method])[2])];
    return breakdown;
.

method _eval_debug_series
    arg vars, args;
    var start, output, result, total, waste, t, s, useful, u;
    
    waste = 0;
    useful = 0;
    start = tick();
    output = [];
    for t in (args) {
        s = tick();
        waste = waste + (vars['waste]);
        useful = useful + (vars['useful]);
        vars = dict_add(vars, 'waste, 0);
        vars = dict_add(vars, 'useful, 0);
        waste = (waste + tick()) - s;
        if (!t) {
            vars = dict_add(vars, 'result, ['string_type, ""]);
        } else if ((t[1]) in ['symbol_type, 'dbref_type, 'integer_type, 'string_type]) {
            vars = dict_add(vars, 'result, t);
        } else {
            catch ~methodnf {
                vars = .(t[1])(vars, t[2]);
            } with handler {
                vars = ._eval_debug_series(vars, t[2]);
                vars = dict_add(vars, 'result, [t[1], vars['result]]);
            }
        }
        result = vars['result];
        if (type(result) != 'symbol)
            output = [@output, result];
    }
    vars = dict_add(vars, 'useful, useful);
    vars = dict_add(vars, 'result, output);
    return dict_add(vars, 'waste, waste + (vars['waste]));
.

method _eval_series
    arg vars, term;
    var t, output, result;
    
    if (vars['debug])
        return ._eval_debug_series(vars, term);
    output = [];
    for t in (term) {
        if ((t[1]) in ['string_type, 'integer_type, 'dbref_type, 'symbol_type]) {
            output = [@output, t];
        } else {
            vars = ._eval_ctext(vars, t);
            result = vars['result];
            if (type(result) != 'symbol)
                output = [@output, result];
        }
    }
    return dict_add(vars, 'result, output);
.

method debug_stmt
    arg vars, args;
    
    //(debug <code>)
    vars = dict_add(vars, 'debug, (vars['this]).manager());
    vars = ._eval_debug(vars, args[1]);
    vars = dict_del(vars, 'debug);
    return vars;
.

method set_stmt
    arg vars, args;
    var name;
    
    vars = ._eval_ctext(vars, args[1]);
    name = vars['result];
    if ((name[1]) != 'string)
        return dict_add(vars, 'result, ['string, "variable name must be a string"]);
    vars = ._eval_ctext(vars, args[2]);
    vars = dict_add(vars, name[2], vars['result]);
    return dict_add(vars, 'result, 'succes);
.

method define_stmt
    arg vars, args;
    var name;
    
    vars = ._eval_ctext(vars, args[1]);
    name = vars['result];
    if ((name[1]) != 'string)
        return dict_add(vars, 'result, ['string, "variable name must be a string"]);
    vars = dict_add(vars, name[2], args[2]);
    return dict_add(vars, 'result, 'succes);
.

method _english_stmt
    arg list, empty, and, sep;
    
    switch (listlen(list)) {
        case 0:
            return [empty];
        case 1:
            return list;
        case 2:
            return [list[1], and, list[2]];
        case 3:
            return [list[1], sep, @._english_stmt(sublist(list, 2), empty, and, sep)];
    }
.