Refactoring of ScilabException in AST, exec, execstr.
[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 "yaspio.hxx"
22 #include "scilabexception.hxx"
23 #include "configvariable.hxx"
24 #include "mutevisitor.hxx"
25
26 extern "C"
27 {
28     #include "Scierror.h"
29     #include "os_swprintf.h"
30 }
31
32 namespace types
33 {
34     Macro::Macro(const std::wstring& _stName, std::list<symbol::Symbol> &_inputArgs, std::list<symbol::Symbol> &_outputArgs, ast::SeqExp &_body, const wstring& _stModule):
35     Callable(), m_inputArgs(&_inputArgs), m_outputArgs(&_outputArgs), m_body(&_body)
36     {
37         setName(_stName);
38         setModule(_stModule);
39         bAutoAlloc = false;
40     }
41
42     Macro::~Macro()
43     {
44         delete m_body;
45     }
46
47     InternalType* Macro::clone()
48     {
49         IncreaseRef();
50         return this;
51     }
52
53     void Macro::whoAmI()
54     {
55         std::cout << "types::Macro";
56     }
57
58     Macro* Macro::getAsMacro(void)
59     {
60         return this;
61     }
62
63     InternalType::RealType Macro::getType(void)
64     {
65         return RealMacro;
66     }
67
68     ast::SeqExp* Macro::getBody(void)
69     {
70         return m_body;
71     }
72
73     wstring Macro::toString(int _iPrecision, int _iLineLen)
74     {
75         wostringstream ostr;
76
77         //FIXME : Implement me.
78         ostr << L"FIXME : Implement Macro::toString" << std::endl;
79
80         return ostr.str();
81     }
82
83     Callable::ReturnValue Macro::call(typed_list &in, int _iRetCount, typed_list &out, ast::ConstVisitor* execFunc)
84     {
85         ReturnValue RetVal = Callable::OK;
86         symbol::Context *pContext = symbol::Context::getInstance();
87
88         //check excepted and input/output parameters numbers
89         // Scilab Macro can be called with less than prototyped arguments,
90         // but not more execpts with varargin
91         // TODO: Manage varargin here
92         if(m_inputArgs->size() > 0 && m_inputArgs->back().name_get() == L"varargin")
93         {
94             //open a new scope
95             pContext->scope_begin();
96
97             int iVarPos = static_cast<int>(in.size());
98             if(iVarPos > static_cast<int>(m_inputArgs->size()) - 1)
99             {
100                 iVarPos = static_cast<int>(m_inputArgs->size()) - 1;
101             }
102
103             //add all standard variable in function context but not varargin
104             std::list<symbol::Symbol>::const_iterator itName = m_inputArgs->begin();
105             typed_list::const_iterator itValue = in.begin();
106             while(iVarPos > 0)
107             {
108                 pContext->put((*itName), **itValue);
109                 iVarPos--;
110                 itName++;
111                 itValue++;
112             }
113
114             //create varargin only if previous variable are assigned
115             if(in.size() >= static_cast<int>(m_inputArgs->size()) - 1)
116             {
117                 //create and fill varargin
118                 List* pL = new List();
119                 while(itValue != in.end())
120                 {
121                     pL->append(*itValue);
122                     itValue++;
123                 }
124                 pContext->put(symbol::Symbol(L"varargin"), *pL);
125             }
126         }
127                 else if(in.size() > m_inputArgs->size())
128                 {
129             wostringstream ostr;
130             ostr << _W("Wrong number of input arguments:") << std::endl << std::endl;
131             ostr << _W("Excepted: ") << m_inputArgs->size() << std::endl;
132
133             if(m_inputArgs->size() > 0)
134             {
135                 ostr << _W("Arguments are:") << std::endl << std::endl;
136                 ostr << " ";
137                 for (std::list<symbol::Symbol>::iterator it =  m_inputArgs->begin() ; it != m_inputArgs->end() ; ++it)
138                 {
139                     ostr << (*it).name_get() << L"    ";
140                 }
141                 ostr << std::endl;
142             }
143             ScierrorW(58, ostr.str().c_str());
144                         return Callable::Error;
145                 }
146         else
147         {
148             //open a new scope
149             pContext->scope_begin();
150
151             //assign value to variable in the new context
152             std::list<symbol::Symbol>::const_iterator i;
153             typed_list::const_iterator j;
154
155             for (i = m_inputArgs->begin(), j = in.begin(); j != in.end (); ++j,++i)
156             {
157                 pContext->put((*i), **j);
158             }
159         }
160
161         //common part with or without varargin
162
163         // Declare nargin & nargout in function context.
164         pContext->put(symbol::Symbol(L"nargin"), *new Double(static_cast<double>(in.size())));
165         pContext->put(symbol::Symbol(L"nargout"), *new Double(static_cast<double>(_iRetCount)));
166
167         try
168         {
169
170             m_body->mute();
171             MuteVisitor mute;
172             m_body->accept(mute);
173
174             m_body->returnable_set();
175             m_body->accept(*execFunc);
176             if(m_body->is_return())
177             {
178                 m_body->returnable_set();
179             }
180
181             std::list<symbol::Symbol>::const_iterator i;
182             for (i = m_outputArgs->begin(); i != m_outputArgs->end() && _iRetCount; ++i, --_iRetCount)
183             {
184                 InternalType *pIT = pContext->get((*i));
185                 if(pIT != NULL)
186                 {
187                     out.push_back(pIT);
188                     pIT->IncreaseRef();
189                 }
190                 else
191                 {
192                     wchar_t sz[bsiz];
193                     os_swprintf(sz, bsiz, _W("Undefined variable %ls.\n"), (*i).name_get().c_str());
194                     YaspWriteW(sz);
195                 }
196             }
197         }
198         catch(ast::ScilabMessage se)
199         {
200             //close the current scope
201             pContext->scope_end();
202             for (int j = 0; j < out.size(); ++j)
203             {
204                 out[j]->DecreaseRef();
205             }
206             throw se;
207         }
208
209         //close the current scope
210         pContext->scope_end();
211
212         for (int j = 0; j < out.size(); ++j)
213         {
214             out[j]->DecreaseRef();
215         }
216         return RetVal;
217     }
218
219     std::list<symbol::Symbol>* Macro::inputs_get()
220     {
221         return m_inputArgs;
222     }
223
224     std::list<symbol::Symbol>* Macro::outputs_get()
225     {
226         return m_outputArgs;
227     }
228 }