* Bugs 16567 16586 fixed: mfile2sci() supports block %{..%}. Appended comments improved"
[scilab.git] / scilab / modules / m2sci / macros / mfile2sci.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) 2002-2004 - INRIA - Vincent COUVERT
3 // Copyright (C) ???? - INRIA - Serge STEER
4 // Copyright (C) 2012 - 2016 - Scilab Enterprises
5 // Copyright (C) 2018 - Samuel GOUGEON
6 //
7 // This file is hereby licensed under the terms of the GNU GPL v2.0,
8 // pursuant to article 5.3.4 of the CeCILL v.2.1.
9 // This file was originally licensed under the terms of the CeCILL v2.1,
10 // and continues to be available under such terms.
11 // For more information, see the COPYING file which you should have received
12 // along with this program.
13
14 function res = mfile2sci(fil, results_path, Recmode, only_double, verbose_mode, prettyprintoutput)
15     // This function performs translation of a single M-file
16     // - fil: file name
17     // - results_path: path to write translated file in (default value is fil path)
18     // - Recmode: recursive mode (default value is false)
19
20     // Get default arguments
21     [lhs,rhs]=argn(0)
22     if ~isdef("prettyprintoutput","l"), prettyprintoutput = %F, end
23     if ~isdef("verbose_mode","l"),      verbose_mode = 3,       end
24     if ~isdef("only_double","l"),       only_double = %F,       end
25     if ~isdef("Recmode","l"),           Recmode = %F,           end
26     if ~isdef("results_path","l"),      results_path = ".",     end
27     if rhs<1 then
28         m2sci_gui();
29         res = [];
30         return
31     end
32     fil = strsubst(fil,filesep(),"/")
33     results_path = getshortpathname(pathconvert(results_path));
34     results_path = strsubst(results_path,"\","/")
35     res_path = results_path  // res_path: environment variable in some called functions
36
37     // Loads libraries related to m2sci
38     if exists("m2scikernellib")==0 then load("SCI/modules/m2sci/macros/kernel/lib"),end
39     if exists("m2scipercentlib")==0 then load("SCI/modules/m2sci/macros/percent/lib"),end
40     if exists("m2scisci_fileslib")==0 then load("SCI/modules/m2sci/macros/sci_files/lib"),end
41
42     if multi_fun_file(fil,results_path,Recmode,only_double,verbose_mode,prettyprintoutput) then
43         res=1
44         return
45     end
46
47     // Get context
48     global("m2sci_infos")
49     global("mtlbref_fun")
50     global("mtlbtool_fun")
51     global("not_mtlb_fun")
52     [l,mac]=where()
53     Reclevel=size(find(mac=="mfile2sci"),"*")
54     tpcallpos=min(find(mac=="translatepaths"));
55     guicallpos=min(find(mac=="m2sci_gui"));
56     if size(find(mac=="m2sci_gui"),"*")==1 & tpcallpos<guicallpos then // Bug 679
57         Reclevel=Reclevel-1
58     end
59     if size(find(mac=="multi_fun_file"),"*")==1 then
60         Reclevel=Reclevel-1
61     end
62
63     if Reclevel==1 then
64         nametbl=[]
65     else
66         m2sci_infos_save=m2sci_infos
67     end
68     m2sci_infos=[%f %f]
69
70     margin=part(" ",ones(1,3*(Reclevel-1)))
71     margin="  "
72     rec=gettext("OFF");
73     dble=gettext("NO");
74     pretty=gettext("NO");
75     if prettyprintoutput then pretty=gettext("YES");end
76     if Recmode then rec=gettext("ON");end
77     if only_double then dble=gettext("YES");end
78
79     res=[]
80
81     // Handle file path
82     // File name
83     k=strindex(fil,".")
84     if k<>[]
85         ke=k($)-1
86         base_name=part(fil,1:ke)
87     else
88         ke=length(fil)
89         base_name=fil
90     end
91     // File path
92     k=strindex(fil,"/")
93     if k==[] then
94         file_path="./"
95     else
96         file_path=part(fil,1:k($))
97     end
98     // Others M-files in directory
99     if exists("Paths")==0 then
100         Paths=file_path,
101         if getos() == "Windows" then
102             Paths=strsubst(Paths,"/","\")
103             mfiles=listfiles(Paths+"*.m")
104             sep=filesep()
105         else
106             mfiles=listfiles(Paths+"*.m")
107             sep=filesep()
108         end
109     end
110
111     // Function name
112     if k~=[] then
113         fnam = part(base_name,k($)+1:ke) // File name without extension
114     else
115         fnam = base_name
116     end
117
118     // logfile initialisation
119     if exists("logfile")==0 then
120         File = getshortpathname(pathconvert(TMPDIR))+"logfile.dat"
121         [tempfd1,ierr1] = file("open",File,"old")
122         if ierr1==0 then
123             load(File)
124             file("close",tempfd1)
125             file("close",logfile)
126             mdelete(File)
127         end
128         logfile = file("open",results_path+"m2sci_"+fnam+".log","unknown")
129         save(File, "logfile")
130     end
131
132     // Output beginning message
133     mss=[gettext("****** Beginning of mfile2sci() session ******");
134     gettext("File to convert:")+" "+fil;
135     gettext("Result file path:")+" "+results_path;
136     gettext("Recursive mode:")+" "+rec;
137     gettext("Only double values used in M-file:")+" "+dble;
138     gettext("Verbose mode:")+" "+string(verbose_mode);
139     gettext("Generate formatted code:")+" "+pretty]
140     m2sci_info(mss,-1);
141
142     // Read in the file as text
143     m2sci_info(gettext("M-file reading..."),-1);
144     txt=mgetl(fil);
145     m2sci_info(gettext("M-file reading: Done"),-1);
146
147     //Replace TAB by SPACE
148     txt=strsubst(txt, ascii(9), "");
149
150     if txt==[] then
151         m2sci_infos(msprintf(gettext("File %s is an empty file.\n"),fil),-1);
152         return
153     end
154     tmptxt=txt
155
156     // Make minor changes on syntax
157     m2sci_info(gettext("Syntax modification..."),-1);
158     ierr=execstr("load(''"+pathconvert(TMPDIR)+fnam+ ".tree'',''txt'',''helppart'',''batch'')","errcatch","n")
159     if ierr<>0 | exists("txt")==0 | exists("batch")==0 & ..
160                  strindex(results_path,getshortpathname(TMPDIR))==[] then
161         [helppart,txt,batch]=m2sci_syntax(txt)
162     elseif ierr==0 & newest(fil,pathconvert(TMPDIR)+fnam+ ".tree")==1 then
163         [helppart,txt,batch]=m2sci_syntax(tmptxt)
164     end
165
166     m2sci_info(gettext("Syntax modification: Done"),-1);
167
168     // Write .cat file and update whatis
169     if helppart<>[] then
170         catfil = results_path + fnam+".cat"
171         whsfil = results_path + "whatis"
172         mputl(helppart,catfil);
173         if exists("whsfil_unit")==1 then
174             write(whsfil_unit,stripblanks(helppart(1))+" |"+fnam,"(a)")
175         end
176     end
177
178     if txt~=[] then
179         quote="''";
180         dquote="""";
181         kc=strindex(txt(1),"function");
182         kc=kc(1);
183
184         // Define Scilab function
185         fprot=funcprot();
186         funcprot(0);
187
188         // Blanks in file name are replaced by _ for batch
189         // kc+9 because 'function '
190         ksc=min(strindex(txt(1),";")) // searching for a comment on first line after function prototype
191         if isempty(ksc) then
192             ksc=length(txt(1))+1;
193             firstline=[]
194         else
195             firstline=part(txt(1),ksc+1:length(txt(1)));
196         end
197
198         // Extraction of the macro's name
199         func_proto=part(txt(1),kc+9:ksc-1)
200         keq=min(strindex(func_proto,"="))
201         kpar=min(strindex(func_proto,"("))
202         if isempty(keq) then
203             keq=1
204         end
205         if isempty(kpar) then
206             kpar=length(func_proto)+1
207         end
208
209         func_proto=part(func_proto,1:keq)+strsubst(stripblanks(part(func_proto,keq+1:kpar-1))," ","_")+part(func_proto,kpar:length(func_proto))
210
211         mname = getMacroNameFromPrototype(func_proto)
212         if mname=="" | mname==[]
213             msg = _("%s: ""%s"" does not exist or is not the macro name.\n");
214             error(msprintf(msg,"mfile2sci", mname))
215         end
216         w = mname;
217         nametbl=[nametbl;mname]
218         if fnam<>mname & ~batch then // warning is not displayed for a batch file
219             mss=msprintf(gettext("Warning: file %s defines function %s instead of %s\n         %s.sci, %s.cat and sci_%s.sci will be generated !"),fil,mname,fnam,mname,mname,mname);
220             m2sci_info(mss,-1);
221         end
222
223         txt($+1) = "endfunction"
224         // Compilation
225         txt = [part(txt(1),kc:ksc-1);firstline;txt(2:$)]
226         mputl(txt, TMPDIR+"/"+mname+".sci");
227         err = exec(TMPDIR+"/"+mname+".sci", "errcatch", -1);
228         if err~=0
229             // Maybe a final {end} closing {function} => try without it
230             txt($) = []   // removing "endfunction"
231             while size(txt,1)>0 & stripblanks(txt($))==""
232                 txt($) = []
233             end
234             if size(txt,1)>0 & stripblanks(txt($))=="end" then
235                 txt($) = []
236                 txt = [txt ; "endfunction"]
237                 mputl(txt, TMPDIR+"/"+mname+".sci");
238             end
239             exec(TMPDIR+"/"+mname+".sci", -1);
240         end
241         funcprot(fprot);
242         mdelete(TMPDIR+"/"+mname+".sci");
243
244         // Get Scilab pseudo code of the function
245         m2sci_info(gettext("Macro to tree conversion..."),-1);
246         macr=evstr(mname)
247         mtlbtree=macr2tree(macr);
248         if ~batch then
249             mtlbtree.name=mname;
250         else
251             mtlbtree.name="";
252         end
253
254         //Transfom a equal instructions(if lhs are multi_operation insert and expression is a funcall) in the matlab tree to sup_equal instructions
255         global("tmpvarnb")
256         tmpvarnb=0;
257         level=[0,0];
258         ninstr=1;
259         while ninstr<=size(mtlbtree.statements)-3
260             mtlbtree.statements(ninstr)=transformtree(mtlbtree.statements(ninstr))
261             ninstr=ninstr+1
262         end
263
264         // Perform the translation
265         [scitree,trad,hdr,crp]=m2sci(mtlbtree,w(1),Recmode,prettyprintoutput)
266
267         //Creation of fname_resume.log file
268         // if mtlbref_fun<>[]|not_mtlb_fun<>[]|mtlbtool_fun<>[] then
269         //resume_logfile initialisation
270         if exists("resume_logfile")==0 then
271             File = getshortpathname(pathconvert(TMPDIR))+gettext("resumelogfile.dat")
272             [tempfd2,ierr2] = file("open",File,"old")
273             if ierr2==0 then
274                 load(pathconvert(TMPDIR)+gettext("resumelogfile.dat"))
275                 file("close", tempfd2)
276                 file("close", resume_logfile)
277                 mdelete(pathconvert(TMPDIR)+gettext("resumelogfile.dat"))
278             end
279             resume_logfile = results_path+gettext("resume")+"_m2sci_"+fnam+".log"
280             resume_logfile = file("open", resume_logfile, "unknown")
281             save(pathconvert(TMPDIR)+gettext("resumelogfile.dat"), "resume_logfile")
282         end
283
284         //number of matlab reference functions, matlab toolboxes functions, not matlab functions
285         size1=size(mtlbref_fun,1)
286         size2=size(mtlbtool_fun,1)
287         size3=size(not_mtlb_fun,1)
288
289         if size(mtlbref_fun,"*")<>0 then
290             mtlbref_fun(:,1) = """"+mtlbref_fun(:,1)+"""";
291             mtlbref_fun12 = mtlbref_fun(:,1) + mtlbref_fun(:,2);
292         else
293             mtlbref_fun12 = [];
294         end
295         if size(mtlbtool_fun,"*")<>0 then
296             mtlbtool_fun(:,1) = """"+mtlbtool_fun(:,1)+"""";
297             mtlbtool_fun12 = mtlbtool_fun(:,1) + mtlbtool_fun(:,2);
298         else
299             mtlbtool_fun12 = [];
300         end
301         if size(not_mtlb_fun,"*")<>0 then
302             not_mtlb_fun(:,1) = """"+not_mtlb_fun(:,1)+"""";
303             not_mtlb_fun12 = not_mtlb_fun(:,1) + not_mtlb_fun(:,2);
304         else
305             not_mtlb_fun12 = [];
306         end
307
308         info_resume=[msprintf(gettext("****** %s: Functions of mfile2sci() session ******"),fnam);
309         "*";
310         msprintf(gettext("%d Matlab Function(s) not yet converted, original calling sequence used:"),size1);
311         mtlbref_fun12;
312         "*";
313         msprintf(gettext("%d Matlab Toolbox(es) Functions, original calling sequence used :"),size2);
314         mtlbtool_fun12;
315         "*";
316         msprintf(gettext("%d Unknown Function(s), original calling sequence used :"),size3);
317         not_mtlb_fun12;
318         "*"]
319
320         write(resume_logfile,margin+info_resume)
321         file("close",resume_logfile)
322         mdelete(pathconvert(TMPDIR)+gettext("resumelogfile.dat"))
323         //end
324
325         m2sci_info(gettext("Macro to tree conversion: Done"),-1);
326
327         crp(1)=""; // Delete function prototype
328         if isempty(firstline) then
329             res=[hdr;crp]
330         else
331             hdr(1)=hdr(1)+" "+crp(2);
332             crp(2)=[];
333             res=[hdr;crp];
334         end
335
336         // Strip last return and blank lines
337         n=size(res,1)
338         while res(n)==part(" ",1:length(res(n))) then
339             n=n-1
340         end
341         res=res(1:n)
342
343         // Write sci-file
344         ext = ".sci"
345         scifil = results_path + fnam + ext
346         mputl(res, scifil);
347
348         // Write sci_<mname>.sci translation file
349         if trad<>[] then
350             sci_fil = results_path + "sci_" + mname + ".sci"
351             mputl(trad,sci_fil);
352             res=1
353         else
354             res=0
355         end
356
357         // Output summary information
358         infos = []
359         if m2sci_infos(1) then
360             infos = gettext("Translation may be improved: see the //! comments and for all mtlb_<funname> function call\n  Type help mtlb_<funname> in Scilab command window to get information about improvements.");
361         end
362         if m2sci_infos(2) then
363             infos = [infos ; gettext("Translation may be wrong (see the //!! comments).")]
364         end
365
366         nametbl($)=[]
367
368     else
369         infos=gettext("File contains no instruction, no translation made...");
370     end
371
372     // End of translation messages
373     mss=gettext("****** End of mfile2sci() session ******");
374
375     m2sci_info([infos;mss],-1);
376
377     if Reclevel>1 then
378         m2sci_infos = m2sci_infos_save
379     end
380
381     file("close", logfile)
382     clearglobal m2sci_infos
383     clearglobal mtlbref_fun
384     clearglobal mtlbtool_fun
385     clearglobal not_mtlb_fun
386     // For execution called by translatepaths()
387     //nametbl=resume(nametbl)
388     mdelete(pathconvert(TMPDIR)+fnam+ ".tree")
389     mdelete(pathconvert(TMPDIR)+"logfile.dat")
390
391 endfunction
392
393 function funcname = getMacroNameFromPrototype(proto)
394     // Private utility function
395     // Extraction of the macro's name
396     tmp = tokens(proto,["(" "=" ")"]);
397     if size(tmp,1)>1
398         [?,?,?,funcname] = regexp(proto, "/(?:.*?=(.*?)\(|(.*?)\(|[^(]+?=\s*([^(]+))/","o");
399         funcname = stripblanks(funcname);
400         funcname(funcname=="") = [];
401     else
402         funcname = proto;
403     end
404     // proto = "[b,hy]=fun2(bar=3)";
405     // proto = "fun3 (bar=3)";
406     // proto = "a = fun4 ()";
407     // proto = "fun5";
408     // proto = "a = fun6"; // from bug_2341 use case
409 endfunction