input/output assignment in templates is working for non-trivial cases. Updated parse_tree to handle '/IO' and '/S' modifiers

This commit is contained in:
hbristow 2013-06-21 22:55:48 -07:00
parent 1a15ed3279
commit f45bc35652
5 changed files with 74 additions and 43 deletions

View File

@ -7,11 +7,10 @@ def inputs(args):
In OpenCV input arguments are all arguments with names
not beginning with 'dst'
'''
out = []
for arg in args:
if not arg.name.startswith('dst'):
out.append(arg)
return out
try:
return [arg for arg in args['only'] if arg.I and not arg.O]
except:
return [arg for arg in args if arg.I]
def ninputs(args):
'''Counts the number of input arguments in the input list'''
@ -22,15 +21,24 @@ def outputs(args):
reference, and returns a list of only those elements.
In OpenCV, output references are preceeded by 'dst'
'''
out = []
for arg in args:
if arg.name.startswith('dst'):
out.append(arg)
return out
try:
return [arg for arg in args['only'] if arg.O and not arg.I]
except:
return [arg for arg in args if arg.O]
def only(args):
'''Returns exclusively the arguments which are only inputs
or only outputs'''
d = {};
d['only'] = args
return d
def void(arg):
return arg == 'void'
def flip(arg):
return not arg
def output(arg):
return True if arg.name.startswith('dst') else False
def noutputs(args):
'''Counts the number of output arguments in the input list'''
return len(outputs(args))

View File

@ -32,10 +32,13 @@ class MatlabWrapperGenerator(object):
jtemplate.filters['toUnderCase'] = toUnderCase
jtemplate.filters['comment'] = comment
jtemplate.filters['inputs'] = inputs
jtemplate.filters['outputs'] = outputs
jtemplate.filters['output'] = output
jtemplate.filters['noutputs'] = noutputs
jtemplate.filters['ninputs'] = ninputs
jtemplate.filters['outputs'] = outputs
jtemplate.filters['noutputs'] = noutputs
jtemplate.filters['only'] = only
jtemplate.filters['void'] = void
jtemplate.filters['not'] = flip
# load the templates
tfunction = jtemplate.get_template('template_function_base.cpp')

View File

@ -65,6 +65,7 @@ class Translator(object):
name = self.translateName(defn[0])
clss = self.translateClassName(defn[0])
rtp = defn[1]
static = True if 'S' in ''.join(defn[2]) else False
args = defn[3]
req = []
opt = []
@ -72,7 +73,7 @@ class Translator(object):
if arg:
a = self.translateArgument(arg)
opt.append(a) if a.default else req.append(a)
return Function(name, clss, '', rtp, False, req, opt)
return Function(name, clss, static, '', rtp, False, req, opt)
def translateConstant(self, defn):
const = True if 'const' in defn[0] else False
@ -83,10 +84,16 @@ class Translator(object):
return Constant(name, clss, tp, const, '', val)
def translateArgument(self, defn):
tp = defn[0]
ref = '*' if '*' in defn[0] else ''
ref = '&' if '&' in defn[0] else ref
const = ' const ' in ' '+defn[0]+' '
tp = " ".join([word for word in defn[0].replace(ref, '').split() if not ' const ' in ' '+word+' '])
name = defn[1]
default = defn[2] if defn[2] else ''
return Argument(name, tp, False, '', default)
modifiers = ''.join(defn[3])
I = True if not modifiers or 'I' in modifiers else False
O = True if 'O' in modifiers else False
return Argument(name, tp, const, I, O, ref, default)
def translateName(self, name):
return name.split(' ')[-1].split('.')[-1]
@ -123,9 +130,10 @@ class Class(object):
(join((f.__str__() for f in self.functions), '\n\t') if self.functions else '')+'\n};'
class Function(object):
def __init__(self, name='', clss='', namespace='', rtp='', const=False, req=None, opt=None):
def __init__(self, name='', clss='', static=False, namespace='', rtp='', const=False, req=None, opt=None):
self.name = name
self.clss = clss
self.static = static
self.const = const
self.namespace = namespace
self.rtp = rtp
@ -138,10 +146,12 @@ class Function(object):
')'+(' const' if self.const else '')+';'
class Argument(object):
def __init__(self, name='', tp='', const=False, ref='', default=''):
def __init__(self, name='', tp='', const=False, I=True, O=False, ref='', default=''):
self.name = name
self.tp = tp
self.ref = ref
self.I = I
self.O = O
self.const = const
self.default = default

View File

@ -1,13 +1,24 @@
// compose a function
{% macro compose(fun, retname="ret") %}
{%- if not fun.rtp == "void" -%} {{fun.rtp}} retname = {% endif -%}
{{fun.name}}(
/*
* compose
* compose a function call
* This macro takes as input a Function object and composes
* a function call by inspecting the types and argument names
*/
/
{% macro compose(fun) %}
{# ----------- Return type ------------- #}
{%- if not fun.rtp|void -%} {{fun.rtp}} retval = {% endif -%}
cv::{{fun.name}}(
{#- ----------- Required ------------- -#}
{%- for arg in fun.req -%}
{%- if arg.ref == '*' -%}&{%- endif -%}
{{arg.name}}
{%- if not loop.last %}, {% endif %}
{% endfor %}
{#- ----------- Optional ------------- -#}
{% if fun.req and fun.opt %}, {% endif %}
{%- for opt in fun.opt -%}
{%- if opt.ref == '*' -%}&{%- endif -%}
{{opt.name}}
{%- if not loop.last -%}, {% endif %}
{%- endfor -%}
@ -18,19 +29,18 @@
{%- macro generate(fun) -%}
// unpack the arguments
// inputs
{# ----------- Inputs ------------- #}
{% for arg in fun.req|inputs %}
{{arg.tp}} {{arg.name}} = inputs[{{ loop.index0 }}];
{% endfor %}
{% for opt in fun.opt|inputs %}
{{opt.tp}} {{opt.name}} = (nrhs > {{loop.index0 + fun.req|ninputs}}) ? inputs[{{loop.index0 + fun.req|ninputs}}] : {{opt.default}};
{{opt.tp}} {{opt.name}} = (nrhs > {{loop.index0 + fun.req|inputs|length}}) ? inputs[{{loop.index0 + fun.req|inputs|length}}] : {{opt.default}};
{% endfor %}
// outputs
{% for arg in fun.req|outputs %}
{# ----------- Outputs ------------ #}
{% for arg in fun.req|only|outputs %}
{{arg.tp}} {{arg.name}};
{% endfor %}
{% for opt in fun.opt|outputs %}
{% for opt in fun.opt|only|outputs %}
{{opt.tp}} {{opt.name}};
{% endfor %}
@ -47,11 +57,14 @@
}
// assign the outputs into the bridge
{% if not fun.rtp|void %}
outputs[0] = retval;
{% endif %}
{% for arg in fun.req|outputs %}
outputs[{{loop.index0}}] = {{arg.name}};
outputs[{{loop.index0 + fun.rtp|void|not}}] = {{arg.name}};
{% endfor %}
{% for opt in fun.opt|outputs %}
outputs[{{loop.index0 + fun.req|noutputs}}] = {{opt.name}};
outputs[{{loop.index0 + fun.rtp|void|not + fun.req|outputs|length}}] = {{opt.name}};
{% endfor %}
{%- endmacro -%}

View File

@ -13,14 +13,13 @@
#include <string>
#include <vector>
#include <exception>
#include <opencv2/{{ns}}.hpp>
#include <opencv2/{{includes}}.hpp>
{% block includes %}
{% endblock %}
using namespace std;
using namespace cv;
/*
* {{ fun.name }}
* {{ fun }}
* Gateway routine
* nlhs - number of return arguments
* plhs - pointers to return arguments
@ -31,15 +30,13 @@ void mexFunction(int nlhs, mxArray* plhs[],
int nrhs, const mxArray* prhs[]) {
// assertions
mxAssert(nrhs >= {{fun.req|length - fun.req|noutputs}}, "Too few required input arguments specified");
mxAssert(nrhs <= {{fun.req|length + fun.opt|length - fun.req|noutputs - fun.opt|noutputs}}, "Too many input arguments specified");
mxAssert(nlhs <= {{fun.ret|length + fun.req|noutputs + fun.opt|noutputs}}, "Too many output arguments specified");
mxAssert(nrhs >= {{fun.req|length - fun.req|outputs|length}}, "Too few required input arguments specified");
mxAssert(nrhs <= {{fun.req|length + fun.opt|length - fun.req|outputs|length - fun.opt|outputs|length}}, "Too many input arguments specified");
mxAssert(nlhs <= {{ fun.rtp|void|not + fun.req|outputs|length + fun.opt|outputs|length}}, "Too many output arguments specified");
// setup
vector<Bridge> inputs(plhs, plhs+nrhs);
vector<Bridge> outputs(nlhs);
{{ fun }}
std::vector<Bridge> inputs(plhs, plhs+nrhs);
std::vector<Bridge> outputs(nlhs);
{{ functional.generate(fun) }}