OpenCog Framework  Branch: master, revision 6f0b7fc776b08468cf1b74aa9db028f387b4f0c0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SchemeSmobNew.cc
Go to the documentation of this file.
1 /*
2  * SchemeSmobNew.cc
3  *
4  * Scheme small objects (SMOBS) --creating new atoms -- for opencog.
5  *
6  * Copyright (c) 2008 Linas Vepstas <linas@linas.org>
7  */
8 
9 #ifdef HAVE_GUILE
10 
11 #include <vector>
12 
13 #include <cstddef>
14 #include <libguile.h>
15 
19 
20 using namespace opencog;
21 
22 /* ============================================================== */
30 std::string SchemeSmob::to_string(SCM node)
31 {
32  if (SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, node))
33  return misc_to_string(node);
34 
35  return "";
36 }
37 
46 {
47  return handle_to_string(h, 0);
48 }
49 
50 std::string SchemeSmob::handle_to_string(Handle h, int indent)
51 {
52  if (Handle::UNDEFINED == h) return "#<Undefined atom handle>";
53  if (NULL == h) return "#<Invalid handle>";
54 
55  // Print a scheme expression, so that the output can be saved
56  // to file, and then restored, as needed.
57  std::string ret = "";
58  for (int i=0; i< indent; i++) ret += " ";
59  ret += "(";
60  ret += classserver().getTypeName(h->getType());
61  NodePtr nnn(NodeCast(h));
62  LinkPtr lll(LinkCast(h));
63  if (nnn) {
64  ret += " \"";
65  ret += nnn->getName();
66  ret += "\"";
67 
68  // Print the truth value only after the node name
70  if (!tv->isDefaultTV()) {
71  ret += " ";
72  ret += tv_to_string (tv.get());
73  }
74 
75  // Print the attention value after the truth value
77  if (av != AttentionValue::DEFAULT_AV()) {
78  ret += " ";
79  ret += av_to_string (av.get());
80  }
81  ret += ")";
82  return ret;
83  }
84  else if (lll) {
85  // If there's a truth value, print it before the other atoms
87  if (!tv->isDefaultTV()) {
88  ret += " ";
89  ret += tv_to_string (tv.get());
90  }
91 
92  // Print the attention value after the truth value
94  if (av != AttentionValue::DEFAULT_AV()) {
95  ret += " ";
96  ret += av_to_string (av.get());
97  }
98 
99  // print the outgoing link set.
100  ret += "\n";
101  std::vector<Handle> oset = lll->getOutgoingSet();
102  unsigned int arity = oset.size();
103  for (unsigned int i=0; i<arity; i++) {
104  //ret += " ";
105  ret += handle_to_string(oset[i], /*(0==i)?0:*/indent+1);
106  ret += "\n";
107  //if (i != arity-1) ret += "\n";
108  }
109  for (int i=0; i < indent; i++) ret += " ";
110  ret += ")";
111  return ret;
112  }
113 
114  return ret;
115 }
116 
117 std::string SchemeSmob::handle_to_string(SCM node)
118 {
119  Handle h(scm_to_handle(node));
120  return handle_to_string(h, 0) + "\n";
121 }
122 
123 /* ============================================================== */
131 {
132  Handle* hp = new Handle(h); // so that the smart pointer increments!
133  // Force resolution to occur now, not later.
134  hp->operator->();
135  scm_gc_register_collectable_memory (hp,
136  sizeof(h), "opencog handle");
137 
138  SCM smob;
139  SCM_NEWSMOB (smob, cog_misc_tag, hp);
140  SCM_SET_SMOB_FLAGS(smob, COG_HANDLE);
141  return smob;
142 }
143 
145 {
146  if (not SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, sh))
147  return Handle::UNDEFINED;
148 
149  scm_t_bits misctype = SCM_SMOB_FLAGS(sh);
150  if (COG_HANDLE != misctype)
151  return Handle::UNDEFINED;
152 
153  Handle h(*((Handle *) SCM_SMOB_DATA(sh)));
154  scm_remember_upto_here_1(sh);
155  return h;
156 }
157 
158 /* ============================================================== */
162 SCM SchemeSmob::ss_atom (SCM suuid)
163 {
164  if (scm_is_false(scm_integer_p(suuid)))
165  scm_wrong_type_arg_msg("cog-atom", 1, suuid, "integer opencog uuid");
166 
167  // SCM_RETURN_NEWSMOB (cog_uuid_tag, suuid);
168  UUID uuid = scm_to_ulong(suuid);
169  return handle_to_scm(Handle(uuid));
170 }
171 
172 /* ============================================================== */
176 SCM SchemeSmob::ss_handle (SCM satom)
177 {
178  Handle h(scm_to_handle(satom));
179  if (Handle::UNDEFINED == h)
180  scm_wrong_type_arg_msg("cog-handle", 1, satom, "opencog atom");
181 
182  return scm_from_ulong(h.value());
183 }
184 
185 /* ============================================================== */
190 {
191  return scm_from_ulong(Handle::UNDEFINED.value());
192 }
193 
194 /* ============================================================== */
198 {
199  if (not SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, s))
200  return SCM_BOOL_F;
201 
202  scm_t_bits misctype = SCM_SMOB_FLAGS(s);
203  if (COG_HANDLE == misctype)
204  return SCM_BOOL_T;
205 
206  return SCM_BOOL_F;
207 }
208 
209 /* ============================================================== */
213 {
214  Handle h(scm_to_handle(s));
215  if (Handle::UNDEFINED == h)
216  return SCM_BOOL_F;
217 
218  if (NodeCast(h)) return SCM_BOOL_T;
219 
220  return SCM_BOOL_F;
221 }
222 
223 /* ============================================================== */
227 {
228  Handle h(scm_to_handle(s));
229  if (Handle::UNDEFINED == h)
230  return SCM_BOOL_F;
231 
232  if (LinkCast(h)) return SCM_BOOL_T;
233  return SCM_BOOL_F;
234 }
235 
236 /* ============================================================== */
242 Type SchemeSmob::verify_atom_type (SCM stype, const char *subrname, int pos)
243 {
244  if (scm_is_integer(stype))
245  return scm_to_ushort(stype);
246 
247  if (scm_is_true(scm_symbol_p(stype)))
248  stype = scm_symbol_to_string(stype);
249 
250  if (scm_is_false(scm_string_p(stype)))
251  scm_wrong_type_arg_msg(subrname, pos, stype, "name of opencog atom type");
252 
253  const char * ct = scm_i_string_chars(stype);
254  Type t = classserver().getType(ct);
255 
256  // Make sure that the type is good
257  if (NOTYPE == t)
258  scm_wrong_type_arg_msg(subrname, pos, stype, "name of opencog atom type");
259 
260  return t;
261 }
262 
263 
268 std::string SchemeSmob::verify_string (SCM sname, const char *subrname,
269  int pos, const char * msg)
270 {
271  if (scm_is_false(scm_string_p(sname)))
272  scm_wrong_type_arg_msg(subrname, pos, sname, msg);
273 
274  char * cname = scm_to_utf8_string(sname);
275  std::string name(cname);
276  free(cname);
277  return name;
278 }
279 
284 int SchemeSmob::verify_int (SCM sint, const char *subrname,
285  int pos, const char * msg)
286 {
287  if (scm_is_false(scm_integer_p(sint)))
288  scm_wrong_type_arg_msg(subrname, pos, sint, msg);
289 
290  return scm_to_int(sint);
291 }
292 
296 SCM SchemeSmob::ss_new_node (SCM stype, SCM sname, SCM kv_pairs)
297 {
298  Type t = verify_atom_type(stype, "cog-new-node", 1);
299 
300  // Special case handling for NumberNode
301  if (NUMBER_NODE == t and scm_is_number(sname)) {
302  sname = scm_number_to_string(sname, _radix_ten);
303  // TODO: if we're given a string, I guess maybe we should check
304  // that the string is convertible to a number ??
305  }
306  std::string name(verify_string (sname, "cog-new-node", 2,
307  "string name for the node"));
308 
309  AtomSpace* atomspace = get_as_from_list(kv_pairs);
310  if (NULL == atomspace) atomspace = ss_get_env_as("cog-new-node");
311 
312  Handle h;
313 
314  try
315  {
316  // Now, create the actual node... in the actual atom space.
317  h = atomspace->add_node(t, name);
318 
319  // tv->clone is called here, because, for the atomspace, we want
320  // to use a use-counted std:shared_ptr, whereas in guile, we are
321  // using a garbage-collected raw pointer. So clone makes up the
322  // difference.
323  const TruthValue *tv = get_tv_from_list(kv_pairs);
324  if (tv)
325  h->setTruthValue(tv->clone());
326 
327  // Was an attention value explicitly specified?
328  // If so, then we've got to set it.
329  AttentionValue *av = get_av_from_list(kv_pairs);
330  if (av) {
331  h->setAttentionValue(av->clone());
332  }
333  }
334  catch (const std::exception& ex)
335  {
336  throw_exception(ex.what(), "cog-new-node");
337  }
338 
339  scm_remember_upto_here_1(kv_pairs);
340  return handle_to_scm(h);
341 }
342 
349 SCM SchemeSmob::ss_node (SCM stype, SCM sname, SCM kv_pairs)
350 {
351  Type t = verify_atom_type(stype, "cog-node", 1);
352  std::string name = verify_string (sname, "cog-node", 2,
353  "string name for the node");
354 
355  AtomSpace* atomspace = get_as_from_list(kv_pairs);
356  if (NULL == atomspace) atomspace = ss_get_env_as("cog-node");
357 
358  // Now, look for the actual node... in the actual atom space.
359  Handle h(atomspace->get_handle(t, name));
360  if (Handle::UNDEFINED == h) return SCM_EOL;
361  if (NULL == h) return SCM_EOL;
362 
363  // If there was a truth value, change it.
364  const TruthValue *tv = get_tv_from_list(kv_pairs);
365  if (tv) {
366  h->setTruthValue(tv->clone());
367  }
368 
369  // If there was an attention value, change it.
370  const AttentionValue *av = get_av_from_list(kv_pairs);
371  if (av) {
372  h->setAttentionValue(av->clone());
373  }
374  scm_remember_upto_here_1(kv_pairs);
375  return handle_to_scm (h);
376 }
377 
378 /* ============================================================== */
379 
383 std::vector<Handle>
384 SchemeSmob::verify_handle_list (SCM satom_list, const char * subrname, int pos)
385 {
386  // Verify that second arg is an actual list. Allow null list
387  // (which is rather unusal, but legit. Allow embedded nulls
388  // as this can be convenient for writing scheme code.
389  if (!scm_is_pair(satom_list) and !scm_is_null(satom_list))
390  scm_wrong_type_arg_msg(subrname, pos, satom_list, "a list of atoms");
391 
392  std::vector<Handle> outgoing_set;
393  SCM sl = satom_list;
394  pos = 2;
395  while (scm_is_pair(sl)) {
396  SCM satom = SCM_CAR(sl);
397 
398  // Verify that the contents of the list are actual atoms.
399  Handle h(scm_to_handle(satom));
400  if (Handle::UNDEFINED != h) {
401  outgoing_set.push_back(h);
402  }
403  else if (scm_is_pair(satom) and !scm_is_null(satom_list)) {
404  // Allow lists to be specified: e.g.
405  // (cog-new-link 'ListLink (list x y z))
406  // Do this via a recursive call, flattening nested lists
407  // as we go along.
408  const std::vector<Handle> &oset =
409  verify_handle_list(satom, subrname, pos);
410  std::vector<Handle>::const_iterator it;
411  for (it = oset.begin(); it != oset.end(); ++it) {
412  outgoing_set.push_back(*it);
413  }
414  }
415  else if (scm_is_null(satom)) {
416  // No-op, just ignore.
417  }
418  else {
419  // Its legit to have embedded truth values, just skip them.
420  if (not SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, satom)) {
421  // If its not an atom, and its not a truth value, and
422  // its not an attention value, and its not an atomspace,
423  // then whatever it is, its bad.
424  scm_wrong_type_arg_msg(subrname, pos, satom, "opencog atom");
425  }
426  }
427  sl = SCM_CDR(sl);
428  pos++;
429  }
430 
431  return outgoing_set;
432 }
433 
437 SCM SchemeSmob::ss_new_link (SCM stype, SCM satom_list)
438 {
439  Handle h;
440  Type t = verify_atom_type(stype, "cog-new-link", 1);
441 
442  std::vector<Handle> outgoing_set;
443  outgoing_set = verify_handle_list(satom_list, "cog-new-link", 2);
444 
445  AtomSpace* atomspace = get_as_from_list(satom_list);
446  if (NULL == atomspace) atomspace = ss_get_env_as("cog-new-link");
447 
448  try
449  {
450  // Now, create the actual link... in the actual atom space.
451  h = atomspace->add_link(t, outgoing_set);
452 
453  // Fish out a truth value, if its there.
454  const TruthValue *tv = get_tv_from_list(satom_list);
455  if (tv) {
456  h->setTruthValue(tv->clone());
457  }
458 
459  // Was an attention value explicitly specified?
460  // If so, then we've got to set it.
461  const AttentionValue *av = get_av_from_list(satom_list);
462  if (av) {
463  h->setAttentionValue(av->clone());
464  }
465  }
466  catch (const std::exception& ex)
467  {
468  throw_exception(ex.what(), "cog-new-link");
469  }
470  scm_remember_upto_here_1(satom_list);
471  return handle_to_scm (h);
472 }
473 
479 SCM SchemeSmob::ss_link (SCM stype, SCM satom_list)
480 {
481  Type t = verify_atom_type(stype, "cog-link", 1);
482 
483  std::vector<Handle> outgoing_set;
484  outgoing_set = verify_handle_list (satom_list, "cog-link", 2);
485 
486  AtomSpace* atomspace = get_as_from_list(satom_list);
487  if (NULL == atomspace) atomspace = ss_get_env_as("cog-link");
488 
489  // Now, look to find the actual link... in the actual atom space.
490  Handle h(atomspace->get_handle(t, outgoing_set));
491  if (Handle::UNDEFINED == h) return SCM_EOL;
492  if (NULL == h) return SCM_EOL;
493 
494  // If there was a truth value, change it.
495  const TruthValue *tv = get_tv_from_list(satom_list);
496  if (tv) h->setTruthValue(tv->clone());
497 
498  // If there was an attention value, change it.
499  const AttentionValue *av = get_av_from_list(satom_list);
500  if (av) h->setAttentionValue(av->clone());
501 
502  scm_remember_upto_here_1(satom_list);
503  return handle_to_scm (h);
504 }
505 
506 /* ============================================================== */
513 SCM SchemeSmob::ss_delete (SCM satom, SCM kv_pairs)
514 {
515  Handle h = verify_handle(satom, "cog-delete");
516 
517  // It can happen that the atom has already been deleted, but we're
518  // still holding on to its UUID. This is rare... but possible. So
519  // don't crash when it happens. XXX Is it really possible? How?
520  if (NULL == h.operator->()) return SCM_BOOL_F;
521 
522  // The remove will fail/log warning if the incoming set isn't null.
523  if (h->getIncomingSetSize() > 0) return SCM_BOOL_F;
524 
525  AtomSpace* atomspace = get_as_from_list(kv_pairs);
526  if (NULL == atomspace) atomspace = ss_get_env_as("cog-delete");
527 
528  // AtomSpace::removeAtom() returns true if atom was deleted,
529  // else returns false
530  bool rc = atomspace->remove_atom(h, false);
531 
532  // Clobber the handle, too.
533  *((Handle *) SCM_SMOB_DATA(satom)) = Handle::UNDEFINED;
534  scm_remember_upto_here_1(satom);
535 
536  // rc should always be true at this point ...
537  if (rc) return SCM_BOOL_T;
538  return SCM_BOOL_F;
539 }
540 
541 /* ============================================================== */
547 SCM SchemeSmob::ss_delete_recursive (SCM satom, SCM kv_pairs)
548 {
549  Handle h = verify_handle(satom, "cog-delete-recursive");
550 
551  AtomSpace* atomspace = get_as_from_list(kv_pairs);
552  if (NULL == atomspace) atomspace = ss_get_env_as("cog-delete-recursive");
553 
554  bool rc = atomspace->remove_atom(h, true);
555 
556  // Clobber the handle, too.
557  *((Handle *) SCM_SMOB_DATA(satom)) = Handle::UNDEFINED;
558  scm_remember_upto_here_1(satom);
559 
560  if (rc) return SCM_BOOL_T;
561  return SCM_BOOL_F;
562 }
563 
564 /* ============================================================== */
571 SCM SchemeSmob::ss_purge (SCM satom, SCM kv_pairs)
572 {
573  Handle h = verify_handle(satom, "cog-purge");
574 
575  // It can happen that the atom has already been purged, but we're
576  // still holding on to its UUID. This is rare... but possible. So
577  // don't crash when it happens. XXX Is it really possible? How?
578  if (NULL == h.operator->()) return SCM_BOOL_F;
579 
580  // The purge will fail/log warning if the incoming set isn't null.
581  if (h->getIncomingSetSize() > 0) return SCM_BOOL_F;
582 
583  AtomSpace* atomspace = get_as_from_list(kv_pairs);
584  if (NULL == atomspace) atomspace = ss_get_env_as("cog-purge");
585 
586  // AtomSpace::purgeAtom() returns true if atom was purged,
587  // else returns false
588  bool rc = atomspace->purge_atom(h, false);
589 
590  // Clobber the handle, too.
591  *((Handle *) SCM_SMOB_DATA(satom)) = Handle::UNDEFINED;
592  scm_remember_upto_here_1(satom);
593 
594  // rc should always be true at this point ...
595  if (rc) return SCM_BOOL_T;
596  return SCM_BOOL_F;
597 }
598 
599 /* ============================================================== */
605 SCM SchemeSmob::ss_purge_recursive (SCM satom, SCM kv_pairs)
606 {
607  Handle h = verify_handle(satom, "cog-purge-recursive");
608 
609  AtomSpace* atomspace = get_as_from_list(kv_pairs);
610  if (NULL == atomspace) atomspace = ss_get_env_as("cog-purge-recursive");
611 
612  bool rc = atomspace->purge_atom(h, true);
613 
614  // Clobber the handle, too.
615  *((Handle *) SCM_SMOB_DATA(satom)) = Handle::UNDEFINED;
616  scm_remember_upto_here_1(satom);
617 
618  if (rc) return SCM_BOOL_T;
619  return SCM_BOOL_F;
620 }
621 
622 #endif
623 /* ===================== END OF FILE ============================ */
AttentionValuePtr getAttentionValue()
Definition: Atom.cc:146
bool purge_atom(Handle h, bool recursive=false)
Definition: AtomSpace.h:261
static SCM ss_purge_recursive(SCM, SCM)
static std::string av_to_string(const AttentionValue *)
Definition: SchemeSmobAV.cc:50
Handle add_node(Type t, const std::string &name="", bool async=false)
Definition: AtomSpace.cc:135
static SCM ss_node(SCM, SCM, SCM)
static std::string to_string(SCM)
static AttentionValue * get_av_from_list(SCM)
Definition: SchemeSmobAV.cc:25
std::shared_ptr< TruthValue > TruthValuePtr
Definition: TruthValue.h:85
std::shared_ptr< AttentionValue > AttentionValuePtr
virtual TruthValuePtr clone() const =0
static void throw_exception(const char *, const char *)
Definition: SchemeSmob.cc:150
static AtomSpace * get_as_from_list(SCM)
static scm_t_bits cog_misc_tag
Definition: SchemeSmob.h:59
static SCM ss_purge(SCM, SCM)
static SCM ss_delete(SCM, SCM)
Type getType() const
Definition: Atom.h:197
static std::string tv_to_string(const TruthValue *)
static int verify_int(SCM, const char *, int pos=1, const char *msg="expecting integer")
static SCM ss_node_p(SCM)
std::shared_ptr< Link > LinkPtr
Definition: Atom.h:53
void setTruthValue(TruthValuePtr)
Sets the TruthValue object of the atom.
Definition: Atom.cc:81
ClassServer & classserver(ClassServerFactory *=ClassServer::createInstance)
Definition: ClassServer.cc:159
static std::string handle_to_string(SCM)
static NodePtr NodeCast(const Handle &h)
Definition: Node.h:113
void setAttentionValue(AttentionValuePtr)
Sets the AttentionValue object of the atom.
Definition: Atom.cc:163
static SCM ss_new_link(SCM, SCM)
static const Handle UNDEFINED
Definition: Handle.h:77
unsigned long UUID
UUID == Universally Unique Identifier.
Definition: Handle.h:46
static SCM ss_undefined_handle(void)
static Type verify_atom_type(SCM, const char *, int pos=1)
static Handle scm_to_handle(SCM)
static SCM ss_atom(SCM)
bool remove_atom(Handle h, bool recursive=false)
Definition: AtomSpace.cc:344
static SCM ss_atom_p(SCM)
Handle get_handle(Type t, const std::string &str)
Definition: AtomSpace.h:294
const std::string & getTypeName(Type type)
Definition: ClassServer.cc:148
static std::vector< Handle > verify_handle_list(SCM, const char *, int pos=1)
AttentionValuePtr clone() const
Returns An AttentionValue* cloned from this AttentionValue.
static SCM ss_link_p(SCM)
static LinkPtr LinkCast(const Handle &h)
Definition: Link.h:263
static AttentionValuePtr DEFAULT_AV()
to be used as default attention value
std::shared_ptr< Node > NodePtr
Definition: Node.h:112
UUID value(void) const
Definition: Handle.h:85
TruthValuePtr getTruthValue()
Definition: Atom.cc:104
Type getType(const std::string &typeName)
Definition: ClassServer.cc:138
static std::string verify_string(SCM, const char *, int pos=1, const char *msg="expecting string")
static SCM ss_delete_recursive(SCM, SCM)
unsigned short Type
type of Atoms, represented as short integer (16 bits)
Definition: types.h:40
static Handle verify_handle(SCM, const char *, int pos=1)
static SCM _radix_ten
Definition: SchemeSmob.h:81
size_t getIncomingSetSize()
Get the size of the incoming set.
Definition: Atom.cc:310
static SCM handle_to_scm(Handle)
static SCM ss_handle(SCM)
Handle add_link(Type t, const HandleSeq &outgoing, bool async=false)
Definition: AtomSpace.cc:175
static SCM ss_new_node(SCM, SCM, SCM)
static AtomSpace * ss_get_env_as(const char *)
static SCM ss_link(SCM, SCM)
static std::string misc_to_string(SCM)
static TruthValue * get_tv_from_list(SCM)