fix blank : there have more than one resultat display
[scilab.git] / scilab / modules / ast / src / cpp / types / macro.cpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2009-2009 - DIGITEO - Bruno JOFRET
4 *
5 *  This file must be used under the terms of the CeCILL.
6 *  This source file is licensed as described in the file COPYING, which
7 *  you should have received as part of this distribution.  The terms
8 *  are also available at
9 *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10 *
11 */
12
13 #include <sstream>
14 #include <cstdio>
15
16 #include "macro.hxx"
17 #include "list.hxx"
18 #include "context.hxx"
19 #include "symbol.hxx"
20 #include "scilabWrite.hxx"
21 #include "scilabexception.hxx"
22 #include "configvariable.hxx"
23 #include "mutevisitor.hxx"
24 #include "serializervisitor.hxx"
25
26 extern "C"
27 {
28 #include "localization.h"
29 #include "Scierror.h"
30 #include "sciprint.h"
31 #include "sci_malloc.h"
32 #include "os_swprintf.h"
33 }
34
35 namespace types
36 {
37 Macro::Macro(const std::wstring& _stName, std::list<symbol::Variable*>& _inputArgs, std::list<symbol::Variable*>& _outputArgs, ast::SeqExp &_body, const std::wstring& _stModule):
38     Callable(),
39     m_inputArgs(&_inputArgs), m_outputArgs(&_outputArgs), m_body(&_body),
40     m_Nargin(symbol::Context::getInstance()->getOrCreate(symbol::Symbol(L"nargin"))),
41     m_Nargout(symbol::Context::getInstance()->getOrCreate(symbol::Symbol(L"nargout"))),
42     m_Varargin(symbol::Context::getInstance()->getOrCreate(symbol::Symbol(L"varargin"))),
43     m_Varargout(symbol::Context::getInstance()->getOrCreate(symbol::Symbol(L"varargout")))
44 {
45     setName(_stName);
46     setModule(_stModule);
47     bAutoAlloc = false;
48     m_pDblArgIn = new Double(1);
49     m_pDblArgIn->IncreaseRef(); //never delete
50     m_pDblArgOut = new Double(1);
51     m_pDblArgOut->IncreaseRef(); //never delete
52
53 }
54
55 Macro::~Macro()
56 {
57     delete m_body;
58     m_pDblArgIn->DecreaseRef();
59     m_pDblArgIn->killMe();
60     m_pDblArgOut->DecreaseRef();
61     m_pDblArgOut->killMe();
62
63     if (m_inputArgs)
64     {
65         delete m_inputArgs;
66     }
67
68     if (m_outputArgs)
69     {
70         delete m_outputArgs;
71     }
72 }
73
74 void Macro::cleanCall(symbol::Context * pContext, int oldPromptMode)
75 {
76     //restore previous prompt mode
77     ConfigVariable::setPromptMode(oldPromptMode);
78     //close the current scope
79     pContext->scope_end();
80     ConfigVariable::macroFirstLine_end();
81 }
82
83 InternalType* Macro::clone()
84 {
85     IncreaseRef();
86     return this;
87 }
88
89 void Macro::whoAmI()
90 {
91     std::cout << "types::Macro";
92 }
93
94 ast::SeqExp* Macro::getBody(void)
95 {
96     return m_body;
97 }
98
99 bool Macro::toString(std::wostringstream& ostr)
100 {
101     ostr << L"[";
102
103     // output arguments [a,b,c] = ....
104     if (m_outputArgs->empty() == false)
105     {
106         std::list<symbol::Variable*>::iterator OutArg = m_outputArgs->begin();
107         std::list<symbol::Variable*>::iterator OutArgfter = OutArg;
108         OutArgfter++;
109
110         for (; OutArgfter != m_outputArgs->end(); OutArgfter++)
111         {
112             ostr << (*OutArg)->getSymbol().getName();
113             ostr << ",";
114             OutArg++;
115         }
116
117         ostr << (*OutArg)->getSymbol().getName();
118     }
119
120     ostr << L"]";
121
122     // function name
123     ostr << L"=" << getName() << L"(";
124
125     // input arguments function(a,b,c)
126     if (m_inputArgs->empty() == false)
127     {
128         std::list<symbol::Variable*>::iterator inArg = m_inputArgs->begin();
129         std::list<symbol::Variable*>::iterator inRagAfter = inArg;
130         inRagAfter++;
131
132         for (; inRagAfter != m_inputArgs->end(); inRagAfter++)
133         {
134             ostr << (*inArg)->getSymbol().getName();
135             ostr << ",";
136             inArg++;
137         }
138
139         ostr << (*inArg)->getSymbol().getName();
140     }
141
142     ostr << L")" << std::endl;
143
144     scilabWriteW(ostr.str().c_str());
145     // reset ostr after scilabWriteW call
146     ostr.str(L"");
147
148     return true;
149 }
150
151 Callable::ReturnValue Macro::call(typed_list &in, optional_list &opt, int _iRetCount, typed_list &out, ast::ConstVisitor* execFunc)
152 {
153     bool bVarargout = false;
154     ReturnValue RetVal = Callable::OK;
155     symbol::Context *pContext = symbol::Context::getInstance();
156
157     //open a new scope
158     pContext->scope_begin();
159     //store the line number where is stored this macro in file.
160     ConfigVariable::macroFirstLine_begin(getFirstLine());
161
162     //check excepted and input/output parameters numbers
163     // Scilab Macro can be called with less than prototyped arguments,
164     // but not more execpts with varargin
165
166     // varargin management
167     if (m_inputArgs->size() > 0 && m_inputArgs->back()->getSymbol().getName() == L"varargin")
168     {
169         int iVarPos = static_cast<int>(in.size());
170         if (iVarPos > static_cast<int>(m_inputArgs->size()) - 1)
171         {
172             iVarPos = static_cast<int>(m_inputArgs->size()) - 1;
173         }
174
175         //add all standard variable in function context but not varargin
176         std::list<symbol::Variable*>::iterator itName = m_inputArgs->begin();
177         typed_list::const_iterator itValue = in.begin();
178         while (iVarPos > 0)
179         {
180             pContext->put(*itName, *itValue);
181             iVarPos--;
182             ++itName;
183             ++itValue;
184         }
185
186         //create varargin only if previous variable are assigned
187         optional_list::const_iterator it = opt.begin();
188         if (in.size() >= m_inputArgs->size() - 1)
189         {
190             //create and fill varargin
191             List* pL = new List();
192             while (itValue != in.end())
193             {
194                 if (*itValue != NULL)
195                 {
196                     pL->append(*itValue);
197                 }
198                 else
199                 {
200                     pL->append(it->second);
201                     it++;
202                 }
203
204                 itValue++;
205             }
206             pContext->put(m_Varargin, pL);
207         }
208     }
209     else if (in.size() > m_inputArgs->size())
210     {
211         if (m_inputArgs->size() == 0)
212         {
213             Scierror(999, _("Wrong number of input arguments: This function has no input argument.\n"));
214         }
215         else
216         {
217             Scierror(999, _("Wrong number of input arguments."));
218         }
219
220         pContext->scope_end();
221         ConfigVariable::macroFirstLine_end();
222         return Callable::Error;
223     }
224     else
225     {
226         //add optional paramter in current scope
227         optional_list::const_iterator it;
228         for (it = opt.begin() ; it != opt.end() ; it++)
229         {
230             pContext->put(symbol::Symbol(it->first), it->second);
231         }
232
233         //assign value to variable in the new context
234         std::list<symbol::Variable*>::iterator i;
235         typed_list::const_iterator j;
236
237         for (i = m_inputArgs->begin(), j = in.begin(); j != in.end (); ++j, ++i)
238         {
239             if (*j)
240             {
241                 //prevent assignation of NULL value
242                 pContext->put(*i, *j);
243             }
244         }
245     }
246
247     // varargout management
248     //rules :
249     // varargout must be alone
250     // varargout is a list
251     // varargout can containt more items than caller need
252     // varargout must containt at leat caller needs
253     if (m_outputArgs->size() == 1 && m_outputArgs->back()->getSymbol().getName() == L"varargout")
254     {
255         bVarargout = true;
256         List* pL = new List();
257         pContext->put(m_Varargout, pL);
258     }
259
260     //common part with or without varargin/varargout
261
262     // Declare nargin & nargout in function context.
263     if (m_pDblArgIn->getRef() > 1)
264     {
265         m_pDblArgIn->DecreaseRef();
266         m_pDblArgIn = (Double*)m_pDblArgIn->clone();
267         m_pDblArgIn->IncreaseRef();
268     }
269     m_pDblArgIn->set(0, static_cast<double>(in.size()));
270
271     if (m_pDblArgOut->getRef() > 1)
272     {
273         m_pDblArgOut->DecreaseRef();
274         m_pDblArgOut = (Double*)m_pDblArgOut->clone();
275         m_pDblArgOut->IncreaseRef();
276     }
277     m_pDblArgOut->set(0, _iRetCount);
278
279     pContext->put(m_Nargin, m_pDblArgIn);
280     pContext->put(m_Nargout, m_pDblArgOut);
281
282     //save current prompt mode
283     int oldVal = ConfigVariable::getPromptMode();
284     try
285     {
286         //m_body->mute();
287         //MuteVisitor mute;
288         //m_body->accept(mute);
289
290         ConfigVariable::setPromptMode(-1);
291         m_body->setReturnable();
292         m_body->accept(*execFunc);
293         //restore previous prompt mode
294         ConfigVariable::setPromptMode(oldVal);
295         if (m_body->isReturn())
296         {
297             m_body->setReturnable();
298         }
299     }
300     catch (ast::ScilabMessage & sm)
301     {
302         cleanCall(pContext, oldVal);
303         throw sm;
304     }
305     catch (ast::InternalAbort & ia)
306     {
307         cleanCall(pContext, oldVal);
308         throw ia;
309     }
310     // Normally, seqexp throws only SM so no need to catch SErr
311
312     //varargout management
313     if (bVarargout)
314     {
315         InternalType* pOut = pContext->get(m_Varargout);
316         if (pOut == NULL)
317         {
318             cleanCall(pContext, oldVal);
319             Scierror(999, _("Invalid index.\n"));
320             return Callable::Error;
321         }
322
323         if (pOut->isList() == false || pOut->getAs<List>()->getSize() == 0)
324         {
325             cleanCall(pContext, oldVal);
326             Scierror(999, _("Invalid index.\n"));
327             return Callable::Error;
328         }
329
330         List* pVarOut = pOut->getAs<List>();
331         const int size = std::max(pVarOut->getSize(), _iRetCount);
332         for (int i = 0 ; i < size ; ++i)
333         {
334             InternalType* pIT = pVarOut->get(i);
335             if (pIT->isListUndefined())
336             {
337                 for (int j = 0; j < i; ++j)
338                 {
339                     out[j]->DecreaseRef();
340                     out[j]->killMe();
341                 }
342                 out.clear();
343                 cleanCall(pContext, oldVal);
344
345                 Scierror(999, _("List element number %d is Undefined.\n"), i + 1);
346                 return Callable::Error;
347             }
348
349             out.push_back(pIT->clone());
350         }
351     }
352     else
353     {
354         //normal output management
355         for (std::list<symbol::Variable*>::iterator i = m_outputArgs->begin(); i != m_outputArgs->end() && _iRetCount; ++i, --_iRetCount)
356         {
357             InternalType * pIT = pContext->get(*i);
358             if (pIT)
359             {
360                 out.push_back(pIT);
361                 pIT->IncreaseRef();
362             }
363             else
364             {
365                 const int size = (const int)out.size();
366                 for (int j = 0; j < size; ++j)
367                 {
368                     out[j]->DecreaseRef();
369                     out[j]->killMe();
370                 }
371                 out.clear();
372                 cleanCall(pContext, oldVal);
373
374                 char* pst = wide_string_to_UTF8((*i)->getSymbol().getName().c_str());
375                 Scierror(999, _("Undefined variable %s.\n"), pst);
376                 FREE(pst);
377                 return Callable::Error;
378             }
379         }
380     }
381
382     //close the current scope
383     cleanCall(pContext, oldVal);
384
385     for (typed_list::iterator i = out.begin(), end = out.end(); i != end; ++i)
386     {
387         (*i)->DecreaseRef();
388     }
389
390     return RetVal;
391 }
392
393 std::list<symbol::Variable*>* Macro::inputs_get()
394 {
395     return m_inputArgs;
396 }
397
398 std::list<symbol::Variable*>* Macro::outputs_get()
399 {
400     return m_outputArgs;
401 }
402
403 int Macro::getNbInputArgument(void)
404 {
405     return (int)m_inputArgs->size();
406 }
407
408 int Macro::getNbOutputArgument(void)
409 {
410     if (m_outputArgs->size() == 1 && m_outputArgs->back()->getSymbol().getName() == L"varargout")
411     {
412         return -1;
413     }
414
415     return (int)m_outputArgs->size();
416 }
417
418 bool Macro::operator==(const InternalType& it)
419 {
420     if (const_cast<InternalType &>(it).isMacro() == false)
421     {
422         return false;
423     }
424
425     std::list<symbol::Variable*>* pInput = NULL;
426     std::list<symbol::Variable*>* pOutput = NULL;
427     types::Macro* pRight = const_cast<InternalType &>(it).getAs<types::Macro>();
428
429     //check inputs
430     pInput = pRight->inputs_get();
431     if (pInput->size() != m_inputArgs->size())
432     {
433         return false;
434     }
435
436     std::list<symbol::Variable*>::iterator itOld = pInput->begin();
437     std::list<symbol::Variable*>::iterator itEndOld = pInput->end();
438     std::list<symbol::Variable*>::iterator itMacro = m_inputArgs->begin();
439
440     for (; itOld != itEndOld ; ++itOld, ++itMacro)
441     {
442         if ((*itOld)->getSymbol() != (*itMacro)->getSymbol())
443         {
444             return false;
445         }
446     }
447
448     //check outputs
449     pOutput = pRight->outputs_get();
450     if (pOutput->size() != m_outputArgs->size())
451     {
452         return false;
453     }
454
455     itOld = pOutput->begin();
456     itEndOld = pOutput->end();
457     itMacro = m_outputArgs->begin();
458
459     for (; itOld != itEndOld ; ++itOld, ++itMacro)
460     {
461         if ((*itOld)->getSymbol() != (*itMacro)->getSymbol())
462         {
463             return false;
464         }
465     }
466
467     ast::Exp* pExp = pRight->getBody();
468     ast::SerializeVisitor serialOld(pExp);
469     unsigned char* oldSerial = serialOld.serialize(false, false);
470     ast::SerializeVisitor serialMacro(m_body);
471     unsigned char* macroSerial = serialMacro.serialize(false, false);
472
473     //check buffer length
474     unsigned int oldSize = *((unsigned int*)oldSerial);
475     unsigned int macroSize = *((unsigned int*)macroSerial);
476     if (oldSize != macroSize)
477     {
478         free(oldSerial);
479         free(macroSerial);
480         return false;
481     }
482
483     bool ret = (memcmp(oldSerial, macroSerial, oldSize) == 0);
484
485     free(oldSerial);
486     free(macroSerial);
487
488     return ret;
489 }
490 }