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