[m2sci] kernel code reorganization: clarify dependencies & ease code browsing
[scilab.git] / scilab / modules / m2sci / macros / kernel / lst_funcall.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) ???? - INRIA - Scilab
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   funcallname = lst_funcall(fil, fnamvect)
14     //  Internal function called only by translatepaths()
15     //
16     //  Creates a list of vectors.
17     //  The first component of each vector is the name of a M-file (found in the Paths to translate),
18     //  followed by the called functions by this file
19     //  Output
20     //  -funcallname : a list of vectors
21     //  Input
22     //  -fil : vector which contains all M-files names (path+name) found in the Paths
23     //  -fnamvect : vector which contains all M-files names (just the name) found in the Paths
24
25     quote="''";
26     dquote="""";
27
28     k=strindex(fil,".")
29     ke=k($)-1
30     // Function name
31     ksep=strindex(fil,sep)
32     fnam=part(fil,ksep($)+1:ke) // File name without extension
33     txt=mgetl(fil);
34
35     kf=grep(txt,["function[","function "])
36
37     if isempty(kf) then
38         // Batch file
39         bval=%f
40     elseif size(kf,"*")==1 then
41         // Only one function defined
42         bval=%f
43     else
44         funcdecl=[]
45         for kk=kf
46             ind=strindex(txt(kk),["function[";"function "])
47             if (ind<isacomment(txt(kk)) | isacomment(txt(kk))==0) & ~isinstring(txt(kk),ind) & part(stripblanks(txt(kk),%T),1:8)=="function"  then // function prototype
48                 funcdecl=[funcdecl kk]
49             end
50         end
51         if isempty(funcdecl) then
52             // "function" only exists in comments and strings
53             bval=%f
54         elseif size(funcdecl,"*")==1 then
55             bval=%f
56         else
57             bval= %t
58         end
59     end
60
61     // file contains more than one function declaration
62     if bval then
63         // Verify if the directory exists
64         sep = filesep();
65         dirnam = ls(pathconvert(TMPDIR));
66         if or(fnam==dirnam) then
67             rmdir(pathconvert(TMPDIR)+fnam,"s")
68         end
69         mkdir(pathconvert(TMPDIR),fnam)
70
71         write(%io(2),msprintf(gettext(" -- File %s contains more than one function -- "),fil));
72         // First split file into as many files as function declared
73         funcdecl=[funcdecl size(txt,"*")+1]
74         tmpfiles=[]
75         for k=1:size(funcdecl,"*")-1
76             tmp = strindex(txt(funcdecl(k)),["function[","function "])
77             if k==1 then
78                 functxt=txt(funcdecl(k):funcdecl(k+1)-1)
79                 str =  strindex(txt(funcdecl(k)),"(")
80                 if str==[] then
81                     funcname=stripblanks(part(txt(funcdecl(k)),tmp+8:length(txt(funcdecl(k)))))
82                 else
83                     funcname=stripblanks(part(txt(funcdecl(k)),tmp+8:str(1)-1))
84                 end
85                 keq=strindex(funcname,"=")
86                 if ~isempty(keq) then
87                     funcname=stripblanks(part(funcname,keq+1:length(funcname)))
88                 end
89                 mputl(functxt,pathconvert(TMPDIR)+fnam+".m");
90             else
91                 functxt=txt(funcdecl(k):funcdecl(k+1)-1)
92                 str=strindex(txt(funcdecl(k)),"(")
93                 if str==[] then
94                     funcname=stripblanks(part(txt(funcdecl(k)),tmp+8:length(txt(funcdecl(k)))))
95                 else
96                     funcname=stripblanks(part(txt(funcdecl(k)),tmp+8:str(1)-1))
97                 end
98                 keq=strindex(funcname,"=")
99                 if ~isempty(keq) then
100                     funcname=stripblanks(part(funcname,keq+1:length(funcname)))
101                 end
102                 tmpfiles=[tmpfiles;funcname]
103                 mputl(functxt,pathconvert(TMPDIR)+pathconvert(fnam)+tmpfiles($)+".m");
104             end
105         end
106         write(%io(2),msprintf(gettext(" -- Each function converted separately: %s -- "),strcat(tmpfiles," ")));
107         write(%io(2),msprintf(gettext(" -- Temporary files put in: %s -- "),pathconvert(TMPDIR)));
108
109         // Conversion of each file
110         //for k=1:size(tmpfiles,"*")
111         //mfile2sci(pathconvert(TMPDIR)+pathconvert(fnam)+tmpfiles(k)+".m",pathconvert(TMPDIR)+pathconvert(fnam))
112         // Delete useless .m files
113         //mdelete(pathconvert(TMPDIR)+pathconvert(fnam)+tmpfiles(k)+".m")
114         //end
115
116         translatepaths(pathconvert(TMPDIR)+pathconvert(fnam),pathconvert(TMPDIR)+pathconvert(fnam))
117         // Catenation of all .sci files to have only one output file
118         txt=[]
119
120         for k=1:size(tmpfiles,"*")
121             txt=[txt ;" ";mgetl(pathconvert(TMPDIR)+pathconvert(fnam)+tmpfiles(k)+".sci")]
122             mdelete(pathconvert(TMPDIR)+pathconvert(fnam)+tmpfiles(k)+".sci")
123         end
124         mputl(txt,pathconvert(TMPDIR)+"tmp_"+fnam+".sci");
125         // End of catenation of all .sci files to have only one output file
126         txt=mgetl(pathconvert(TMPDIR)+pathconvert(fnam)+sep+"log")
127         mputl(txt,pathconvert(TMPDIR)+"tmp_m2sci_"+fnam+".log");
128         //
129         txt=mgetl(pathconvert(TMPDIR)+pathconvert(fnam)+sep+"resumelog")
130         mputl(txt,pathconvert(TMPDIR)+"tmp_resume_m2sci_"+fnam+".log");
131
132         // Catenation of all .log files to have only one output file
133         // txt=[]
134         // for k=1:size(tmpfiles,"*")
135         // txt=[txt ; mgetl(pathconvert(TMPDIR)+pathconvert(fnam)+"m2sci_"+tmpfiles(k)+".log")]
136         // Delete useless .log files
137         // mdelete(pathconvert(TMPDIR)+pathconvert(fnam)+"m2sci_"+tmpfiles(k)+".log")
138         //end
139         //mputl(txt,pathconvert(TMPDIR)+"tmp_m2sci_"+fnam+".log");
140         //End of catenation of all .log files to have only one output file
141
142         // Catenation of all resume.log files to have only one output file
143         //txt=[]
144         //for k=1:size(tmpfiles,"*")
145         //txt=[txt ; mgetl(pathconvert(TMPDIR)+pathconvert(fnam)+"resume_m2sci_"+tmpfiles(k)+".log")]
146         // Delete useless resume.log files
147         // mdelete(pathconvert(TMPDIR)+pathconvert(fnam)+"resume_m2sci_"+tmpfiles(k)+".log")
148         //end
149         //mputl(txt,pathconvert(TMPDIR)+"tmp_resume_m2sci_"+fnam+".log");
150         //End of catenation of all resume.log files to have only one output file
151
152         txt=mgetl(pathconvert(TMPDIR)+fnam+".m")
153     end
154
155     txt = strsubst(txt, ascii(9), "")
156     [helppart,txt,batch]=m2sci_syntax(txt)
157     // save txt vector, helpart and batch after the syntax modification
158     if strindex(fil,TMPDIR)==[] then
159         save(pathconvert(TMPDIR)+fnam+".tree", "txt", "helppart", "batch")
160     end
161
162     funcallname=[]
163     if txt~=[] then
164         kc=strindex(txt(1),"function");
165         kc=kc(1);
166
167         // Define Scilab function
168         fprot=funcprot();
169         funcprot(0);
170
171         // Blanks in file name are replaced by _ for batch
172         // kc+9 because 'function '
173
174         ksc=min(strindex(txt(1),";")) // searching for a comment on first line after function prototype
175
176         if isempty(ksc) then
177             ksc=length(txt(1))+1;
178             firstline=[]
179         else
180             firstline=part(txt(1),ksc+1:length(txt(1)));
181         end
182
183         func_proto=part(txt(1),kc+9:ksc-1)
184         keq=min(strindex(func_proto,"="))
185         kpar=min(strindex(func_proto,"("))
186
187         if isempty(keq) then
188             keq=0
189         end
190         if isempty(kpar) then
191             kpar=length(func_proto)+1
192         end
193
194         mname=strsubst(stripblanks(part(func_proto,keq+1:kpar-1))," ","_")
195         func_proto=part(func_proto,1:keq)+..
196         strsubst(stripblanks(part(func_proto,keq+1:kpar-1))," ","_")+..
197         part(func_proto,kpar:length(func_proto))
198
199         deff(func_proto,[firstline;txt(2:$)])
200         // w=who("get");
201         // mname=w(1);
202
203
204         funcprot(fprot)
205
206         // Get Scilab pseudo code of the function
207         macr=evstr(mname)
208
209         mtlbtree=macr2tree(macr);
210
211         if ~batch then
212             mtlbtree.name=mname;
213         else
214             mtlbtree.name="";
215         end
216
217         ninstr=1
218         // variablevect is a vector which contains all variables (excluded functions)
219         variablevect=[]
220         for i=1:size(mtlbtree.inputs)
221             variablevect=[variablevect;mtlbtree.inputs(i).name]
222         end
223
224         // search the declared variables in mtlbtree
225         while ninstr<=size(mtlbtree.statements)-3
226             [variablevect]=variablesearch(mtlbtree.statements(ninstr),variablevect)
227             ninstr=ninstr+1
228         end
229
230         ninstr=1
231         // search the called functions in the mtlbtree
232         // funcallname contains the name of the M-file, followed by the called functions
233
234         while ninstr<=size(mtlbtree.statements)-3
235             [funcallname,variablevect]=funcallsearch(mtlbtree.statements(ninstr),funcallname,fnamvect,variablevect)
236             ninstr=ninstr+1
237         end
238
239     end
240
241     // add the M-file name in funcallname vector (at the first index)
242     funcallname=[fnam;funcallname]
243
244 endfunction
245
246 // ---------------------------------------------------------------------------
247
248 function  variablename = variablesearch(instr,variablename)
249     //  PRIVATE INTERNAL function called only by lst_funcall() hereabove and itself (recursive)
250     //
251     //  Searches names of declared variables for each instruction of mtlbtree
252     //  Output
253     //  -variablename : a vector which contains the names of declared variables
254     //  -instr : mtlbtree instruction
255
256     // case : ifthenelse instruction
257     if typeof(instr) == "ifthenelse" then
258         for i=1:size(instr.then)
259             [variablename]=variablesearch((instr.then(i)),variablename)
260         end
261         for i=1:size(instr.elseifs)
262             for k=1:size(instr.elseifs(i).then)
263                 [variablename]=variablesearch((instr.elseifs(i).then(k)),variablename)
264             end
265         end
266         for i=1:size(instr.else)
267         [variablename]=variablesearch((instr.else(i)),variablename)
268         end
269         // case : selectcase instruction
270     elseif typeof(instr) == "selectcase" then
271         for i=1:size(instr.cases)
272             [variablename]=variablesearch(instr.cases(i).expression,variablename)
273             for j=1:size(instr.cases(i).then)
274                 [variablename]=variablesearch((instr.cases(i).then(j)),variablename)
275             end
276         end
277         for i=1:size(instr.else)
278         [variablename]=variablesearch(instr.else(i),variablename)
279         end
280         // case : while instruction
281     elseif typeof(instr) == "while" then
282         for i=1:size(instr.statements)
283             [variablename]=variablesearch(instr.statements(i),variablename)
284         end
285         // case : for instruction
286     elseif typeof(instr) == "for" then
287         [variablename]=variablesearch(instr.expression,variablename)
288         for i=1:size(instr.statements)
289             [variablename]=variablesearch(instr.statements(i),variablename)
290         end
291         // case : equal instruction
292     elseif typeof(instr) == "equal" then
293         for i=1:size(instr.lhs)
294             [variablename]=variablesearch(instr.lhs(i),variablename)
295         end
296         // case : operation instruction
297     elseif typeof(instr) == "operation" then
298         if instr.operator=="ins" then
299             if find(instr.operands(1).name==variablename)==[] then
300                 variablename($+1)=instr.operands(1).name
301             end
302         end
303         // case : variable instruction
304     elseif typeof(instr) == "variable" then
305         if find(instr.name==variablename)==[] & instr.name<>"ans" then
306             variablename($+1)=instr.name
307         end
308     end
309
310 endfunction
311
312 // ---------------------------------------------------------------------------
313
314 function   [funcallname,variablename] = funcallsearch(instr,funcallname,fnamvect,variablename)
315     //  PRIVATE INTERNAL function called only by lst_funcall() hereabove and itself (recursive)
316     //
317     //  Searches the functions names in each instruction of mtlbtree
318     //  Input-Output
319     //  -funcallname : a vector which contains the names of called functions if it exists a M-file having the same name in the Paths
320     //  -variablename : a vector which contains the names of declared variables
321     //  Input
322     //  -instr : mtlbtree instruction
323     //  -fnamvect : vector which contains all M-files names found in the Paths
324
325     // case : ifthenelse instruction
326     if typeof(instr) == "ifthenelse" then
327         [funcallname,variablename]=funcallsearch(instr.expression,funcallname,fnamvect,variablename)
328         for i=1:size(instr.then)
329             [funcallname,variablename]=funcallsearch((instr.then(i)),funcallname,fnamvect,variablename)
330         end
331         for i=1:size(instr.elseifs)
332             for k=1:size(instr.elseifs(i).then)
333                 [funcallname,variablename]=funcallsearch((instr.elseifs(i).then(k)),funcallname,fnamvect,variablename)
334             end
335         end
336         for i=1:size(instr.else)
337         [funcallname,variablename]=funcallsearch((instr.else(i)),funcallname,fnamvect,variablename)
338         end
339         // case : selectcase instruction
340     elseif typeof(instr) == "selectcase" then
341         [funcallname,variablename]=funcallsearch(instr.expression,funcallname,fnamvect,variablename)
342
343         for i=1:size(instr.cases)
344             [funcallname,variablename]=funcallsearch((instr.cases(i).expression),funcallname,fnamvect,variablename)
345             for j=1:size(instr.cases(i).then)
346                 [funcallname,variablename]=funcallsearch((instr.cases(i).then(j)),funcallname,fnamvect,variablename)
347             end
348         end
349         for i=1:size(instr.else)
350         [funcallname,variablename]=funcallsearch(instr.else(i),funcallname,fnamvect,variablename)
351         end
352         // case : while instruction
353     elseif typeof(instr) == "while" then
354         [funcallname,variablename]=funcallsearch(instr.expression,funcallname,fnamvect,variablename)
355         for i=1:size(instr.statements)
356             [funcallname,variablename]=funcallsearch(instr.statements(i),funcallname,fnamvect,variablename)
357         end
358         // case : for instruction
359     elseif typeof(instr) == "for" then
360         [funcallname,variablename]=funcallsearch(instr.expression,funcallname,fnamvect,variablename)
361         for i=1:size(instr.statements)
362             [funcallname,variablename]=funcallsearch(instr.statements(i),funcallname,fnamvect,variablename)
363         end
364         // case : cste instruction
365     elseif  typeof(instr)== "cste" then
366         return
367         // case : variable instruction
368     elseif typeof(instr)=="variable"
369         if find(instr.name==variablename)==[] & find(instr.name==stripblanks(part(fnamvect,1:24)))<>[] & find(instr.name==funcallname)==[] then
370             funcallname=[funcallname;fnamvect(find(instr.name==stripblanks(part(fnamvect,1:24))))]
371         else
372             return
373         end
374         // case : equal instruction
375     elseif typeof(instr) == "equal" then
376         [funcallname,variablename]=funcallsearch(instr.expression,funcallname,fnamvect,variablename)
377         // case : expression is a funcall
378     elseif typeof(instr) == "funcall" then
379         if find(funcallname==instr.name) == [] & find(instr.name==stripblanks(part(fnamvect,1:24)))<>[]  then
380             if size(find(instr.name==stripblanks(part(fnamvect,1:24))),2)==1 then
381                 funcallname=[funcallname;fnamvect(find(instr.name==stripblanks(part(fnamvect,1:24))))]
382             else
383                 findvect=find(instr.name==stripblanks(part(fnamvect,1:24)))
384                 funcallname=[funcallname;fnamvect(findvect(2))]
385                 st = " " + mtlbtree.name + ": " + fnamvect(findvect(1))
386                 for i=2:size(findvect,2)
387                     st = st+ " <-> " + fnamvect(findvect(i))
388                 end
389                 st = st + gettext(": The 24 first characters of the files names are equal: ");
390                 warning(st)
391             end
392         end
393         // case : expression is cste
394         if typeof(instr.rhs)== "constant" then
395             return
396         else
397             for ind=1:size(instr.rhs)
398                 [funcallname,variablename]=funcallsearch(instr.rhs(ind),funcallname,fnamvect,variablename)
399             end
400         end
401         // case : operation instruction
402     elseif typeof(instr) == "operation" then
403         for ind=1:size(instr.operands)
404             [funcallname,variablename]=funcallsearch(instr.operands(ind),funcallname,fnamvect,variablename)
405         end
406     end
407
408 endfunction