macro print fixed.
[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     // get macro name
102     wchar_t* wcsVarName = os_wcsdup(ostr.str().c_str());
103     ostr.str(L"");
104
105     ostr << L"[";
106
107     // output arguments [a,b,c] = ....
108     if (m_outputArgs->empty() == false)
109     {
110         std::list<symbol::Variable*>::iterator OutArg = m_outputArgs->begin();
111         std::list<symbol::Variable*>::iterator OutArgfter = OutArg;
112         OutArgfter++;
113
114         for (; OutArgfter != m_outputArgs->end(); OutArgfter++)
115         {
116             ostr << (*OutArg)->getSymbol().getName();
117             ostr << ",";
118             OutArg++;
119         }
120
121         ostr << (*OutArg)->getSymbol().getName();
122     }
123
124     ostr << L"]";
125
126     // function name
127     ostr << L"=" << wcsVarName << L"(";
128
129     // input arguments function(a,b,c)
130     if (m_inputArgs->empty() == false)
131     {
132         std::list<symbol::Variable*>::iterator inArg = m_inputArgs->begin();
133         std::list<symbol::Variable*>::iterator inRagAfter = inArg;
134         inRagAfter++;
135
136         for (; inRagAfter != m_inputArgs->end(); inRagAfter++)
137         {
138             ostr << (*inArg)->getSymbol().getName();
139             ostr << ",";
140             inArg++;
141         }
142
143         ostr << (*inArg)->getSymbol().getName();
144     }
145
146     ostr << L")" << std::endl;
147
148     FREE(wcsVarName);
149     return true;
150 }
151
152 Callable::ReturnValue Macro::call(typed_list &in, optional_list &opt, int _iRetCount, typed_list &out, ast::ConstVisitor* execFunc)
153 {
154     bool bVarargout = false;
155     ReturnValue RetVal = Callable::OK;
156     symbol::Context *pContext = symbol::Context::getInstance();
157
158     //open a new scope
159     pContext->scope_begin();
160     //store the line number where is stored this macro in file.
161     ConfigVariable::macroFirstLine_begin(getFirstLine());
162
163     //check excepted and input/output parameters numbers
164     // Scilab Macro can be called with less than prototyped arguments,
165     // but not more execpts with varargin
166
167     // varargin management
168     if (m_inputArgs->size() > 0 && m_inputArgs->back()->getSymbol().getName() == L"varargin")
169     {
170         int iVarPos = static_cast<int>(in.size());
171         if (iVarPos > static_cast<int>(m_inputArgs->size()) - 1)
172         {
173             iVarPos = static_cast<int>(m_inputArgs->size()) - 1;
174         }
175
176         //add all standard variable in function context but not varargin
177         std::list<symbol::Variable*>::iterator itName = m_inputArgs->begin();
178         typed_list::const_iterator itValue = in.begin();
179         while (iVarPos > 0)
180         {
181             pContext->put(*itName, *itValue);
182             iVarPos--;
183             ++itName;
184             ++itValue;
185         }
186
187         //create varargin only if previous variable are assigned
188         optional_list::const_iterator it = opt.begin();
189         if (in.size() >= m_inputArgs->size() - 1)
190         {
191             //create and fill varargin
192             List* pL = new List();
193             while (itValue != in.end())
194             {
195                 if (*itValue != NULL)
196                 {
197                     pL->append(*itValue);
198                 }
199                 else
200                 {
201                     pL->append(it->second);
202                     it++;
203                 }
204
205                 itValue++;
206             }
207             pContext->put(m_Varargin, pL);
208         }
209     }
210     else if (in.size() > m_inputArgs->size())
211     {
212         if (m_inputArgs->size() == 0)
213         {
214             Scierror(999, _("Wrong number of input arguments: This function has no input argument.\n"));
215         }
216         else
217         {
218             Scierror(999, _("Wrong number of input arguments."));
219         }
220
221         pContext->scope_end();
222         ConfigVariable::macroFirstLine_end();
223         return Callable::Error;
224     }
225     else
226     {
227         //add optional paramter in current scope
228         optional_list::const_iterator it;
229         for (it = opt.begin() ; it != opt.end() ; it++)
230         {
231             pContext->put(symbol::Symbol(it->first), it->second);
232         }
233
234         //assign value to variable in the new context
235         std::list<symbol::Variable*>::iterator i;
236         typed_list::const_iterator j;
237
238         for (i = m_inputArgs->begin(), j = in.begin(); j != in.end (); ++j, ++i)
239         {
240             if (*j)
241             {
242                 //prevent assignation of NULL value
243                 pContext->put(*i, *j);
244             }
245         }
246     }
247
248     // varargout management
249     //rules :
250     // varargout must be alone
251     // varargout is a list
252     // varargout can containt more items than caller need
253     // varargout must containt at leat caller needs
254     if (m_outputArgs->size() == 1 && m_outputArgs->back()->getSymbol().getName() == L"varargout")
255     {
256         bVarargout = true;
257         List* pL = new List();
258         pContext->put(m_Varargout, pL);
259     }
260
261     //common part with or without varargin/varargout
262
263     // Declare nargin & nargout in function context.
264     if (m_pDblArgIn->getRef() > 1)
265     {
266         m_pDblArgIn->DecreaseRef();
267         m_pDblArgIn = (Double*)m_pDblArgIn->clone();
268         m_pDblArgIn->IncreaseRef();
269     }
270     m_pDblArgIn->set(0, static_cast<double>(in.size()));
271
272     if (m_pDblArgOut->getRef() > 1)
273     {
274         m_pDblArgOut->DecreaseRef();
275         m_pDblArgOut = (Double*)m_pDblArgOut->clone();
276         m_pDblArgOut->IncreaseRef();
277     }
278     m_pDblArgOut->set(0, _iRetCount);
279
280     pContext->put(m_Nargin, m_pDblArgIn);
281     pContext->put(m_Nargout, m_pDblArgOut);
282
283     //save current prompt mode
284     int oldVal = ConfigVariable::getPromptMode();
285     try
286     {
287         //m_body->mute();
288         //MuteVisitor mute;
289         //m_body->accept(mute);
290
291         ConfigVariable::setPromptMode(-1);
292         m_body->setReturnable();
293         m_body->accept(*execFunc);
294         //restore previous prompt mode
295         ConfigVariable::setPromptMode(oldVal);
296         if (m_body->isReturn())
297         {
298             m_body->setReturnable();
299         }
300     }
301     catch (ast::ScilabMessage & sm)
302     {
303         cleanCall(pContext, oldVal);
304         throw sm;
305     }
306     catch (ast::InternalAbort & ia)
307     {
308         cleanCall(pContext, oldVal);
309         throw ia;
310     }
311     // Normally, seqexp throws only SM so no need to catch SErr
312
313     //varargout management
314     if (bVarargout)
315     {
316         InternalType* pOut = pContext->get(m_Varargout);
317         if (pOut == NULL)
318         {
319             cleanCall(pContext, oldVal);
320             Scierror(999, _("Invalid index.\n"));
321             return Callable::Error;
322         }
323
324         if (pOut->isList() == false || pOut->getAs<List>()->getSize() == 0)
325         {
326             cleanCall(pContext, oldVal);
327             Scierror(999, _("Invalid index.\n"));
328             return Callable::Error;
329         }
330
331         List* pVarOut = pOut->getAs<List>();
332         const int size = std::min(pVarOut->getSize(), _iRetCount);
333         for (int i = 0 ; i < size ; ++i)
334         {
335             InternalType* pIT = pVarOut->get(i);
336             if (pIT->isListUndefined())
337             {
338                 for (int j = 0; j < i; ++j)
339                 {
340                     out[j]->DecreaseRef();
341                     out[j]->killMe();
342                 }
343                 out.clear();
344                 cleanCall(pContext, oldVal);
345
346                 Scierror(999, _("List element number %d is Undefined.\n"), i + 1);
347                 return Callable::Error;
348             }
349
350             pIT->IncreaseRef();
351             out.push_back(pIT);
352         }
353     }
354     else
355     {
356         //normal output management
357         for (std::list<symbol::Variable*>::iterator i = m_outputArgs->begin(); i != m_outputArgs->end() && _iRetCount; ++i, --_iRetCount)
358         {
359             InternalType * pIT = pContext->get(*i);
360             if (pIT)
361             {
362                 out.push_back(pIT);
363                 pIT->IncreaseRef();
364             }
365             else
366             {
367                 const int size = (const int)out.size();
368                 for (int j = 0; j < size; ++j)
369                 {
370                     out[j]->DecreaseRef();
371                     out[j]->killMe();
372                 }
373                 out.clear();
374                 cleanCall(pContext, oldVal);
375
376                 char* pst = wide_string_to_UTF8((*i)->getSymbol().getName().c_str());
377                 Scierror(999, _("Undefined variable %s.\n"), pst);
378                 FREE(pst);
379                 return Callable::Error;
380             }
381         }
382     }
383
384     //close the current scope
385     cleanCall(pContext, oldVal);
386
387     for (typed_list::iterator i = out.begin(), end = out.end(); i != end; ++i)
388     {
389         (*i)->DecreaseRef();
390     }
391
392     return RetVal;
393 }
394
395 std::list<symbol::Variable*>* Macro::inputs_get()
396 {
397     return m_inputArgs;
398 }
399
400 std::list<symbol::Variable*>* Macro::outputs_get()
401 {
402     return m_outputArgs;
403 }
404
405 int Macro::getNbInputArgument(void)
406 {
407     return (int)m_inputArgs->size();
408 }
409
410 int Macro::getNbOutputArgument(void)
411 {
412     if (m_outputArgs->size() == 1 && m_outputArgs->back()->getSymbol().getName() == L"varargout")
413     {
414         return -1;
415     }
416
417     return (int)m_outputArgs->size();
418 }
419
420 bool Macro::operator==(const InternalType& it)
421 {
422     if (const_cast<InternalType &>(it).isMacro() == false)
423     {
424         return false;
425     }
426
427     std::list<symbol::Variable*>* pInput = NULL;
428     std::list<symbol::Variable*>* pOutput = NULL;
429     types::Macro* pRight = const_cast<InternalType &>(it).getAs<types::Macro>();
430
431     //check inputs
432     pInput = pRight->inputs_get();
433     if (pInput->size() != m_inputArgs->size())
434     {
435         return false;
436     }
437
438     std::list<symbol::Variable*>::iterator itOld = pInput->begin();
439     std::list<symbol::Variable*>::iterator itEndOld = pInput->end();
440     std::list<symbol::Variable*>::iterator itMacro = m_inputArgs->begin();
441
442     for (; itOld != itEndOld ; ++itOld, ++itMacro)
443     {
444         if ((*itOld)->getSymbol() != (*itMacro)->getSymbol())
445         {
446             return false;
447         }
448     }
449
450     //check outputs
451     pOutput = pRight->outputs_get();
452     if (pOutput->size() != m_outputArgs->size())
453     {
454         return false;
455     }
456
457     itOld = pOutput->begin();
458     itEndOld = pOutput->end();
459     itMacro = m_outputArgs->begin();
460
461     for (; itOld != itEndOld ; ++itOld, ++itMacro)
462     {
463         if ((*itOld)->getSymbol() != (*itMacro)->getSymbol())
464         {
465             return false;
466         }
467     }
468
469     ast::Exp* pExp = pRight->getBody();
470     ast::SerializeVisitor serialOld(pExp);
471     unsigned char* oldSerial = serialOld.serialize(false, false);
472     ast::SerializeVisitor serialMacro(m_body);
473     unsigned char* macroSerial = serialMacro.serialize(false, false);
474
475     //check buffer length
476     unsigned int oldSize = *((unsigned int*)oldSerial);
477     unsigned int macroSize = *((unsigned int*)macroSerial);
478     if (oldSize != macroSize)
479     {
480         free(oldSerial);
481         free(macroSerial);
482         return false;
483     }
484
485     bool ret = (memcmp(oldSerial, macroSerial, oldSize) == 0);
486
487     free(oldSerial);
488     free(macroSerial);
489
490     return ret;
491 }
492 }