1 /*---------------------------------------------------------------------\
3 | __ __ ____ _____ ____ |
4 | \ \ / /_ _/ ___|_ _|___ \ |
5 | \ V / _` \___ \ | | __) | |
6 | | | (_| |___) || | / __/ |
7 | |_|\__,_|____/ |_| |_____| |
10 | ruby language support (C) Novell Inc. |
11 \----------------------------------------------------------------------/
13 Author: Duncan Mac-Vicar <dmacvicar@suse.de>
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License
17 as published by the Free Software Foundation; either version
18 2 of the License, or (at your option) any later version.
22 #include "YRubyNamespace.h"
27 #define y2log_component "Y2Ruby"
28 #include <ycp/y2log.h>
30 #include <ycp/YCPElement.h>
32 #include <ycp/YCPVoid.h>
38 * using this instead of plain strcmp
39 * enables embedding argument names into the typeinfo
41 static bool firstWordIs (const char *where, const char *what)
43 size_t n = strlen (what);
44 return !strncmp (where, what, n) &&
45 (where[n] == '\0' || isspace (where[n]));
49 * The definition of a function that is implemented in Ruby
51 class Y2RubyFunctionCall : public Y2Function
55 //! function name, excluding module name
58 constFunctionTypePtr m_type;
59 //! data prepared for the inner call
63 Y2RubyFunctionCall (const string &module_name,
64 const string &local_name,
65 constFunctionTypePtr function_type
67 m_module_name (module_name),
68 m_local_name (local_name),
69 m_type (function_type)
71 // placeholder, formerly function name
72 m_call->add (YCPVoid ());
75 //! if true, the ruby function is passed the module name
76 virtual bool isMethod () = 0;
78 //! called by YEFunction::evaluate
79 virtual YCPValue evaluateCall ()
81 return YRuby::yRuby()->callInner ( m_module_name,
85 m_type->returnType() );
88 * Attaches a parameter to a given position to the call.
89 * @return false if there was a type mismatch
91 virtual bool attachParameter (const YCPValue& arg, const int position)
93 m_call->set (position+1, arg);
98 * What type is expected for the next appendParameter (val) ?
99 * (Used when calling from Ruby, to be able to convert from the
100 * simple type system of Ruby to the elaborate type system of YCP)
101 * @return Type::Any if number of parameters exceeded
103 virtual constTypePtr wantedParameterType () const
105 // -1 for the function name
106 int params_so_far = m_call->size ()-1;
107 return m_type->parameterType (params_so_far);
111 * Appends a parameter to the call.
112 * @return false if there was a type mismatch
114 virtual bool appendParameter (const YCPValue& arg)
116 y2internal("Adding parameter to function %s::%s of type %s", m_module_name.c_str(), m_local_name.c_str(), arg->valuetype_str());
122 * Signal that we're done adding parameters.
123 * @return false if there was a parameter missing
125 virtual bool finishParameters ()
131 virtual bool reset ()
134 // placeholder, formerly function name
135 m_call->add (YCPVoid ());
140 * Something for remote namespaces
142 virtual string name () const
148 class Y2RubySubCall : public Y2RubyFunctionCall
151 Y2RubySubCall (const string &module_name,
152 const string &local_name,
153 constFunctionTypePtr function_type
155 Y2RubyFunctionCall (module_name, local_name, function_type)
157 virtual bool isMethod ()
163 class Y2RubyMethodCall : public Y2RubyFunctionCall
166 Y2RubyMethodCall (const string &module_name,
167 const string &local_name,
168 constFunctionTypePtr function_type
170 Y2RubyFunctionCall (module_name, local_name, function_type)
172 virtual bool isMethod ()
180 YRubyNamespace::YRubyNamespace (string name)
184 y2milestone("Creating namespace for '%s'", name.c_str());
186 //y2milestone("loadModule 3.5");
187 //VALUE result = rb_eval_string((require_module).c_str());
189 VALUE module = rb_funcall( rb_mKernel, rb_intern("const_get"), 1, rb_str_new2(name.c_str()) );
192 y2error ("The Ruby module '%s' is not provided by its rb file", name.c_str());
195 y2milestone("The module '%s' was found", name.c_str());
197 // we will perform operator- to determine the module methods
198 VALUE moduleklassmethods = rb_funcall( rb_cModule, rb_intern("methods"), 0);
199 VALUE mymodulemethods = rb_funcall( module, rb_intern("methods"), 0);
200 VALUE methods = rb_funcall( mymodulemethods, rb_intern("-"), 1, moduleklassmethods );
204 y2error ("Can't see methods in module '%s'", name.c_str());
209 for(i = 0; i < RARRAY(methods)->len; i++)
211 VALUE current = RARRAY(methods)->ptr[i];
212 y2milestone("New method: '%s'", RSTRING(current)->ptr);
214 constTypePtr sym_tp = Type::Unspec;
215 //sym_tp = parseTypeinfo (*sym_ti)
216 if (sym_tp->isError ())
218 y2error ("Cannot parse $TYPEINFO{%s}", RSTRING(current)->ptr);
221 if (sym_tp->isUnspec ())
223 //sym_tp = new FunctionType (Type::Any, new FunctionType(Type::Any) );
226 Check_Type(module,T_MODULE);
227 VALUE methodobj = rb_funcall( module, rb_intern("method"), 1, current );
228 //VALUE methodobj = rb_funcall( module, rb_intern("send"), 2, rb_str_new2("method"), current );
229 if ( methodobj == Qnil )
231 y2error ("Cannot access method object '%s'", RSTRING(current)->ptr);
235 string signature = "any( ";
236 VALUE rbarity = rb_funcall( methodobj, rb_intern("arity"), 0);
238 int arity = NUM2INT(rbarity);
239 for ( int k=0; k < arity; ++k )
242 if ( k < (arity - 1) )
246 y2internal("going to parse signature: '%s'", signature.c_str());
247 sym_tp = Type::fromSignature(signature);
250 constFunctionTypePtr fun_tp = (constFunctionTypePtr) sym_tp;
252 // symbol entry for the function
253 SymbolEntry *fun_se = new SymbolEntry ( this,
254 i,// position. arbitrary numbering. must stay consistent when?
255 RSTRING(current)->ptr, // passed to Ustring, no need to strdup
256 SymbolEntry::c_function,
258 fun_se->setGlobal (true);
259 // enter it to the symbol table
260 enterSymbol (fun_se, 0);
261 y2milestone("method: '%s' added", RSTRING(current)->ptr);
262 y2milestone("%s", symbolsToString().c_str());
266 YRubyNamespace::~YRubyNamespace ()
269 const string YRubyNamespace::filename () const
272 return ".../" + m_name;
275 // this is for error reporting only?
276 string YRubyNamespace::toString () const
280 "/* this namespace is provided in Ruby */\n"
284 // called when running and the import statement is encountered
285 // does initialization of variables
286 // constructor is handled separately after this
287 YCPValue YRubyNamespace::evaluate (bool cse)
289 // so we don't need to do anything
290 y2debug ("Doing nothing");
294 // It seems that this is the standard implementation. why would we
295 // ever want it to be different?
296 Y2Function* YRubyNamespace::createFunctionCall (const string name, constFunctionTypePtr required_type)
298 y2debug ("Creating function call for %s", name.c_str ());
299 TableEntry *func_te = table ()->find (name.c_str (), SymbolEntry::c_function);
302 constTypePtr t = required_type ? required_type : (constFunctionTypePtr)func_te->sentry()->type ();
305 return new Y2RubyMethodCall (m_name, name, t);
309 return new Y2RubySubCall (m_name, name, t);
312 y2error ("No such function %s", name.c_str ());