new object $user: $reads_lines, $has_commands;
var $root inited = 1;
var $has_commands shortcuts = #[["\"", 'say_cmd], [":", 'emote_cmd], [";", 'eval_cmd]];
var $has_commands commands = #[["say", 'say_cmd], ["emote", 'emote_cmd], ["@program", 'program_cmd], ["feh", 'feh_cmd], ["@eval", 'eval_cmd], ["@edit", 'edit_cmd]];
var $user name = "the Generic User Object";
var $user connection = 0;
var $user eval_offset = 0;
public method .new_connection() {
arg @args;
sender().write("Welcome to ColdTurkey 0.0!");
return (> pass(@args) <);
};
public method .init() {
arg conn, username;
connection = conn;
name = username;
};
public method .name() {
return name;
};
protected method .say_cmd() {
arg cmdstr, cmd, what;
var line;
line = .name() + " says, \"" + what + "\"";
$user.children().mmap('tell, line);
};
protected method .emote_cmd() {
arg cmdstr, cmd, what;
var line;
if (what[1] == ":") {
line = .name() + substr(what, 2);
} else {
line = .name() + " " + what;
}
$user.children().mmap('tell, line);
};
public method .tell() {
arg what;
var i;
switch (type(what)) {
case 'string:
connection.write(what);
case 'list:
for i in (what) {
.tell(i);
}
case 'symbol:
connection.write(tostr(what));
}
};
protected method .feh_cmd() {
arg cmdstr, com, @whatever;
.debug(.read_lines());
};
//
// These are programmer commands
//
private method ._obj_meth() {
arg methref;
switch (methref[1]) {
case "$":
methref = methref.subrange(2);
case ".":
methref = .objname().subrange(2) + methref;
// Maybe put in something about objnums here.
}
return methref.explode(".").mmap('to_symbol) + [methref];
};
protected method .edit_cmd() {
arg cmdstr, com, methref;
var obj, meth, code;
[obj, meth, methref] = ._obj_meth(methref);
// verify what we have is correct
catch ~namenf, ~methodnf {
obj = lookup(obj);
} with {
return traceback()[1][2];
}
// List the method out as an MCP edit command, woohoo
code = (| obj.list_method(meth) |) || [];
return ["#$# edit name: $" + methref + "() upload: @program $" + methref] + code + ["."];
};
protected method .program_cmd() {
arg cmdstr, com, methref;
var obj, meth, code, errs;
[obj, meth, methref] = ._obj_meth(methref);
// verify what we have is correct
catch ~namenf {
obj = lookup(obj);
} with {
return traceback()[1][2];
}
// Read in the text
if ((code = .read_lines("Programing $" + methref + "(). Enter \".\" to finish, \"@abort\" to abort.")) == 0) {
return;
}
// Now try to add the method
catch any {
if ((errs = obj.add_method(code, meth))) {
return errs;
}
if (0) {
(> ref[3].set_method_flags(meth, fl) <);
(> ref[3].set_method_access(meth, acc) <);
if ((line = (> $code_lib.verify_code(code, meth, warn) <))) {
.tell(line);
}
}
return "Method " + methref + "() compiled";
} with {
return traceback()[1][2];
}
};
public method .parse_line() {
arg line;
var ret;
set_user();
catch any {
ret = pass(line);
} with {
.tell($parse_lib.traceback(traceback()));
}
return ret;
};
protected method .eval_cmd() {
arg cmdstr, com, str;
var result, adjust, vars, v, evalp, times, line, reg, obj, definer, ref, debug;
// Taken from tCD
vars = "me";
v = "me=" + this() + ";";
// check for debug flags
if ((reg = str.regexp("^(trace|debug|profile) *;*(.*)$"))) {
debug = tosym(reg[1]);
str = reg[2];
} else {
debug = 0;
}
// who are we evaluating as?
if ((reg = regexp(str, "^ *as +([^; ]+)"))) {
ref = $parse_lib.ref(reg[1]);
obj = ref[2];
definer = ref[3];
str = strsed(str, "^ *as +([^; ]+)[ ;]+", "");
if (!obj.is(definer))
return obj + " isn't a child of " + definer;
} else {
obj = (definer = this());
}
// are we just adjusting our offset?
if (!str) {
result = (> .evaluate("var " + vars + ";" + v + "return (> 1 <);", obj, definer, 'no_offset) <);
result = replace(result[1], 1, result[1][1] - 1);
if (eval_offset)
line = strfmt("adjusted by %s ticks and %s.%6{0}r seconds.", eval_offset[1] - result[1], eval_offset[2] - result[2], abs(eval_offset[3] - result[3]));
else
line = strfmt("set to %s ticks and %s.%6{0}r seconds.", @result);
eval_offset = result;
return "Eval offset " + line;
}
// format it
if (match_begin(str, "var") && (reg = regexp(str, "var ([^;]+)"))) {
str = strsed(str, "var ([^;]+);", "");
str = "var " + vars + ", " + reg.join(",") + ";" + v + str;
} else if ("return" in str) {
str = "var " + vars + ";" + v + str;
} else {
str = strsed(str, " *;* *$", "");
str = "var " + vars + ";" + v + "return (> " + str + " <);";
}
if (debug) {
result = (> .evaluate(str, obj, definer, debug) <);
if (! (| [times, result, debug] = result |)) {
debug = 0;
}
} else {
[times, result] = (> .evaluate(str, obj, definer) <);
}
// Display the errors, or the result.
if (result[1] == 'errors) {
.tell(result[2]);
} else if (result[1] == 'traceback) {
.tell($parse_lib.traceback(result[2]));
line = strfmt("[ seconds: %l.%6{0}r; operations: %s", times[2], times[3], times[1]);
if (times[2])
line += " (" + times[1] / times[2] + " ticks per second)";
return line + " ]";
} else {
if (type(result[2]) == 'objnum)
.tell("=> " + ((| result[2].namef('xref) |) || result[2]));
else
.tell("=> " + toliteral(result[2]));
if (debug)
.tell(debug);
line = strfmt("[ seconds: %l.%6{0}r; operations: %s", times[2], times[3], times[1]);
if (times[2])
line += " (" + times[1] / times[2] + " ticks per second)";
return line + " ]";
}
// $#Edited: 11 Apr 97 03:12 $brad
// $#Edited: 09 Jul 97 14:39 $user_bruce
// $#Edited: 10 Dec 97 14:09 $brandon
};
private method .evaluate() {
arg str, obj, definer, @mode;
var start, end, time, ticks, mtime, times1, times2, method, errs, trace, result, is_error;
// Taken from tCD
mode = mode ? mode[1] : 0;
method = tosym("tmp_eval_" + time());
if ((errs = (> definer.add_method([str], method) <))) {
if (mode) {
return [[0, 0, 0], ['errors, errs, 0, 0], []];
} else {
return [[0, 0, 0], ['errors, errs, 0, 0]];
}
}
catch any {
if (mode in ['trace, 'profile]) {
debug_callers(1);
} else if (mode == 'debug) {
debug_callers(2);
}
times1 = [tick(), time(), mtime()];
result = (> obj.(method)() <);
times2 = [mtime(), time(), tick()];
trace = call_trace();
debug_callers(0);
} with {
times2 = [mtime(), time(), tick()];
result = traceback();
is_error = 1;
debug_callers(0);
}
(| definer.del_method(method) |);
// figure up the actual times
time = times2[2] - times1[2];
ticks = times2[3] - times1[1];
if (times2[1] > times1[3]) {
mtime = times2[1] - times1[3];
} else if (time) {
mtime = time * 1000000 + (1000000 - times1[3]) + times2[1];
} else {
mtime = 1000000 - times2[1] + times1[3];
}
// offset it?
if (eval_offset && mode != 'no_offset) {
ticks -= eval_offset[1];
time -= eval_offset[2];
mtime -= eval_offset[3];
}
if (trace) {
return [[ticks, time, abs(mtime)], ['result, result], $code_lib.generate_debug_listing(trace, mode)];
} else {
return [[ticks, time, abs(mtime)], [is_error ? 'traceback : 'result, result]];
}
// $#Edited: 11 Apr 97 03:17 $brad
// $#Edited: 03 Aug 97 14:34 $brad
// $#Edited: 15 Aug 97 10:15 $brandon
};