Add support for manual %docstrings, so users can provide texinfo help for wrapped functions.

Add some support for autodoc feature, so otherwise undocumented functions at least get prototype.
Fix bug in argument number check.



git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@10341 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Xavier Delacour 2008-04-03 13:22:19 +00:00
commit 05097de0ff
3 changed files with 191 additions and 77 deletions

View file

@ -4,3 +4,5 @@
%include <octuserdir.swg>
%include <octtypemaps.swg>
%include <octopers.swg>
%define %docstring %feature("docstring") %enddef

View file

@ -4,7 +4,7 @@ SWIGRUNTIME bool SWIG_check_num_args(const char *func_name, int num_args, int ma
if (num_args > max_args && !varargs)
error("function %s takes at most %i arguments", func_name, max_args);
else if (num_args < min_args)
error("function %s requires at least %i arguments", func_name, max_args);
error("function %s requires at least %i arguments", func_name, min_args);
else
return true;
return false;
@ -172,6 +172,7 @@ namespace {
swig_type_info **type;
int director;
octave_func constructor;
const char *constructor_doc;
octave_func destructor;
const swig_octave_member *members;
const char **base_names;
@ -385,6 +386,14 @@ namespace {
return (long) this;
return (long) types[0].second.ptr;
}
const char* help_text() const {
if (!types.size())
return 0;
if (!types[0].first->clientdata)
return 0;
swig_octave_class *c = (swig_octave_class *) types[0].first->clientdata;
return c->constructor_doc;
}
std::string swig_type_name() const {
// * need some way to manually name subclasses.
@ -420,10 +429,19 @@ namespace {
for (member_map::const_iterator it = members.begin(); it != members.end(); ++it) {
if (it->second.first && it->second.first->method)
install_builtin_function(it->second.first->method, it->first,
/*it->second.first->doc?it->second.first->doc:*/std::string());
it->second.first->doc?it->second.first->doc:std::string());
else if (it->second.second.is_defined()) {
link_to_global_variable(curr_sym_tab->lookup(it->first, true));
set_global_value(it->first, it->second.second);
octave_swig_type *ost = Swig::swig_value_deref(it->second.second);
if (ost) {
const char* h = ost->help_text();
if (h) {
symbol_record *sr = global_sym_tab->lookup (it->first, true);
sr->document(h);
}
}
}
}
}

View file

@ -42,28 +42,28 @@ private:
String *decl_info;
String *cdecl_info;
String *synopsis;
String *inarg_info;
String *outarg_info;
String *args_info;
doc_info() {
decl_info=NewString("");
cdecl_info=NewString("");
synopsis=NewString("");
inarg_info=NewString("");
outarg_info=NewString("");
args_info=NewString("");
}
doc_info(const doc_info& x) {
decl_info = Copy(x.decl_info);
cdecl_info = Copy(x.cdecl_info);
synopsis = Copy(x.synopsis);
inarg_info = Copy(x.inarg_info);
outarg_info = Copy(x.outarg_info);
args_info = Copy(x.args_info);
}
~doc_info() {
Delete(decl_info);
Delete(cdecl_info);
Delete(synopsis);
Delete(inarg_info);
Delete(outarg_info);
Delete(args_info);
}
bool empty() const {
return !Len(decl_info) && !Len(cdecl_info) &&
!Len(synopsis) && !Len(args_info);
}
};
typedef std::map<std::string, doc_info> doc_info_map;
@ -164,10 +164,8 @@ public:
if (!CPlusPlus)
Printf(f_header,"}\n");
/*
if (docs.size())
emit_doc_texinfo();
*/
if (directorsEnabled())
Swig_insert_file("director.swg", f_runtime);
@ -201,23 +199,117 @@ public:
return SWIG_OK;
}
/*
String *texinfo_escape(String *_s) {
const char* s=(const char*)Data(_s);
while (*s&&(*s=='\t'||*s=='\r'||*s=='\n'||*s==' '))
++s;
std::string r;
std::string nl="\\\n";
for (int j=0;s[j];++j) {
if (s[j] == '\n')
r+="\\n"+nl;
else if (s[j] == '\r')
r+="\\r"+nl;
else if (s[j] == '\t')
r+="\\t"+nl;
else if (s[j] == '\\')
r+="\\\\"+nl;
else if (s[j] == '\'')
r+="\\\'"+nl;
else if (s[j] == '\"')
r+="\\\""+nl;
else
r+=s[j];
}
return NewString(r.c_str());
}
void emit_doc_texinfo() {
for (doc_info_map::iterator it=docs.begin();
it!=docs.end();++it) {
doc_info& d=it->second;
String *wrap_name=NewString(it->first.c_str());
Printf(f_doc,"const char* %s_texinfo = \"",wrap_name);
String *doc_str = NewString("");
Printv(doc_str, d.synopsis, d.decl_info, d.cdecl_info, d.args_info, NIL);
String *escaped_doc_str = texinfo_escape(doc_str);
if (Len(doc_str)>0) {
Printf(f_doc,"const char* %s_texinfo = ",wrap_name);
Printf(f_doc,"\"-*- texinfo -*-\\n\\\n%s", escaped_doc_str);
if (Len(d.decl_info))
Printf(f_doc,"\\n\\\n@end deftypefn");
Printf(f_doc,"\";\n");
}
Delete(escaped_doc_str);
Delete(doc_str);
Delete(wrap_name);
Printf(f_doc,"-*- texinfo -*-\\n");
Printv(f_doc,d.decl_info,d.cdecl_info,d.inarg_info,d.outarg_info,NIL);
if (Len(d.decl_info))
Printf(f_doc,"@end deftypefn");
Printf(f_doc,"\";\n");
}
Printf(f_doc,"\n");
}
*/
String *texinfo_name(Node* n) {
String *tname = NewString("");
String *iname = Getattr(n, "sym:name");
String *wname = Swig_name_wrapper(iname);
doc_info& d = docs[(const char*)Data(wname)];
if (d.empty())
Printf(tname, "0");
else
Printf(tname, "%s_texinfo", wname);
return tname;
}
void process_autodoc(Node *n) {
String *iname = Getattr(n, "sym:name");
String *name = Getattr(n, "name");
String *wname = Swig_name_wrapper(iname);
String *str = Getattr(n, "feature:docstring");
bool autodoc_enabled = !Cmp(Getattr(n, "feature:autodoc"), "1");
doc_info& d = docs[(const char*)Data(wname)];
// * couldn't we just emit the docs here?
if (autodoc_enabled) {
String *decl_str = NewString("");
String *args_str = NewString("");
make_autodocParmList(n, decl_str, args_str);
Append(d.decl_info, "@deftypefn {Loadable Function} ");
SwigType *type = Getattr(n, "type");
if (type && Strcmp(type, "void")) {
type = SwigType_base(type);
Node *lookup = Swig_symbol_clookup(type, 0);
if (lookup)
type = Getattr(lookup, "sym:name");
Append(d.decl_info, "@var{retval} = ");
String *type_str = NewString("");
Printf(type_str, "@var{retval} is of type %s. ", type);
Append(args_str, type_str);
Delete(type_str);
}
Append(d.decl_info, name);
Append(d.decl_info, " (");
Append(d.decl_info, decl_str);
Append(d.decl_info, ")\n");
Append(d.args_info, args_str);
Delete(decl_str);
Delete(args_str);
}
if (str && Len(str) > 0) {
// strip off {} if necessary
char *t = Char(str);
if (*t == '{') {
Delitem(str, 0);
Delitem(str, DOH_END);
}
// emit into synopsis section
Append(d.synopsis, str);
}
}
virtual int importDirective(Node *n) {
String *modname = Getattr(n, "module");
@ -234,20 +326,16 @@ public:
return conv ? "SWIG_POINTER_IMPLICIT_CONV" : "0";
}
String *make_autodocParmList(Node *n, bool showTypes) {
String *doc = NewString("");
void make_autodocParmList(Node *n, String *decl_str, String *args_str) {
String *pdocs = Copy(Getattr(n, "feature:pdocs"));
ParmList *plist = CopyParmList(Getattr(n, "parms"));
Parm *p;
Parm *pnext;
Node *lookup;
int lines = 0;
const int maxwidth = 50;
if (pdocs)
Append(pdocs, "\n");
Swig_typemap_attach_parms("in", plist, 0);
Swig_typemap_attach_parms("doc", plist, 0);
@ -268,6 +356,12 @@ public:
type = type ? type : Getattr(p, "type");
value = value ? value : Getattr(p, "value");
String *tex_name = NewString("");
if (name)
Printf(tex_name, "@var{%s}", name);
else
Printf(tex_name, "@var{?}");
String *tm = Getattr(p, "tmap:in");
if (tm) {
pnext = Getattr(p, "tmap:in:next");
@ -275,55 +369,41 @@ public:
pnext = nextSibling(p);
}
if (Len(doc)) {
// add a comma to the previous one if any
Append(doc, ", ");
// Do we need to wrap a long line?
if ((Len(doc) - lines * maxwidth) > maxwidth) {
Printf(doc, "\n%s", tab4);
lines += 1;
}
}
// Do the param type too?
if (showTypes) {
type = SwigType_base(type);
lookup = Swig_symbol_clookup(type, 0);
if (lookup)
type = Getattr(lookup, "sym:name");
Printf(doc, "%s ", type);
}
if (name) {
Append(doc, name);
if (pdoc) {
if (!pdocs)
pdocs = NewString("Parameters:\n");
Printf(pdocs, " %s\n", pdoc);
}
} else {
Append(doc, "?");
}
if (Len(decl_str))
Append(decl_str, ", ");
Append(decl_str, tex_name);
if (value) {
if (Strcmp(value, "NULL") == 0)
value = NewString("None");
value = NewString("nil");
else if (Strcmp(value, "true") == 0 || Strcmp(value, "TRUE") == 0)
value = NewString("True");
value = NewString("true");
else if (Strcmp(value, "false") == 0 || Strcmp(value, "FALSE") == 0)
value = NewString("False");
value = NewString("false");
else {
lookup = Swig_symbol_clookup(value, 0);
if (lookup)
value = Getattr(lookup, "sym:name");
}
Printf(doc, "=%s", value);
Printf(decl_str, " = %s", value);
}
if (type) {
String *type_str = NewString("");
type = SwigType_base(type);
lookup = Swig_symbol_clookup(type, 0);
if (lookup)
type = Getattr(lookup, "sym:name");
Printf(type_str, "%s is of type %s. ", tex_name, type);
Append(args_str, type_str);
Delete(type_str);
}
Delete(tex_name);
}
if (pdocs)
Setattr(n, "feature:pdocs", pdocs);
Delete(plist);
return doc;
}
virtual int functionWrapper(Node *n) {
@ -352,9 +432,6 @@ public:
Append(overname, Getattr(n, "sym:overname"));
Printv(f->def, "static octave_value_list ", overname, " (const octave_value_list& args, int nargout) {", NIL);
if (!overloaded || last_overload)
Printf(s_global_tab, "{\"%s\",%s,0,0,2,0},\n", iname, wname, wname);
// Printf(s_global_tab, "{\"%s\",%s,0,0,2,%s_texinfo},\n", iname, wname, wname);
emit_args(d, l, f);
emit_attach_parmmaps(l, f);
@ -545,17 +622,24 @@ public:
Printf(f->code, "}\n");
Replaceall(f->code, "$symname", iname);
Wrapper_print(f, f_wrappers);
DelWrapper(f);
if (last_overload)
dispatchFunction(n);
if (!overloaded || last_overload) {
process_autodoc(n);
String *tname = texinfo_name(n);
Printf(s_global_tab, "{\"%s\",%s,0,0,2,%s},\n", iname, wname, tname);
Delete(tname);
}
Delete(overname);
Delete(wname);
Delete(cleanup);
Delete(outarg);
if (last_overload)
dispatchFunction(n);
return SWIG_OK;
}
@ -782,11 +866,13 @@ public:
if (have_constructor) {
String *cname = Swig_name_construct(constructor_name);
String *wcname = Swig_name_wrapper(cname);
Printf(f_wrappers, "%s,", wcname);
String *tname = texinfo_name(n);
Printf(f_wrappers, "%s,%s,", wcname, tname);
Delete(tname);
Delete(wcname);
Delete(cname);
} else
Printv(f_wrappers, "0", ",", NIL);
Printv(f_wrappers, "0,0,", NIL);
if (have_destructor)
Printv(f_wrappers, "_wrap_delete_", class_name, ",", NIL);
else
@ -813,16 +899,20 @@ public:
String *realname = iname ? iname : name;
String *rname = Swig_name_wrapper(Swig_name_member(class_name, realname));
if (!Getattr(n, "sym:nextSibling"))
// Printf(s_members_tab, "{\"%s\",%s,0,0,0,%s_texinfo},\n",
Printf(s_members_tab, "{\"%s\",%s,0,0,0,0},\n",
realname, rname, rname);
if (!Getattr(n, "sym:nextSibling")) {
String *tname = texinfo_name(n);
Printf(s_members_tab, "{\"%s\",%s,0,0,0,%s},\n",
realname, rname, tname);
Delete(tname);
}
Delete(rname);
return SWIG_OK;
}
virtual int membervariableHandler(Node *n) {
Setattr(n, "feature:autodoc", "0");
Language::membervariableHandler(n);
assert(s_members_tab);
@ -882,11 +972,13 @@ public:
String *realname = iname ? iname : name;
String *rname = Swig_name_wrapper(Swig_name_member(class_name, realname));
if (!Getattr(n, "sym:nextSibling"))
// Printf(s_members_tab, "{\"%s\",%s,0,0,1,%s_texinfo},\n",
Printf(s_members_tab, "{\"%s\",%s,0,0,1,0},\n",
realname, rname, rname);
if (!Getattr(n, "sym:nextSibling")) {
String *tname = texinfo_name(n);
Printf(s_members_tab, "{\"%s\",%s,0,0,1,%s},\n",
realname, rname, tname);
Delete(tname);
}
Delete(rname);
return SWIG_OK;
}
@ -896,6 +988,8 @@ public:
}
virtual int staticmembervariableHandler(Node *n) {
Setattr(n, "feature:autodoc", "0");
Language::staticmembervariableHandler(n);
if (!GetFlag(n, "wrappedasconstant")) {