[m2sci] kernel code reorganization: clarify dependencies & ease code browsing
[scilab.git] / scilab / modules / m2sci / macros / kernel / m2sci.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) 2002-2004 - INRIA - Vincent COUVERT
3 //
4 // Copyright (C) 2012 - 2016 - Scilab Enterprises
5 //
6 // This file is hereby licensed under the terms of the GNU GPL v2.0,
7 // pursuant to article 5.3.4 of the CeCILL v.2.1.
8 // This file was originally licensed under the terms of the CeCILL v2.1,
9 // and continues to be available under such terms.
10 // For more information, see the COPYING file which you should have received
11 // along with this program.
12
13 function [scitree,trad,txt,crp]=m2sci(mtlbtree,nam,Recmode,prettyprintoutput)
14     // This function translates Matlab interpreted code tree of a function to Scilab
15     // Input arguments:
16     //  - mtlbtree: tree (returned by macr2tree) representing Matlab function compiled code
17     //  - nam: name of Matlb function
18     //  - Recmode: boolean flag for recursive conversion if TRUE
19     //  - prettyprintoutput: boolean flag for pretty printed output file if TRUE
20     // Output arguments:
21     //  - scitree: Scilab equivalent for mtlbtree
22     //  - trad: code of function sci_<nam>
23     //  - txt: Scilab equivalent function code (function declaration and variables initialisation)
24     //  - crp: Scilab equivalent function code (function body)
25
26     [lhs,rhs]=argn(0)
27     if rhs==1 then
28         error(gettext("Wrong number of inputs."))
29     end
30     if rhs==2 then Recmode=%f,end
31
32     lcount=1;
33
34     // Level of clause indentation (used for getting temporary variables and for updating varslist)
35     // if there is not a clause then size of level = 1 and the value is 0 (level=0)
36     // add one size at level each time a new clause is found
37     // if just one clause then size of level = 2,  the value of level(2) : the index of clause part for the first clause (1 for 'if' statements, 2 for first 'elseif' statements, 3 for first 'elseif' statements,...)
38     // if there are 2 clauses, then size of level = 3, the value of level(3) : the index of clause part for the second clause (1 for if statements, 2 for first elseif statements, 3 for second elseif statements,...)
39     // for example : level = [0,4,1] : in this case there are 2 clauses the index for the first clause (i.e level(2)) is 4 (4 for second 'elseif' statements), the index for the second clause (i.e level(3)) is 1 (1 for 'if' statements)
40     // the first components of level (i.e level(1)) is always 0 (because in the zero level there is no clause, so there is no 'if' no 'elseif' no 'else')
41     level=0
42
43     // Parameters declaration
44     sciparam()
45
46     // Scilab variable types
47     Double=1;
48     Boolean=4; // Boolean type can also be 6
49     Sparse=5;
50     Int=8;
51     Handle=9;
52     String=10;
53     Cell=17;
54     Struct=16;
55     Void=0;
56     Unknown=-1; // Unknown type or dimension
57     SupToOne=-2; // Dimension >1
58     NotNull=-3; // Dimension >0
59     Complex=1 //"Complex"
60     Real=0 //"Real"
61     Units=["pixels","centimeters","points","inches","normalized"]
62
63     global %graphics
64     %graphics=struct()
65     %graphics.type=Double
66     %graphics.units="pixels"
67
68     // Translated function input arguments
69     macrhs=size(mtlbtree.inputs)
70     global("varslist")
71     varslist=list()
72     for k=1:macrhs
73         if funptr(mtlbtree.inputs(k).name)<>0 then // Matlab variable name corresponding to a Scilab function name
74             varslist($+1)=M2scivar("%"+mtlbtree.inputs(k).name,mtlbtree.inputs(k).name,Infer())
75             mtlbtree.inputs(k).name="%"+mtlbtree.inputs(k).name,
76         elseif mtlbtree.inputs(k).name=="varargin" then
77             varslist($+1)=M2scivar("varargin","varargin",Infer(list(Unknown,Unknown),Type(Cell,Unknown)))
78         else
79             varslist($+1)=M2scivar(mtlbtree.inputs(k).name,mtlbtree.inputs(k).name,Infer())
80         end
81     end
82     // Add predefined variables in the defined variables
83     varslist($+1)=M2scivar("%i","%i",Infer(list(1,1),Type(Double,Complex)))
84     varslist($+1)=M2scivar("%i","%j",Infer(list(1,1),Type(Double,Complex)))
85     varslist($+1)=M2scivar("%nan","NaN",Infer(list(1,1),Type(Double,Real)))
86     varslist($+1)=M2scivar("%nan","nan",Infer(list(1,1),Type(Double,Real)))
87     varslist($+1)=M2scivar("%inf","Inf",Infer(list(1,1),Type(Double,Real)))
88     varslist($+1)=M2scivar("%inf","inf",Infer(list(1,1),Type(Double,Real)))
89     varslist($+1)=M2scivar("%pi","pi",Infer(list(1,1),Type(Double,Real)))
90     varslist($+1)=M2scivar("%eps","eps",Infer(list(1,1),Type(Double,Real)))
91     varslist($+1)=M2scivar(":", ":", Infer(list(1,Unknown),Type(Unknown,Unknown)))
92     varslist($+1)=M2scivar("$", "$", Infer(list(1,1),Type(Double,Real)))
93     varslist($+1)=M2scivar("varargout","%varargout",Infer(list(Unknown,Unknown),Type(Cell,Unknown)))
94     varslist($+1)=M2scivar("%shortcircuit","%shortcircuit",Infer(list(1,1),Type(Double,Real))) // Used for short circuiting operators
95
96     // Translated function output arguments
97     maclhs=size(mtlbtree.outputs)
98     for k=1:maclhs
99         if funptr(mtlbtree.outputs(k).name)<>0 then
100             varslist($+1)=M2scivar("%"+mtlbtree.outputs(k).name,mtlbtree.outputs(k).name,Infer(list(0,0),Type(Double,Real)))
101             mtlbtree.outputs(k).name="%"+mtlbtree.outputs(k).name
102         else
103             varslist($+1)=M2scivar(mtlbtree.outputs(k).name,mtlbtree.outputs(k).name,Infer(list(0,0),Type(Double,Real)))
104         end
105     end
106
107     // Translation
108     [scitree,crp]=mtlbtree2sci(mtlbtree,prettyprintoutput)
109
110     dcl=[]
111     // Add special code
112     // If nargin or nargout function is used
113     if isdefinedvar("%nargin") | isdefinedvar("%nargout") then
114         dcl=["";gettext("// Number of arguments in function call");"[%nargout,%nargin] = argn(0)"]
115     end
116
117     // Initial value of lhs arguments
118     // If they are not initialized by input value, they are initialized with []
119     ini=[]
120     for k=1:size(mtlbtree.outputs)
121         found=%F
122         for l=1:size(mtlbtree.inputs)
123             if mtlbtree.inputs(l).name==mtlbtree.outputs(k).name then
124                 found=%T
125             end
126         end
127         if ~found then
128             if mtlbtree.outputs(k).name<>"varargout" then
129                 ini=[ini;mtlbtree.outputs(k).name+"=[];"]
130             else
131                 ini=[ini;mtlbtree.outputs(k).name+"=list();"]
132             end
133         end
134     end
135
136     // Graphics init
137     //graph_ini=[gettext("// Graphics initialisation");"global %graphics";"%graphics.type=1";"%graphics.units=""pixels"""];
138     graph_ini=[]
139     if ini<>[] then
140         ini=["";gettext("// Output variables initialisation (not found in input variables)");ini]
141     end
142     //ini=[ini;" ";graph_ini]
143
144     // Info on macros variables
145     if verbose_mode<0 then
146         write(%io(2),gettext("TESTING M2SCI: creating varslist file..."))
147         n=size(varslist)
148         info=[]
149
150         for k=1:n
151             info=[info;"//"+varslist(k).sciname+infer2txt(varslist(k).infer)];
152         end
153         infofilename=res_path+nam+"_varslist.dia.ref";
154         if verbose_mode==-2 then
155             write(%io(2),info)
156         end
157         infofile=mopen(infofilename,"w");
158         mputl(info,infofile);
159         mclose(infofile);
160     end
161
162     // Add function header
163     if ~batch then
164         rhsexpr="("
165         for k=1:macrhs
166             rhsexpr=rhsexpr+varslist(k).sciname
167             if k<macrhs then
168                 rhsexpr=rhsexpr+","
169             end
170         end
171         rhsexpr=rhsexpr+")"
172         hdr="function ["
173         for k=1:size(mtlbtree.outputs)
174             hdr=hdr+mtlbtree.outputs(k).name
175             if k<>size(mtlbtree.outputs) then
176                 hdr=hdr+","
177             end
178         end
179         hdr=hdr+"] = "+nam+rhsexpr;
180         txt=[hdr;ini;dcl]
181     else
182         txt=[ini;dcl]
183     end
184
185     // Generate associated translation function
186     if batch then
187         trad=[
188         "function [tree] = sci_"+fnam+"(tree)"
189         msprintf(gettext("// Generated by M2SCI\n// Conversion function for Matlab %s\n// Input: tree = Matlab funcall tree\n// Output: tree = Scilab equivalent for tree"),fnam)
190         ""
191         "tree=Funcall(""exec"",1,Rhs_tlist(tree.name),tree.lhs)"
192         ]
193     else
194         trad=[
195         "function [tree] = sci_"+nam+"(tree)"
196         msprintf(gettext("// Copyright INRIA (Generated by M2SCI)\n// Conversion function for Matlab %s()\n// Input: tree = Matlab funcall tree\n// Output: tree = Scilab equivalent for tree"),nam)
197         ]
198
199         if maclhs==0 then // Function with no outputs
200             // Do nothing
201         elseif maclhs==1 then // Function with one output
202             [boolval,index]=isdefinedvar(M2scivar(mtlbtree.outputs(1).name,strsubst(mtlbtree.outputs(1).name,"%",""),Infer()))
203             if boolval then
204                 dims=sci2exp(varslist(index).dims)
205                 vtype=varslist(index).vtype
206                 prop=varslist(index).property
207             else
208                 dims="list(Unknown,Unknown)"
209                 vtype=Unknown
210                 prop=Unknown
211             end
212
213             select vtype
214             case Double  then vtype="Double"
215             case Boolean  then vtype="Boolean"
216             case String then vtype="String"
217             case Struct then vtype="Struct"
218             case Cell then vtype="Cell"
219             case Unknown then vtype="Unknown"
220             case Sparse then vtype="Sparse"
221             end
222
223             select prop
224             case -1 then prop="Unknown"
225             case  0 then prop="Real"
226             case  1 then prop="Complex"
227             end
228
229             typ="Type("+vtype+","+prop+")"
230
231             if mtlbtree.outputs($).name<>"varargout" then
232                 trad=[trad;"tree.lhs(1).dims="+dims;"tree.lhs(1).type="+typ]
233             else
234                 trad=[trad;
235                 "for k=1:lhs"
236                 "  tree.lhs(k).dims=list(Unknown,Unknown)"
237                 "  tree.lhs(k).vtype=Unknown"
238                 "  tree.lhs(k).property=Unknown"
239                 "end"
240                 ]
241             end
242         else  // Function with more than 1 output
243             dims=list();
244             vtype=[];
245             prop=[]
246             for k=1:maclhs
247                 [boolval,index]=isdefinedvar(M2scivar(mtlbtree.outputs(k).name,strsubst(mtlbtree.outputs(k).name,"%",""),Infer()))
248                 if boolval then
249                     dims(k)=varslist(index).dims
250                     vtype=[vtype;varslist(index).vtype]
251                     prop=[prop;varslist(index).property]
252                 else
253                     dims(k)=list(Unknown,Unknown)
254                     vtype=[vtype;Unknown]
255                     prop=[prop;Unknown]
256                 end
257             end
258
259             dimstemp=sci2exp(dims)
260             dims=["dims="+dimstemp(1);dimstemp(2:$)]
261             vtype="vtype="+sci2exp(vtype)
262             prop="prop="+sci2exp(prop)
263             trad=[trad;
264             gettext("//  dims(i,:) is the ith output argument dimensions vector")
265             dims
266             gettext("//  dims(i,:) is the ith output argument dimensions vector")
267             vtype
268             gettext("//  prop(i) is the ith output argument property")
269             prop]
270             if mtlbtree.outputs($).name<>"varargout" then
271                 trad=[trad;
272                 "for k=1:lhs"
273                 "  tree.lhs(k).dims=dims(k)"
274                 "  tree.lhs(k).vtype=vtype(k)"
275                 "  tree.lhs(k).property=prop(k)"
276                 "end"
277                 ]
278             else
279                 trad=[trad;
280                 "for k=1:min(size(dims),lhs)"
281                 "  tree.lhs(k).dims=dims(k)"
282                 "  tree.lhs(k).vtype=vtype(k)"
283                 "  tree.lhs(k).property=prop(k)"
284                 "end"
285                 gettext("// Inference for varargout")
286                 "for k=min(size(dims),lhs)+1:lhs"
287                 "  tree.lhs(k).dims=list(Unknown,Unknown)"
288                 "  tree.lhs(k).vtype=Unknown"
289                 "  tree.lhs(k).property=Unknown"
290                 "end"
291                 ]
292             end
293         end
294     end
295     trad=[trad;"endfunction"]
296     clearglobal varslist
297     clearglobal %graphics
298 endfunction
299
300 // ---------------------------------------------------------------------------
301
302 function txt = infer2txt(infer)
303     txt=[]
304     dims=[]
305     if typeof(infer)=="infer" then
306         for l=1:size(infer.dims)
307             dims=[dims,string(infer.dims(l))]
308         end
309     else
310         error(gettext("Not yet implemented."))
311     end
312     dims=strcat(dims," ")
313
314     tp=infer.type.vtype
315     if tp==1 then
316         tp="Double"
317     elseif tp==10 then
318         tp="String"
319     elseif or(tp==[4,6]) then
320         tp="Boolean"
321     elseif tp==16 then
322         tp="Struct"
323         for k = 1:size(infer.contents.index)
324             if typeof(infer.contents.index(k))<>"list" then
325                 txt=[txt;expression2code(list(infer.contents.index(k)))+infer2txt(infer.contents.data(k))]
326             else
327                 txt=[txt;expression2code(infer.contents.index(k))+infer2txt(infer.contents.data(k))]
328             end
329         end
330     elseif tp==17 then
331         tp="Cell"
332         for k = 1:size(infer.contents.index)
333             if typeof(infer.contents.index(k))<>"list" then
334                 txt=[txt;expression2code(list(infer.contents.index(k)))+infer2txt(infer.contents.data(k))]
335             else
336                 txt=[txt;expression2code(infer.contents.index(k))+infer2txt(infer.contents.data(k))]
337             end
338         end
339     elseif tp==9 then
340         tp="Handle"
341     else
342         tp="Unknown"
343     end
344     if infer.type.property==Real then
345         prop="Real"
346     elseif infer.type.property==Complex then
347         prop="Complex"
348     else
349         prop="Unknown"
350     end
351     txt=["|"+dims+"|"+tp+"|"+prop;txt]
352 endfunction