manage a=42 in parameter of macro
[scilab.git] / scilab / modules / types / src / cpp / 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 "localization.h"
21 #include "scilabWrite.hxx"
22 #include "scilabexception.hxx"
23 #include "configvariable.hxx"
24 #include "mutevisitor.hxx"
25
26 extern "C"
27 {
28 #include "Scierror.h"
29 #include "MALLOC.h"
30 #include "os_swprintf.h"
31 }
32
33 namespace types
34 {
35 Macro::Macro(const std::wstring& _stName, std::list<symbol::Symbol> &_inputArgs, std::list<symbol::Symbol> &_outputArgs, ast::SeqExp &_body, const wstring& _stModule):
36     Callable(), m_inputArgs(&_inputArgs), m_outputArgs(&_outputArgs), m_body(&_body),
37     m_ArgInSymb(symbol::Symbol(L"nargin")), m_ArgOutSymb(symbol::Symbol(L"nargout"))
38 {
39     setName(_stName);
40     setModule(_stModule);
41     bAutoAlloc = false;
42     m_pDblArgIn = new Double(1);
43     m_pDblArgIn->IncreaseRef(); //never delete
44     m_pDblArgOut = new Double(1);
45     m_pDblArgOut->IncreaseRef(); //never delete
46 }
47
48 Macro::~Macro()
49 {
50     delete m_body;
51 }
52
53 InternalType* Macro::clone()
54 {
55     IncreaseRef();
56     return this;
57 }
58
59 void Macro::whoAmI()
60 {
61     std::cout << "types::Macro";
62 }
63
64 InternalType::RealType Macro::getType(void)
65 {
66     return RealMacro;
67 }
68
69 ast::SeqExp* Macro::getBody(void)
70 {
71     return m_body;
72 }
73
74 bool Macro::toString(std::wostringstream& ostr)
75 {
76     ostr << L"FIXME : Implement Macro::toString" << std::endl;
77     return true;
78 }
79
80 Callable::ReturnValue Macro::call(typed_list &in, optional_list &opt, int _iRetCount, typed_list &out, ast::ConstVisitor* execFunc)
81 {
82     bool bVarargout = false;
83     ReturnValue RetVal = Callable::OK;
84     symbol::Context *pContext = symbol::Context::getInstance();
85
86     //open a new scope
87     pContext->scope_begin();
88
89     //add optional paramter in current scope
90     optional_list::const_iterator it;
91     for (it = opt.begin() ; it != opt.end() ; it++)
92     {
93         pContext->put(symbol::Symbol(it->first), *it->second);
94     }
95     //check excepted and input/output parameters numbers
96     // Scilab Macro can be called with less than prototyped arguments,
97     // but not more execpts with varargin
98
99     // varargin management
100     if (m_inputArgs->size() > 0 && m_inputArgs->back().name_get() == L"varargin")
101     {
102         int iVarPos = static_cast<int>(in.size());
103         if (iVarPos > static_cast<int>(m_inputArgs->size()) - 1)
104         {
105             iVarPos = static_cast<int>(m_inputArgs->size()) - 1;
106         }
107
108         //add all standard variable in function context but not varargin
109         std::list<symbol::Symbol>::const_iterator itName = m_inputArgs->begin();
110         typed_list::const_iterator itValue = in.begin();
111         while (iVarPos > 0)
112         {
113             pContext->put((*itName), **itValue);
114             iVarPos--;
115             itName++;
116             itValue++;
117         }
118
119         //create varargin only if previous variable are assigned
120         if (in.size() >= m_inputArgs->size() - 1)
121         {
122             //create and fill varargin
123             List* pL = new List();
124             while (itValue != in.end())
125             {
126                 pL->append(*itValue);
127                 itValue++;
128             }
129             pContext->put(symbol::Symbol(L"varargin"), *pL);
130         }
131     }
132     else if (in.size() > m_inputArgs->size())
133     {
134         wostringstream ostr;
135         ostr << _W("Wrong number of input arguments.") << std::endl << std::endl;
136         ostr << _W("Excepted: ") << m_inputArgs->size() << std::endl;
137
138         if (m_inputArgs->size() > 0)
139         {
140             ostr << _W("Arguments are:") << std::endl << std::endl;
141             ostr << " ";
142             for (std::list<symbol::Symbol>::iterator it =  m_inputArgs->begin() ; it != m_inputArgs->end() ; ++it)
143             {
144                 ostr << (*it).name_get() << L"    ";
145             }
146             ostr << std::endl;
147         }
148
149         char* pst = wide_string_to_UTF8(ostr.str().c_str());
150         Scierror(58, "%s", pst);
151         pContext->scope_end();
152         return Callable::Error;
153     }
154     else
155     {
156         //assign value to variable in the new context
157         std::list<symbol::Symbol>::const_iterator i;
158         typed_list::const_iterator j;
159
160         for (i = m_inputArgs->begin(), j = in.begin(); j != in.end (); ++j, ++i)
161         {
162             if (*j)
163             {
164                 //prevent assignation of NULL value
165                 pContext->put((*i), **j);
166             }
167         }
168     }
169
170     // varargout management
171     //rules :
172     // varargout must be alone
173     // varargout is a list
174     // varargout can containt more items than caller need
175     // varargout must containt at leat caller needs
176     if (m_outputArgs->size() == 1 && m_outputArgs->back().name_get() == L"varargout")
177     {
178         bVarargout = true;
179         List* pL = new List();
180         pContext->put(symbol::Symbol(L"varargout"), *pL);
181     }
182
183     //common part with or without varargin/varargout
184
185     // Declare nargin & nargout in function context.
186     m_pDblArgIn->set(0, static_cast<double>(in.size()));
187     m_pDblArgOut->set(0, _iRetCount);
188     pContext->put(m_ArgInSymb, *m_pDblArgIn);
189     pContext->put(m_ArgOutSymb, *m_pDblArgOut);
190
191     //save current prompt mode
192     int oldVal = ConfigVariable::getPromptMode();
193     try
194     {
195         //m_body->mute();
196         //MuteVisitor mute;
197         //m_body->accept(mute);
198
199         ConfigVariable::setPromptMode(-1);
200         m_body->returnable_set();
201         m_body->accept(*execFunc);
202         //restore previous prompt mode
203         ConfigVariable::setPromptMode(oldVal);
204         if (m_body->is_return())
205         {
206             m_body->returnable_set();
207         }
208
209         //varargout management
210         if (bVarargout)
211         {
212             InternalType* pOut = pContext->get(symbol::Symbol(L"varargout"));
213             if (pOut == NULL)
214             {
215                 Scierror(999, _("Invalid index.\n"));
216                 return Callable::Error;
217             }
218
219             if (pOut->isList() == false || pOut->getAs<List>()->getSize() == 0)
220             {
221                 Scierror(999, _("Invalid index.\n"));
222                 return Callable::Error;
223             }
224
225             List* pVarOut = pOut->getAs<List>();
226             for (int i = 0 ; i < Min(pVarOut->getSize(), _iRetCount) ; i++)
227             {
228                 InternalType* pIT = pVarOut->get(i)->clone();
229                 if (pIT->isListUndefined())
230                 {
231                     Scierror(999, _("List element number %d is Undefined.\n"), i + 1);
232                     return Callable::Error;
233                 }
234
235                 out.push_back(pIT);
236             }
237         }
238         else
239         {
240             //normal output management
241             std::list<symbol::Symbol>::const_iterator i;
242             for (i = m_outputArgs->begin(); i != m_outputArgs->end() && _iRetCount; ++i, --_iRetCount)
243             {
244                 InternalType *pIT = pContext->get((*i));
245                 if (pIT != NULL)
246                 {
247                     out.push_back(pIT);
248                     pIT->IncreaseRef();
249                 }
250                 else
251                 {
252                     char* pst = wide_string_to_UTF8((*i).name_get().c_str());
253                     Scierror(999, _("Undefined variable %s.\n"), pst);
254                     FREE(pst);
255                     return Callable::Error;
256                 }
257             }
258         }
259     }
260     catch (ast::ScilabMessage se)
261     {
262         //restore previous prompt mode
263         ConfigVariable::setPromptMode(oldVal);
264         //close the current scope
265         pContext->scope_end();
266         for (size_t j = 0; j < out.size(); ++j)
267         {
268             out[j]->DecreaseRef();
269         }
270         throw se;
271     }
272     catch (ast::InternalAbort sa)
273     {
274         //restore previous prompt mode
275         ConfigVariable::setPromptMode(oldVal);
276         //close the current scope
277         pContext->scope_end();
278         for (size_t j = 0; j < out.size(); ++j)
279         {
280             out[j]->DecreaseRef();
281         }
282         throw sa;
283     }
284
285     //close the current scope
286     pContext->scope_end();
287
288     for (size_t j = 0; j < out.size(); ++j)
289     {
290         out[j]->DecreaseRef();
291     }
292     return RetVal;
293 }
294
295 std::list<symbol::Symbol>* Macro::inputs_get()
296 {
297     return m_inputArgs;
298 }
299
300 std::list<symbol::Symbol>* Macro::outputs_get()
301 {
302     return m_outputArgs;
303 }
304 }