#include "List.h" #include "command.h" #include "tokentable.h" #pragma implementation //long vls=0; Val_List::Val_List (Value* first_element, Val_List* cdr){ elem = first_element; next = cdr; // cout<<(long)this<<" : "<<++vls<<"\n"; } Val_List::~Val_List (){ // cout<<(long)this<<" : "<<--vls<<"\n"; elem->release(); delete next; } void Val_List::cat (Val_List* inlist){ Val_List **temp; temp = &next; while (*temp) temp = &((*temp) -> next); (*temp) = inlist; } int Val_List::length (){ int i; Val_List* temp; if (! this) return 0; for (temp = next , i=1 ; temp ; temp=temp->next , i++); return i; } Value* Val_List::nth (int i){ Val_List* retval; if (!this) return NULL; for (retval = this ; i>1 ; i--) {if (retval->next) retval = retval->next; else return NULL;} return retval->elem; } Val_List* Val_List::insert (Value* someval , int pos){ if (pos < 2 || !this) {return new Val_List (someval->grab(), this);} next = next->insert (someval , pos-1); return this; } char* Val_List::pack_list (char* buf){ if (next) /** yeah, i know it\'s inefficiently recursive. sue me. **/ buf = next->pack_list (buf); return elem->pack_value (buf); } void Val_List::ensure_clean (){ if (this) {elem = elem->ensure_clean(); next->ensure_clean();} } Val_List* Val_List::copy (){ Val_List *temp; if (!this) return NULL; temp = new Val_List (elem->copy()); temp->next = next->copy(); return temp; } Val_List* Val_List::copy_some (int i){ Val_List *temp, **tempptr, *index; for (index = this , temp = NULL , tempptr = &temp ; i ; i--) {*tempptr = new Val_List (index->elem->copy()); tempptr = & ((*tempptr)->next); index = index->next;} return temp; } String* Val_List::tostr(){ Val_List* listptr; String *temp = new String ("("); listptr = this; do {listptr->elem->tostr(); (*temp) += *(listptr->elem->str); delete listptr->elem; listptr->elem = NULL; listptr = listptr->next; if (listptr) (*temp) += " ";} while (listptr); (*temp) += ")"; return temp; } int format_newline (String* ins, int nspc){ int i; *ins += "\n"; for (i=0 ; i<nspc ; i++) *ins += " "; return i+1; } #define FORMAT_CONCAT(s) \ {*temp += *(s); \ length_so_far += (s)->length();} #define FORMAT_S_CONCAT(s) \ {*temp += s; \ length_so_far += strlen(s);} // // i take no great pride in this block of formatting code ... it's ugly, // i guess because the whole process is fairly ugly. // anyone to rewrite this cleanly gets a big cookie. // String* Val_List::format (int tab, int columns){ Val_List* listptr; String *temp = new String ("("); String *lstr; int length_so_far = (tab + 1); if (!this) {FORMAT_S_CONCAT(")"); return temp;} if (elem->get_type() == RESERVED) {switch (elem->reserved) {case QUOTE: if (next) {*temp = "'"; next->elem->tostr(); FORMAT_CONCAT(next->elem->str); return temp;} listptr = this; break; case CALL: if ((listptr = next) && (listptr->next) && (listptr->next->elem->get_type() == SYM) && ((listptr->elem->get_type() == OBJ) || (listptr->elem->get_type() == SYM))) {listptr->elem->tostr(); FORMAT_CONCAT(listptr->elem->str); FORMAT_S_CONCAT(":"); listptr->next->elem->format(tab+2, columns); FORMAT_CONCAT(listptr->next->elem->str); if (listptr = listptr->next->next) FORMAT_S_CONCAT(" ");} else FORMAT_S_CONCAT ("call "); break; default: listptr = this; break;}} else listptr = this; while (listptr) {switch (listptr->elem->get_type()) {case LIST: case EXPR: lstr = listptr->elem->list->format (tab+2 , columns); if (listptr->elem->get_type() == LIST) lstr->prepend ("'"); if ((lstr->length() + length_so_far + 1) > columns) length_so_far += format_newline (temp, tab+2); FORMAT_CONCAT(lstr); delete lstr; break; case STR: if ((listptr->elem->str->length() + length_so_far + 3) > columns) length_so_far += format_newline (temp, tab+2); default: listptr->elem->format(tab+2 , columns); if ((listptr->elem->str->length() + length_so_far + 1) > columns) length_so_far += format_newline (temp, tab+2); FORMAT_CONCAT(listptr->elem->str);} delete listptr->elem; listptr->elem = NULL; listptr = listptr->next; if (listptr) FORMAT_S_CONCAT(" "); } FORMAT_S_CONCAT(")"); return temp; } int Val_List::compare (Val_List* inlist){ Val_List *ptr; ptr = this; for (ptr = this ; (ptr && inlist) ; ptr = ptr->next , inlist = inlist->next) {if (ptr->elem->compare (inlist->elem)) return INT_MIN;} if (ptr) return (-1); if (inlist) return (1); return 0; } int Val_List::search (Value* key, Val_List* key_as_list){ Val_List* complist = NULL; int retval; if (key->type == EXPR || key->type == LIST) return 0; if (! key_as_list) complist = (key_as_list = new Val_List (key->grab())); if (elem->type == LIST || elem->type == EXPR) {retval = elem->list->compare (key_as_list); if (retval == 1 || retval == 0) {delete complist; return 1;}} else {if (! elem->compare(key)) {delete complist; return 1;}} retval = (next ? next->search (key, key_as_list) : 0); delete complist; if (retval) return retval + 1; return 0; } int Val_List::ok_command(){ if (this) return (elem->ok_clause() && next->ok_command()); return 1; } int Val_List::ok_clause(){ Val_List* next_ptr; if (!this || (elem->get_type() != RESERVED)) return 0; switch (elem->reserved) {case BEFORE: for (next_ptr=next ; next_ptr ; next_ptr=next_ptr->next) if (next_ptr->elem->get_type() != STR) return 0; return 1; case OR: for (next_ptr=next ; next_ptr ; next_ptr=next_ptr->next) if (! next_ptr->elem->ok_clause()) return 0; return 1;} return 0; } Val_List* Val_List::command_match (String& pattern){ String* this_token; Val_List* rest_list; // cout << "pattern as passed to Value [" << pattern << "] = " << // pattern.length() << "\n"; if (this_token = elem->command_match (pattern)) {if (next) { //cout << "pattern before passing: [" << pattern << "] = " << pattern.length() << "\n"; //cout << "this_token: [" << *this_token << "]\n"; if (pattern.length() && this_token->length()) rest_list = next->command_match (pattern.after (*this_token)); else rest_list = next->command_match (pattern); if (rest_list) {if (this_token->length() > 1 && this_token->elem(0) == '\"' && this_token->elem(this_token->length()-1) == '\"') *this_token = (*this_token)(1, this_token->length()-2); return new Val_List (new Value (this_token), rest_list);} else {delete this_token; return NULL;}} else {if ((! this_token->length() && pattern.length()) || (pattern.after(*this_token)).length()) {delete this_token; return NULL;} else return new Val_List (new Value (this_token));}} else return NULL; } String* Val_List::command_match_OR (String& pattern){ String* this_token; if (!this) return NULL; if (this_token = elem->command_match (pattern)) return this_token; return next->command_match_OR (pattern); }