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