OpenCog Framework  Branch: master, revision 6f0b7fc776b08468cf1b74aa9db028f387b4f0c0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SchemePrimitive.cc
Go to the documentation of this file.
1 /*
2  * SchemePrimitive.cc
3  *
4  * Allow C++ code to be invoked from scheme --
5  * by defining a scheme primitive function.
6  *
7  * Copyright (C) 2009, 2014, 2015 Linas Vepstas
8  */
9 
10 #include <exception>
11 
12 #include "SchemeEval.h"
13 #include "SchemePrimitive.h"
14 #include "SchemeSmob.h"
15 
16 using namespace opencog;
17 
18 bool PrimitiveEnviron::is_inited = false;
19 
20 #ifdef HAVE_GUILE2
21  #define C(X) ((scm_t_subr) X)
22 #else
23  #define C(X) ((SCM (*) ()) X)
24 #endif
25 
26 
32 {
33  if (is_inited) return;
34  is_inited = true;
35  scm_c_define_module("opencog extension", init_in_module, NULL);
36 
37  // Use, immediately after define. Kind of hacky-ish, but assorted
38  // C++ code will fail if they forget to use: so we use it, for them.
39  scm_c_use_module("opencog extension");
40 }
41 
45 {
46  scm_c_define_gsubr("opencog-extension", 2,0,0, C(do_call));
47 
48  // Export, because other modules will need to call this directly.
49  scm_c_export("opencog-extension", NULL);
50 }
51 
53 
54 void PrimitiveEnviron::do_register(const char * module,
55  const char *name, int nargs)
56 {
57  // Now enter guile mode, and do the actual work there.
58  tmp_module = module;
59  tmp_name = name;
60  tmp_nargs = nargs;
61  scm_with_guile(c_wrap_register, this);
62 }
63 
65 {
66  PrimitiveEnviron *self = (PrimitiveEnviron *) p;
67  self->really_do_register(self->tmp_module, self->tmp_name, self->tmp_nargs);
68  return NULL;
69 }
70 
81 void
82 PrimitiveEnviron::really_do_register(const char * module_name,
83  const char *name, int nargs)
84 {
85  init();
86 
87  // Scheme garbage collection will be managing the lifecycle
88  scm_gc_register_collectable_memory (this, get_size(),
89  "opencog primitive environ");
90 
91  // The (opencog extension) module
92  std::string modn = "opencog ";
93  modn += module_name;
94  SCM module = scm_c_define_module(modn.c_str(), NULL, NULL);
95  scm_c_use_module(modn.c_str());
96 
97  // The smob will hold a pointer to "this" -- the PrimitiveEnviron
98  SCM smob;
99  SCM_NEWSMOB (smob, SchemeSmob::cog_misc_tag, this);
100  SCM_SET_SMOB_FLAGS(smob, SchemeSmob::COG_EXTEND);
101 
102  // We need to give the smob a unique name. Using addr of this is
103  // sufficient for this purpose.
104 #define BUFLEN 40
105  char buff[BUFLEN];
106  snprintf(buff, BUFLEN, "cog-prim-%p", this);
107  scm_c_module_define(module, buff, smob);
108 
109  std::string wrapper = "(use-modules (opencog extension))";
110  wrapper += "(define-public (";
111  wrapper += name;
112  for (int i=0; i<nargs; i++)
113  {
114  wrapper += " ";
115  char arg = 'a' + i;
116  wrapper += arg;
117  }
118  wrapper += ") (opencog-extension ";
119  wrapper += buff;
120  wrapper += " (list";
121  for (int i=0; i<nargs; i++)
122  {
123  wrapper += " ";
124  char arg = 'a' + i;
125  wrapper += arg;
126  }
127  wrapper += ")))";
128  scm_c_eval_string_in_module(wrapper.c_str(), module);
129  // printf("Debug: do_regsiter %s\n", wrapper.c_str());
130 }
131 
132 SCM PrimitiveEnviron::do_call(SCM sfe, SCM arglist)
133 {
134  // First, get the environ.
135  PrimitiveEnviron *fe = verify_pe(sfe, "opencog-extension");
136 
137  SCM rc = SCM_EOL;
138 
139  // If the C++ code throws any exceptions, and no one else
140  // has caught them, then we have to catch them, and print
141  // an error message to the shell. Actually, we'll be nice
142  // nice about this, and convert the C++ exception into a
143  // scheme exception.
144  try
145  {
146  rc = fe->invoke(arglist);
147  }
148  catch (const std::exception& ex)
149  {
150  SchemeSmob::throw_exception(ex.what(), fe->get_name());
151  }
152  catch (...)
153  {
155  }
156  scm_remember_upto_here_1(sfe);
157  return rc;
158 }
159 
160 PrimitiveEnviron * PrimitiveEnviron::verify_pe(SCM spe, const char *subrname)
161 {
162  if (!SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, spe))
163  scm_wrong_type_arg_msg(subrname, 1, spe, "opencog primitive function");
164 
165  scm_t_bits misctype = SCM_SMOB_FLAGS(spe);
166  if (SchemeSmob::COG_EXTEND != misctype)
167  scm_wrong_type_arg_msg(subrname, 1, spe, "opencog primitive function");
168 
169  PrimitiveEnviron * pe = (PrimitiveEnviron *) SCM_SMOB_DATA(spe);
170  return pe;
171 }
172 
virtual SCM invoke(SCM)=0
static SCM do_call(SCM, SCM)
static void throw_exception(const char *, const char *)
Definition: SchemeSmob.cc:150
static scm_t_bits cog_misc_tag
Definition: SchemeSmob.h:59
static void * c_wrap_register(void *)
void do_register(const char *, const char *, int)
void really_do_register(const char *, const char *, int)
#define BUFLEN
virtual const char * get_name(void)=0
static PrimitiveEnviron * verify_pe(SCM, const char *)
#define C(X)
static void init_in_module(void *)
virtual size_t get_size(void)=0