pike.git / lib / modules / Tools.pmod / Hilfe.pmod

version» Context lines:

pike.git/lib/modules/Tools.pmod/Hilfe.pmod:6:      constant hilfe_todo = #"List of known Hilfe bugs/room for improvements:      - Hilfe can not handle enums.   - Hilfe can not handle typedefs.   - Hilfe can not handle implicit lambdas.   - Hilfe can not handle unnamed classes.   - Hilfe can not handle named lambdas.   - Hilfe should possibly handle imports better, e.g. overwrite the    local variables/constants/functions/programs. - - Filter exit/quit from history. Could be done by adding a 'pop' -  method to Readline.History and calling it from StdinHilfe's -  destroy. +    - Add some better multiline edit support.   - Improve doc command to get documentation from c-code.   ";      // The Big To Do:   // The parser part of Hilfe should really be redesigned once again. - // The user input is first run through Parser.Pike.split and outputted - // as a token stream. This stream is fed into a streming parser which + // The user input is first run through Parser.Pike.split and output + // as a token stream. This stream is fed into a streaming parser which   // then relocates the variables and outputs expression objects with   // evaluation destinations already assigned. Note that the streaming   // parser can not start on the next expression before the previous - // expression has been evaulated, because the variable table might not + // expression has been evaluated, because the variable table might not   // be up to date.      //! Abstract class for Hilfe commands.   class Command {       //! Returns a one line description of the command. This help should    //! be shorter than 54 characters.    string help(string what);       //! A more elaborate documentation of the command. This should be
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:64:    "specified by\nname. Example: \"reset tmp\"\n";    }       void exec(Evaluator e, string line, array(string) words,    array(string) tokens) {    string n = sizeof(words)>1 && words[1];    if(!n) {    e->safe_write("No symbol given as argument to reset.\n");    return;    } -  if(zero_type(e->variables[n]) && zero_type(e->constants[n]) && -  zero_type(e->functions[n]) && zero_type(e->programs[n])) { +  if(!has_index(e->variables, n) && !has_index(e->constants, n) && +  !has_index(e->functions, n) && !has_index(e->programs, n)) {    e->safe_write("Symbol %O not defined.\n", n);    return;    }       m_delete(e->variables, n);    m_delete(e->types, n);    m_delete(e->constants, n);    m_delete(e->functions, n);    m_delete(e->programs, n);    }
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:295:    // FIXME: Allow user to change prompt (>/>>)?    }   }      protected class CommandExit {    inherit Command;    string help(string what) { return "Exit Hilfe."; }       void exec(Evaluator e, string line, array(string) words,    array(string) tokens) { +  if (e->readline) { +  e->readline->get_history()->pop(line); +  e->save_history(); +  }    e->safe_write("Exiting.\n");    destruct(e);    exit(0);    }   }      protected class CommandDoc {    inherit Command;    string help(string what)    {
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:382:    case "me more":    write( documentation_help_me_more );    return;       case "hilfe todo":    write(hilfe_todo);    return;       case "about hilfe":    e->print_version(); -  write(#" - Initial version written by Fredrik Hübinette 1996-2000 - Rewritten by Martin Nilsson 2002 - "); +     return;    }       if(sizeof(words)>1 && e->commands[words[1]]) {    string ret = e->commands[words[1]]->doc(words[1], words[2..]*"");    if(ret) write(ret+"\n");    return;    }       write("\n");
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:426:       foreach(err-({0}), mixed err)    write(describe_backtrace(err)+"\n\n");    }   }      protected class CommandDot {    inherit Command;    string help(string what) { return 0; }    -  protected constant usr_vector_a = ({ +  local protected constant usr_vector_a = ({    89, 111, 117, 32, 97, 114, 101, 32, 105, 110, 115, 105, 100, 101, 32, 97,    32, 72, 105, 108, 102, 101, 46, 32, 73, 116, 32, 115, 109, 101, 108, 108,    115, 32, 103, 111, 111, 100, 32, 104, 101, 114, 101, 46, 32, 89, 111,    117, 32, 115, 101, 101, 32 }); -  protected constant usr_vector_b = ({ +  local protected constant usr_vector_b = ({    32, 89, 111, 117, 32, 99, 97, 110, 32, 103, 111, 32, 105, 110, 32, 97,    110, 121, 32, 100, 105, 114, 101, 99, 116, 105, 111, 110, 32, 102, 114,    111, 109, 32, 104, 101, 114, 101, 46 }); -  protected constant usr_vector_c = ({ +  local protected constant usr_vector_c = ({    32, 89, 111, 117, 32, 97, 114, 101, 32, 99, 97, 114, 114, 121, 105, 110,    103, 32 }); -  protected constant usr_vector_d = usr_vector_c[..8] + ({ +  local protected constant usr_vector_d = usr_vector_c[..8] + ({    101, 109, 112, 116, 121, 32, 104, 97, 110, 100, 101, 100, 46 });       protected array(string) thing(array|mapping|object thing, string what,    void|string a, void|string b) {    if(!sizeof(thing)) return ({});    return ({ sizeof(thing)+" "+what+(sizeof(thing)==1?(a||""):(b||"s")) });    }       void exec(Evaluator e, string line, array(string) words,    array(string) tokens) {
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:554:    case "wrapper":    wrapper(e);    return;    case "state":    write(e->state->status());    return;    case "history":    write(e->history->status());    return;    case "memory": -  write(master()->resolv("Debug.pp_memory_usage")()); +  write(Pike.Lazy.Debug.pp_memory_usage());    return;    case "":    dump(e);    return;    }    write("Unknown dump specifier.\n");    write(doc(0,0)+"\n");    }   }   
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:672: Inside #if constant(thread_create)
   void stop(Evaluator e, array(string) words){    call_out(throw, 0, 0);    }       int(0..1) runningp() {    return is_running;    }       protected void backend_loop(function(string:int) write_err, int(0..1) once){    is_running=1; -  object backend = master()->resolv("Pike.DefaultBackend"); +  object backend = Pike.DefaultBackend;    mixed err;    do {    err = catch {    while(1)    backend(3600.0);    };    if(err)    write_err(describe_backtrace(err));    } while(!once && err);    if(once && err)
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:709:       protected class Logger (Evaluator e, Stdio.File logfile)    {    constant is_logger = 1;       protected void create() {    e->add_input_hook(this);    running = 1;    }    -  protected void destroy() { +  protected void _destruct() {    e && e->remove_input_hook(this);    running = 0;    }       protected int(0..0) `() (string in) {    if(!running) return 0;    if(catch( logfile->write(in) )) {    e->remove_writer(this);    e->safe_write("Error writing to log file. Terminating logger.\n");    }
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:861:    if(subsystems[what]->runningp())    subsystems[what]->stop(e,words);    else    e->safe_write("%s is not running.\n", what);    }    else    e->safe_write("No such subsystem (%O).\n", what);    }   }    + local { +    protected constant whitespace = (< ' ', '\n' ,'\r', '\t' >);   protected constant termblock = (< "catch", "do", "gauge", "lambda",    "class stop" >);   protected constant modifier = (< "extern", "final", "inline", "local", -  "nomask", "optional", "private", "protected", -  "public", "static", "variant" >); +  "optional", "private", "protected", +  "public", "static", "variant", "deprecated" >);      protected constant types = (< "string", "int", "float", "array", "mapping",    "multiset", "mixed", "object", "program",    "function", "void" >);      // infix token may appear between two literals   protected constant infix = (< "!=", "%", "%=", "&", "&=", "*", "*=",    "+", "+=", ",", "-", "-=",    "->", "->=", "/", "/=",    "<", "<<", "<<=", "<=", "==",    ">", ">=", ">>", ">>=",    "^", "^=", "|", "|=", "~", "~=", -  "&&", "||", "=", ".." >); +  "&&", "||", "=", "..", "**" >);      // before literal but not after   protected constant prefix = (< "!", "@", "(", "({", "([", "(<", "[", "{",    "<", ">" >);      // after literal but not before   protected constant postfix = (< ")", "})", "])", ">)", "]", "}" >);      // before or after literal but not between   protected constant prepostfix = (< "--", "++" >);
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:904:   protected constant reference = ([ ".":"module", "->":"object", "[":"array" ]);      protected constant group = ([ "(":")", "({":"})", "([":"])", "(<":">)",    "[":"]", "{":"}" ]);      // Symbols not valid in type expressions.   // All of the above except ".", "|", "&" and "~".   protected constant notype = (infix+prefix+postfix+prepostfix+seperator) -    (< ".", "|", "&", "~" >);    + } +    string typeof_token(string|array token)   {    string type;    if (arrayp(token))    {    if (token[0] == "(" && token[-1] == ")")    type = "argumentgroup";    else if (token[0] == "[" && token[-1] == "]")    type = "referencegroup";    }
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:1097:       if( (< "|", "&" >)[`[](position+1)] ) {    return endoftype(position+2);    }       return position;    }       // Well, we did find a type declaration, but it    // wasn't used for anything except perhaps loading -  // a module into pike, e.g. "spider;" +  // a module into pike, e.g. "_Roxen;"    return -1;    }       //! Returns the position of the matching parenthesis of the given    //! kind, starting from the given position. The position should be    //! the position after the opening parenthesis, or later. Assuming    //! balanced code. Returns -1 on failure.    int(-1..) find_matching(string token, int(0..)|void pos) {    string find = ([ "(":")", "{":"}", "[":"]",    "({":"})", "([":"])", "(<":">)" ])[token];
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:1146:       //! An Expression object can be cast to an array or a string. In    //! both forms all tokens, including white spaces will be returned.    protected mixed cast(string to)    {    switch(to)    {    case "array": return tokens;    case "string": return code();    } -  error("Can not cast to %O\n", to); +  return UNDEFINED;    }       protected string _sprintf(int t) {    return t=='O' && sprintf("%O(%O)", this_program, tokens);    }   }      //! In every Hilfe object (@[Evaluator]) there is a ParserState object   //! that manages the current state of the parser. Essentially tokens are - //! entered in one end and complete expressions are outputted in the other. + //! entered in one end and complete expressions are output in the other.   //! The parser object is accessible as ___Hilfe->state from Hilfe expressions.   protected class ParserState {    protected ADT.Stack pstack = ADT.Stack();    protected constant starts = ([ ")":"(", "}":"{", "]":"[",    ">)":"(<", "})":"({", "])":"([" ]);    protected array(string) pipeline = ({ });    protected array(Expression) ready = ({ });    protected string last;    protected string block;   
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:1293:    ready = ({});    return ret;    }       protected string caught_error;       //! Prints out any error that might have occurred while    //! @[push_string] was executed. The error will be    //! printed with the print function @[w].    void show_error(function(array(string)|string, mixed ... : int) w) { -  if(!error) return; +  if(!caught_error) return;    w("Hilfe Error: %s", caught_error);    caught_error = 0;    }       //! Sends the input @[line] to @[Parser.Pike] for tokenization,    //! but keeps a state between each call to handle multiline    //! /**/ comments and multiline #"" strings.    array(string) push_string(string line) {    array(string) tokens;    array err;
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:1352:    int datap() {    if(sizeof(pipeline)==1 && whitespace[pipeline[0][0]])    pipeline = ({});    return sizeof(ready);    }       //! Are we in the middle of an expression. Used e.g. for changing the    //! Hilfe prompt when entering multiline expressions.    int(0..1) finishedp() {    if(sizeof(pstack)) return 0; -  if(low_state->in_token) return 0; +  if(low_state->remains) return 0;    if(!sizeof(pipeline)) return 1;    if(sizeof(pipeline)==1 && whitespace[pipeline[0][0]]) {    pipeline = ({});    return 1;    }    return 0;    }       //! Clear the current state.    void flush() {
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:1598:    add_buffer(s);    }       //! Add buffer tokenizes the input string and determines if the    //! new line is a Hilfe command. If not, it updates the current    //! state with the new tokens and sends any and all complete    //! expressions to evaluation in @[parse_expression].    void add_buffer(string s)    {    // Tokenize the input +  int(0..1) finished = state->finishedp();    array(string) tokens = state->push_string(s+"\n");    array(string) words = s/" ";    string command = words[0];    -  +  if(finished) +  {    // See if first token is a command and not a defined entity. -  if(commands[command] && zero_type(constants[command]) && -  zero_type(variables[command]) && zero_type(functions[command]) && +  if(commands[command] && !has_index(constants, command) && +  !has_index(variables, command) && !has_index(functions, command) &&    (sizeof(words)==1 || words[1]!=";")) {    commands[command]->exec(this, s, words, tokens);    return;    }       // See if the command is executed in overridden mode.    if(sizeof(command) && command[0]=='.') {    command = command[1..];    if(commands[command]) {    commands[command]->exec(this, s, words, tokens);    return;    }    } -  +  }       if(!tokens) {    state->show_error(safe_write);    return;    }       // Push new tokens into our state.    mixed err = catch( state->feed(tokens) );    if(err) {    if(stringp(err))
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:1681:    if(object o = hilfe_compile("constant " + code +    ";\nmixed ___HilfeWrapper() { return " +    var + "; }", var)) {    hilfe_error( catch( constants[var] = o->___HilfeWrapper() ) );    }    }       protected void add_hilfe_variable(string type, string code, string var) {    int(0..1) existed;    mixed old_value; -  if(!zero_type(variables[var])) { +  if(has_index(variables, var)) {    old_value = m_delete(variables, var);    existed = 1;    }       object o = hilfe_compile(type + " " + code +    ";\nmixed ___HilfeWrapper() { return " +    var + "; }", var);       if( o && hilfe_error( catch( variables[var] =    o->___HilfeWrapper() ) ) ) {
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:1845:    werror("Variable declaration detection in relocation broke.\n");    return pos;    }    }       // Relocate symbols in the variable assignment.    for(int i=from+1; i<pos; i++){       string t = expr[i];    +  if(t==".") { +  i++; +  continue; +  } +     if(t=="lambda") {    int d = expr->depth(i);    do {    i++;    if( i==pos ) break;    } while( expr->depth(++i)>d );    continue;    }       if(expr->in_sscanf(i)) {
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:1987:    rel_parser(expr, (multiset)(indices(variables)) );       switch(expr[0])    {    case "if":    case "else":    case "for":    case "do":    case "while":    case "foreach": -  // Parse loops. +  case "switch": +  // Value-less statements    evaluate(expr->code(), 0);    return 0;       case "inherit":    {    inherits += ({ expr[1..<1] });    if(!hilfe_compile(""))    inherits = inherits[..<1];    return 0;    }
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:2137:    w("Ok.\n");    else    w( "(%d) Result: %s\n", num,    replace(sres, "\n", "\n "+(" "*sizeof(""+num))) );    }       //! The function used to write results.    //! Gets as arguments in order: The safe_write function    //! (function(string, mixed ...:int), the result as a string (string),    //! the history entry number (int), the result (mixed), the compilation -  //! time (int) and the evaulation time (int). If the evaluated expression +  //! time (int) and the evaluation time (int). If the evaluated expression    //! didn't return anything (e.g. a for loop) then 0 will be given as the    //! result string.    function reswrite = std_reswrite;          protected string hch_errors = "";    protected string hch_warnings = ""; -  +     protected class HilfeCompileHandler (int stack_level) {       protected void create() {    hch_errors = "";    hch_warnings = "";    }       mapping(string:mixed) hilfe_symbols;       mapping(string:mixed) get_default_module() {    object compat = get_active_compilation_handler();    if (compat?->get_default_module) {    // Support things like @expr{7.4::rusage}. -  return compat->get_default_module() + hilfe_symbols; +  return (compat->get_default_module()||all_constants()) + hilfe_symbols;    }    return all_constants() + hilfe_symbols;    }       string format(string file, int line, string err) {    if(file=="HilfeInput")    file = "";    else    file = master()->trim_file_name(file)+":";    if(err[-1]!='\n') err += "\n";
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:2209:       void show_errors() {    if (sizeof(hch_errors))    safe_write(hch_errors);    }       void show_warnings() {    if (sizeof(hch_warnings))    safe_write(hch_warnings);    } -  }; +  }       //! Creates a wrapper and compiles the pike code @[f] in it.    //! If a new variable is compiled to be tested, its name    //! should be given in @[new_var] so that magically defined    //! entities can be undefined and a warning printed.    object hilfe_compile(string f, void|string new_var)    {    if(new_var && commands[new_var])    safe_write("Hilfe Warning: Command %O no longer reachable. "    "Use %O instead.\n",
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:2239:    if(new_var=="=") {    safe_write("Hilfe Error: No variable name specified.\n");    return 0;    }       mapping symbols = constants + functions + programs;       if(new_var=="__")    safe_write("Hilfe Warning: History variable __ is no "    "longer reachable.\n"); -  else if(zero_type(symbols["__"]) && zero_type(variables["__"])) { +  else if(!has_index(symbols, "__") && !has_index(variables, "__")) {    symbols["__"] = history;    }       if(new_var=="_")    safe_write("Hilfe Warning: History variable _ is no "    "longer reachable.\n"); -  else if(zero_type(symbols["_"]) && zero_type(variables["__"]) +  else if(!has_index(symbols, "_") && !has_index(variables, "_")    && sizeof(history)) {    symbols["_"] = history[-1];    }       string prog;    int major = master()->compat_major;    int minor = master()->compat_minor;    if( major!=-1 || minor!=-1 )    prog = sprintf("#pike %d.%d\n", major, minor);    else
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:2322:    return 0;    }       //! Compiles the Pike code @[a] and evaluates it by    //! calling ___HilfeWrapper in the generated object.    //! If @[show_result] is set the result will be displayed    //! and the result buffer updated with its value.    void evaluate(string a, int(0..1) show_result)    {    if(trace_level) -  a = "\ntrace("+trace_level+");\n" + a; +  a = "\ntrace("+trace_level+");\n"+a;   #if constant(_debug)    if(debug_level)    a = "\n_debug("+debug_level+");\n" + a;   #endif    a = "mixed ___HilfeWrapper() { " + a + " ; }";       last_else = 0;    object o;    if( o=hilfe_compile(a) )    {
pike.git/lib/modules/Tools.pmod/Hilfe.pmod:2503:    void load_hilferc() {    if(string home=getenv("HOME")||getenv("USERPROFILE"))    if(string s=Stdio.read_file(home+"/.hilferc"))    map(s/"\n", add_buffer);    }       void signal_trap(int s) {    exit(1);    }    +  protected int do_write(string a, mixed ... args ) +  { +  if( sizeof( args ) ) +  a = sprintf(a,@args); +  write(a); +  return strlen(a); +  } +     //! Any hilfe statements given in the init array will be executed    //! once .hilferc has been executed.    protected void create(void|array(string) init)    {    readline = Stdio.Readline();    write = readline->write;    ::create();    -  +  add_constant("werror",do_write); +  add_constant("write",do_write); +     load_hilferc();    if(init) map(init, add_buffer);       load_history();    if(!readline->get_history())    readline->enable_history(512);    readline->get_input_controller()->bind("\t", handle_completions);    readline->get_input_controller()->bind("\\!k1", handle_doc);       signal(signum("SIGINT"),signal_trap);