/* * slidict.cc * * This file is part of NEST. * * Copyright (C) 2004 The NEST Initiative * * NEST is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * NEST is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NEST. If not, see <http://www.gnu.org/licenses/>. * */ /* SLI Dictionary access */ #include <typeinfo> #include "slidict.h" #include "dictdatum.h" #include "namedatum.h" #include "dictstack.h" #include "iostreamdatum.h" #include "integerdatum.h" #include "arraydatum.h" #include "booldatum.h" #include "tokenutils.h" /* BeginDocumentation Name: dict - Create new, empty dictionary Synopsis: dict -> <<>> Description: dict creates a new dictionary with no entries. This command is equivalent to <<>> Diagnostics: No errors are raised. Author: Marc-Oliver Gewaltig SeeAlso: <<>>, clonedict, cleardict */ void DictFunction::execute(SLIInterpreter *i) const { // create a new dictionary i->EStack.pop(); // never forget me i->OStack.push(DictionaryDatum(new Dictionary)); } /* BeginDocumentation Name: put_d - Add an entry to a dictionary Synopsis: <<dict>> /key val -> <<dict>> Description: put_d adds the pair /key value to the supplied dictionary. If /key was already defined in that dictionary, its old value is lost. In contrast to PostScript dictionaries, only literal names can be used as keys in a dictionary. Parameters: dict - a dictionary /key - a literal name val - an object of arbitrary type Examples: userdict /a 1 put_d << >> /a 1 put_d Diagnostics: No errors are raised. Author: Marc-Oliver Gewaltig SeeAlso: get_d, known, dict, <<>>, clonedict */ void DictputFunction::execute(SLIInterpreter *i) const { if(i->OStack.load()>=3) { // call: dict key val DictionaryDatum *dict = dynamic_cast<DictionaryDatum *>(i->OStack.pick(2).datum()); if(dict!=0) { LiteralDatum *key = dynamic_cast<LiteralDatum *>(i->OStack.pick(1).datum()); if(key!=0) { (*dict)->insert_move(*key, i->OStack.top()); #ifdef DICTSTACK_CACHE if((*dict)->is_on_dictstack()) i->DStack->clear_token_from_cache(*key); #endif i->OStack.pop(3); i->EStack.pop(); // never forget me return; } else throw ArgumentType(1); } else throw ArgumentType(2); } else throw StackUnderflow(3,i->OStack.load()); } /* BeginDocumentation Name: get_d - look a name up in a dictionary Synopsis: dict /key get_d -> any Description: get_d tries to find /key in the supplied dictionary. If it is present, the associated value is returned. If /key is not in the dictionary, an UndefinedNameError is raised Parameters: dict - a dictionary /key - a literal name Examples: systemdict /PI get_d -> 3.1415... <</a 1>> /a get -> 1 Diagnostics: UndefinedNameError Author: Marc-Oliver Gewaltig SeeAlso: put_d, lookup, known */ void DictgetFunction::execute(SLIInterpreter *i) const { // call: dict key -> val if(i->OStack.load()>=2) { DictionaryDatum *dict = dynamic_cast<DictionaryDatum *>(i->OStack.pick(1).datum()); if(dict!=0) { LiteralDatum *key = dynamic_cast<LiteralDatum *>(i->OStack.pick(0).datum()); if(key!=0) { Token value=(*dict)->lookup2(*key); i->EStack.pop(); // never forget me i->OStack.pop(2); i->OStack.push_move(value); return; } else throw ArgumentType(0); } else throw ArgumentType(1); }else throw StackUnderflow(2,i->OStack.load()); } /* BeginDocumentation Name: info - Display the contents of a dictionary Synopsis: ostream dict info -> - Description: Prints the contents of the dictionary to the supplied stream. Parameters: dict - a dictionary No return values are given. Examples: std::cout <</a 1 /b 2.5 /c (Hallo World)>> info shows -------------------------------------------------- Name Type Value -------------------------------------------------- a integertype 1 b doubletype 2.5 c stringtype Hallo World -------------------------------------------------- Total number of dictionary entries: 3 SeeAlso: info_ds, topinfo_d, who, whos */ void DictinfoFunction::execute(SLIInterpreter *i) const { // call: ostream dict assert(i->OStack.load()>1); OstreamDatum *outd = dynamic_cast<OstreamDatum*>(i->OStack.pick(1).datum()); DictionaryDatum *dict = dynamic_cast<DictionaryDatum *>(i->OStack.top().datum()); assert(dict != NULL); assert(outd != NULL); i->EStack.pop(); (*dict)->info(**outd); i->OStack.pop(2); } /* BeginDocumentation Name: length_d - counts elements of a dictionary Synopsis: dict length_d -> int Examples: <</a 1 /b 2>> length_d -> 2 modeldict length_d --> 34 Author: docu by Sirko Straube Remarks: Use length if you are not sure of the data type. SeeAlso: length */ void Length_dFunction::execute(SLIInterpreter *i) const { // call: dict length_d -> int assert(i->OStack.load()>0); DictionaryDatum *dict = dynamic_cast<DictionaryDatum *>(i->OStack.top().datum()); assert(dict != NULL); i->EStack.pop(); Token st(new IntegerDatum( (*dict)->size())); i->OStack.pop(); i->OStack.push_move(st); } void Empty_DFunction::execute(SLIInterpreter *i) const { // call: dict empty_D dict bool assert(i->OStack.load()>0); DictionaryDatum const * const dd = dynamic_cast<DictionaryDatum const * const>(i->OStack.top().datum()); assert(dd != NULL); i->OStack.push_by_pointer(new BoolDatum((*dd)->empty() )); i->EStack.pop(); } /* BeginDocumentation Name: countdictstack - return number of dictionaries on the dictionary stack. Synopsis: No arguments. Description: Returns the current load of the dictionary stack. The default value is 2. Parameters: None. SeeAlso: dictstack, cleardictstack, whos */ void CountdictstackFunction::execute(SLIInterpreter *i) const { // call: Countdictstack -> int i->EStack.pop(); Token st(new IntegerDatum(i->DStack->size())); i->OStack.push_move(st); } /* BeginDocumentation Name: dictstack - return current dictionary stack as array Synopsis: dictstack -> array Description: Returns an array whose entries are references to the dictionaries on the dictionary stack. The dictionaries are stored from bottom to top, such that the first array element refers to the bottom of the stack and the last array element to the top. SeeAlso: currentdict, countdictstack, cleardictstack, whos */ void DictstackFunction::execute(SLIInterpreter *i) const { // call: - dictstack -> array i->EStack.pop(); TokenArray ta; i->DStack->toArray(ta); Token st(new ArrayDatum(ta)); i->OStack.push_move(st); } /* BeginDocumentation Name: currentdict - return topmost dictionary of the dictionary stack Synopsis: currentdict -> dict Description: Returns a reference to the current dictionary. SeeAlso: dictstack, begin, end, cleardictstack, who, whos */ void CurrentdictFunction::execute(SLIInterpreter *i) const { // call: - currentdict -> dict i->EStack.pop(); Token dt; i->DStack->top(dt); i->OStack.push_move(dt); } /* BeginDocumentation Name: cleardictstack - Pop all non standard dictionaries off the dictionary stack. Description: Removes all non standard dictionaries off the dictionary stack. After this, only the systemdict and the userdict dictionaries remain on the dictionary stack. SeeAlso: dictstack, begin, end, currentdict, who, whos */ void CleardictstackFunction::execute(SLIInterpreter *i) const { // Pop all non-permanent dictionaries i->EStack.pop(); while(i->DStack->size() > 2) i->DStack->pop(); } /* BeginDocumentation Name: topinfo_d - print contents of top dictionary to stream Synopsis: ostream topinfo_d -> - Description: Print the contents of the top dictionary on the dictionary stack to the supplied stream. Parameters: ostream - a valid output stream Examples: Diagnostics: Bugs: Author: FirstVersion: Remarks: SeeAlso: dictstack, currentdict, info, who, whos */ void DicttopinfoFunction::execute(SLIInterpreter *i) const { // call: ostream Dicttopinfo assert(i->OStack.load()>0); OstreamDatum *outd = dynamic_cast<OstreamDatum*>(i->OStack.top().datum()); assert(outd != NULL); i->EStack.pop(); i->DStack->top_info(**outd); i->OStack.pop(); } /* BeginDocumentation Name: info_ds - print contents of all dictionaries on the dicitonary stack to stream Synopsis: ostream info_ds -> - Description: info_ds prints the contents of all dictionaries on the dictionary stack to the supplied ostream. Dictionaries are printed from bottom to top. Parameters: ostream - a valid output stream SeeAlso: dictstack, info, topinfo_d, who, whos */ void WhoFunction::execute(SLIInterpreter *i) const { // call: ostream assert(i->OStack.load()>0); OstreamDatum *outd = dynamic_cast<OstreamDatum*>(i->OStack.top().datum()); assert(outd != NULL); i->EStack.pop(); i->DStack->info(**outd); i->OStack.pop(); } /* BeginDocumentation Name: begin - Make a dictionary the current dictionary. Synopsis: dict begin -> - Parameters: dict - a dictionary object Description: begin opens a dictionary by pushing it on the dictionary stack. After begin, the opened dictionary is searched first whenever a name is resolved. SeeAlso: end, get_d, dictstack, cleardictstack, countdictstack */ void DictbeginFunction::execute(SLIInterpreter *i) const { // call: dict if(i->OStack.load()>0) { DictionaryDatum *dict = dynamic_cast<DictionaryDatum *>(i->OStack.top().datum()); if(dict != NULL) { i->EStack.pop(); i->DStack->push(*dict); i->OStack.pop(); return; } else i->raiseerror(i->ArgumentTypeError); } else i->raiseerror(i->StackUnderflowError); } /* BeginDocumentation Name: end - Close the current (topmost) dictionary. Synopsis: - end -> - Description: Closes the current dictionary by removing the top element of the dictionary stack. Note that end cannot pop the dictionary stack beyond the two standard dictionaries systemdict and userdict. If this is tried, a DictStackUnderflow Error is raised. Diagnostics: DictStackUnderflow SeeAlso: begin, dictstack, cleardictstack, countdictstack */ void DictendFunction::execute(SLIInterpreter *i) const { if(i->DStack->size()>2) // keep at least systemdict and userdict { // see sli-init.sli for details i->DStack->pop(); i->EStack.pop(); } else i->raiseerror("DictStackUnderflow"); } /* BeginDocumentation Name: undef - Remove a key from a dictionary. Synopsis: dict key undef -> - Parameters: dict - a (possibly empty) dictionary key - a literal name to be removed. Description: undef removes the definition of a name from the supplied dictionary. The name does not have to be present in the dicitonary. Examples: SLI ] /d << /a 1 /b 2 >> def SLI ] d info - -------------------------------------------------- Name Type Value - -------------------------------------------------- a integertype 1 b integertype 2 - -------------------------------------------------- Total number of entries: 2 SLI ] d /b undef SLI ] d info - -------------------------------------------------- Name Type Value - -------------------------------------------------- a integertype 1 - -------------------------------------------------- Total number of entries: 1 Diagnostics: None. Author: docu edited by Marc Oliver Gewaltig and Sirko Straube SeeAlso: get_d, put_d, known, lookup, info */ void UndefFunction::execute(SLIInterpreter *i) const { // call: dict key -> - if(i->OStack.load()>1) { DictionaryDatum *dict = dynamic_cast<DictionaryDatum *>(i->OStack.pick(1).datum()); if(dict != NULL) { LiteralDatum *key = dynamic_cast<LiteralDatum *>(i->OStack.pick(0).datum()); if(key != NULL) { i->EStack.pop(); #ifdef DICTSTACK_CACHE if((*dict)->is_on_dictstack()) i->DStack->clear_token_from_cache(*key); #endif (*dict)->erase(*key); i->OStack.pop(2); return; } else throw ArgumentType(0); } else throw ArgumentType(1); } else throw StackUnderflow(2,i->OStack.load()); } /* BeginDocumentation Name: <<>> - Create a new dictionary. Synopsis: << /key1 val1 ... /keyn valn >> -> dict Parameters: /key - literal name val - Object of any type Description: Constructs a dictionary with the entries which are specified by key-value pairs. Note that the key-value pairs are evaluated BEFORE the dictionary is constructed. << >> operates the following way: The characters << correspond to a mark which is pushed on the stack. Next, all following key-value pairs are evaluated. >> finally counts the number of pairs on the stack and constructs a new dictionary. Examples: <pre> SLI ] << /a 1 /b 2 >> info -------------------------------------------------- Name Type Value -------------------------------------------------- a integertype 1 b integertype 2 -------------------------------------------------- Total number of entries: 2 SLI ] << (a) (b) join cvlit 2 3 mul 2 add >> info -------------------------------------------------- Name Type Value -------------------------------------------------- ab integertype 8 -------------------------------------------------- Total number of entries: 1 </pre> Diagnostics: An ArgumentType error is raised if the initializer list does not consist of proper /key value pairs. References: The Red Book SeeAlso: clonedict, begin, cleardictstack, dict, dictstack, info, end */ void DictconstructFunction::execute(SLIInterpreter *i) const { // call: mark key1 val1 ... keyn valn -> dict size_t l = i->OStack.load(); if(l == 0) throw StackUnderflow(1,0); DictionaryDatum *dictd=new DictionaryDatum(new Dictionary); Token dict(dictd); LiteralDatum *key=NULL; static Token mark=i->baselookup(i->mark_name); size_t n = 0; //!< pick(1) is the first literal, then we count in steps of 2 while( ( n < l ) && !(i->OStack.pick(n) == mark )) { Token &val= (i->OStack.pick(n)); key = dynamic_cast<LiteralDatum *>(i->OStack.pick(n+1).datum()); if(key == NULL) { i->message(30, "DictConstruct", "Literal expected. Maybe initializer list is in the wrong order."); i->raiseerror(i->ArgumentTypeError); delete dictd; return; } (*dictd)->insert_move(*key, val); n+=2; // count number of elements } if (n==l) { i->message(30, "DictConstruct", "<< expected."); i->raiseerror(i->ArgumentTypeError); return; } if( n%2 != 0 ) // there must be an even number of objects { // above the mark i->message(30, "DictConstruct", "Initializer list must be pairs of literal and value."); i->raiseerror(i->ArgumentTypeError); return; } i->EStack.pop(); i->OStack.pop(n); i->OStack.top().move(dict); } /* BeginDocumentation Name: known - check whether a name is defined in a dictionary or object Synopsis: dict /key known -> bool int /key known -> bool Examples: modeldict /iaf_neuron known -> true modeldict /parkinson_neuron known -> false /iaf_psc_alpha_presc Create /Interpol_Order know -> true Author: docu edited by Sirko Straube SeeAlso: lookup */ void KnownFunction::execute(SLIInterpreter *i) const { // call: dict key -> bool DictionaryDatum *dict = dynamic_cast<DictionaryDatum *>(i->OStack.pick(1).datum()); LiteralDatum *key = dynamic_cast<LiteralDatum *>(i->OStack.pick(0).datum()); bool known=(*dict)->known(*key); i->EStack.pop(); // never forget me i->OStack.pop(1); i->OStack.top()=new BoolDatum(known); } /* BeginDocumentation Name: cleardict - Clears the contents of a dictionary Synopsis: dict cleardict SeeAlso: <<>>, clonedict, dictstack */ void CleardictFunction::execute(SLIInterpreter *i) const { // call: dict -> - assert(i->OStack.load()>0); DictionaryDatum *dict = dynamic_cast<DictionaryDatum *>(i->OStack.top().datum()); assert(dict != NULL); #ifdef DICTSTACK_CACHE if((*dict)->is_on_dictstack()) i->DStack->clear_dict_from_cache(*dict); #endif (*dict)->clear(); i->EStack.pop(); // never forget me i->OStack.pop(); } /* BeginDocumentation Name: clonedict - create a copy of a dictionary Synopsis: dict1 clonedict -> dict1 dict2 Description: clonedict creates a new dictionary dict2 with the same entries as dict1. Parameters: dict1 - a dictionary Examples: << /a 1 >> clonedict Diagnostics: None. Author: Marc-Oliver Gewaltig SeeAlso: <<>>, dict, cleardict */ void ClonedictFunction::execute(SLIInterpreter *i) const { // Clone a given dictionary (real copy) // call: dict clonedict -> dict1 dict2 assert(i->OStack.load()>0); DictionaryDatum *dict = dynamic_cast<DictionaryDatum *>(i->OStack.top().datum()); assert(dict != NULL); i->OStack.push(DictionaryDatum(new Dictionary(*(*dict)))); i->EStack.pop(); // never forget me } /* BeginDocumentation Name: cva_d - Convert dictionary to array Synopsis: dict cva_d -> array Description: cda converts a given dictionary to an array. The contents of the dictionay is mapped to the array in a form which is similar to the construction of an array, namely << key1 val1 ... keyn valn>> cva_d -> [key1 val1 ... keyn valn] Parameters: dict is a dictionary which may be empty Examples: << /a 1 /b 2>> cva_d -> [/a 1 /b 2] Diagnostics: no errors are issued. Remarks: The name follows the convention of PostScript and stands for ConVert to Array. Implementation: Class TokenMap provides an iterator which allows to step through the elements stored in the TokenMap. Member function begin() returns an iterator which points to the "first" element in the TokenMap and end() to the "last" element. operator ++ moves the iterator from one element to the next. Note, the iteration process itself does not define any order of the elements, e.g. in terms of the comparison operators. The only guaranteed function is that during the iteration from begin() to end() all elements in the TokenMap are accessed. Operator * applied to the iterator returns a pair. Member first of the pair is the key and member second is the value of the element the iterator points to. See @Book{Musser96, author = "Musser, David R. and Saini, Atul", title = "STL Tutorial and Reference Guide: {C++} Programming with the Standard Template Library", publisher = "Addison Wesley", year = 1996, isbn = "0-201-63398-1", pages = 432, address = {Reading Massachusetts}, note = "(hardcover)" } for a discussion of the definition and use of iterators in combination with containers. Author: Marc-oliver Gewaltig SeeAlso: keys, values, <<>>, cva */ void Cva_dFunction::execute(SLIInterpreter *i) const { i->EStack.pop(); assert(i->OStack.load()>0); DictionaryDatum *dict = dynamic_cast<DictionaryDatum *>(i->OStack.top().datum()); assert(dict != NULL); ArrayDatum *ad = new ArrayDatum(); ad->reserve((*dict)->size() * 2); for(TokenMap::const_iterator t = (*dict)->begin(); t != (*dict)->end(); t ++) { Token nt(new LiteralDatum((*t).first)); ad->push_back_move(nt); ad->push_back((*t).second); } i->OStack.pop(); i->OStack.push(ad); } /* BeginDocumentation Name: keys - Return array of keys in a dictionary Synopsis: dict keys -> array <</key1 val1 ... /keyn valn>> keys -> [/key1 ... /keyn] Description: "keys" converts the keys in a given dictionary to an array. The order of elements is the same as for the "values" command. Parameters: dict is a dictionary which may be empty Examples: << /a 1 /b 2>> keys -> [/a /b] Diagnostics: no errors are issued. Remarks: The commands "keys" and "values" return the same order of elements, when applied to the same dictionary. Apart from that, there is no particular order of elements in the returned array. Author: Ruediger Kupper First Version: 27-jun-2008 SeeAlso: keys, values, <<>>, cva */ void KeysFunction::execute(SLIInterpreter *i) const { i->EStack.pop(); assert(i->OStack.load()>0); DictionaryDatum *dict = dynamic_cast<DictionaryDatum *>(i->OStack.top().datum()); assert(dict != NULL); ArrayDatum *ad = new ArrayDatum(); for(TokenMap::const_iterator t = (*dict)->begin(); t != (*dict)->end(); t ++) { Token nt(new LiteralDatum((*t).first)); assert(! nt.empty()); ad->push_back_move(nt); } i->OStack.pop(); i->OStack.push(ad); } /* BeginDocumentation Name: values - Return array of values in a dictionary Synopsis: dict values -> array <</key1 val1 ... /keyn valn>> values -> [val1 ... valn] Description: "values" converts the values in a given dictionary to an array. The order of elements is the same as for the "keys" command. Parameters: dict is a dictionary which may be empty Examples: << /a 1 /b 2>> values -> [1 2] Diagnostics: no errors are issued. Remarks: The commands "keys" and "values" return the same order of elements, when applied to the same dictionary. Apart from that, there is no particular order of elements in the returned array. Author: Ruediger Kupper First Version: 27-jun-2008 SeeAlso: keys, values, <<>>, cva */ void ValuesFunction::execute(SLIInterpreter *i) const { i->EStack.pop(); assert(i->OStack.load()>0); DictionaryDatum *dict = dynamic_cast<DictionaryDatum *>(i->OStack.top().datum()); assert(dict != NULL); ArrayDatum *ad = new ArrayDatum(); for(TokenMap::const_iterator t = (*dict)->begin(); t != (*dict)->end(); t ++) { ad->push_back((*t).second); } i->OStack.pop(); i->OStack.push(ad); } void RestoredstackFunction::execute(SLIInterpreter *i) const { assert(i->OStack.load()>0); ArrayDatum *ad= dynamic_cast<ArrayDatum *>(i->OStack.top().datum()); assert(ad != NULL); TokenArray ta = *ad; DictionaryStack *olddstack =i->DStack; // copy current dstack i->DStack= new DictionaryStack; for(size_t j=0; j< ta.size(); ++j) { try{ DictionaryDatum dict = getValue<DictionaryDatum>(ta[j]); i->DStack->push(ta[j]); } catch(...) { delete i->DStack; i->DStack = olddstack; i->raiseerror(i->ArgumentTypeError); return; } } i->OStack.pop(); i->EStack.pop(); } const DictFunction dictfunction; const DictputFunction dictputfunction; const DictgetFunction dictgetfunction; const DictinfoFunction dictinfofunction; const DicttopinfoFunction dicttopinfofunction; const WhoFunction whofunction; const DictbeginFunction dictbeginfunction; const DictendFunction dictendfunction; const DictconstructFunction dictconstructfunction; const Length_dFunction length_dfunction; const Empty_DFunction empty_Dfunction; const DictstackFunction dictstackfunction; const CountdictstackFunction countdictstackfunction; const CleardictstackFunction cleardictstackfunction; const CurrentdictFunction currentdictfunction; const KnownFunction knownfunction; const UndefFunction undeffunction; const CleardictFunction cleardictfunction; const ClonedictFunction clonedictfunction; const Cva_dFunction cva_dfunction; const KeysFunction keysfunction; const ValuesFunction valuesfunction; const RestoredstackFunction restoredstackfunction; void init_slidict(SLIInterpreter *i) { i->createcommand("dict", &dictfunction); i->createcommand("put_d", &dictputfunction); i->createcommand("get_d", &dictgetfunction); i->createcommand("info_d", &dictinfofunction); i->createcommand("length_d", &length_dfunction); i->createcommand("empty_D", &empty_Dfunction); i->createcommand("topinfo_d", &dicttopinfofunction); i->createcommand("info_ds", &whofunction); i->createcommand("begin", &dictbeginfunction); i->createcommand(i->end_name,&dictendfunction); i->createcommand("undef",&undeffunction); i->createcommand(">>", &dictconstructfunction); i->createcommand("dictstack",&dictstackfunction); i->createcommand("countdictstack",&countdictstackfunction); i->createcommand("cleardictstack",&cleardictstackfunction); i->createcommand("currentdict",¤tdictfunction); i->createcommand("known",&knownfunction); i->createcommand("cleardict",&cleardictfunction); i->createcommand("clonedict",&clonedictfunction); i->createcommand("cva_d",&cva_dfunction); i->createcommand("keys",&keysfunction); i->createcommand("values",&valuesfunction); i->createcommand("restoredstack",&restoredstackfunction); }