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 <y2/Y2Namespace.h>
23 // #include <y2/Y2Component.h>
24 #include <y2/Y2ComponentCreator.h>
26 #include <yui/YUIComponent.h>
27 #include <wfm/Y2WFMComponent.h>
29 #include <y2/Y2ComponentBroker.h>
30 #include <y2/Y2Namespace.h>
31 #include <y2/Y2Component.h>
32 #include <y2/Y2Function.h>
34 #include <ycp/pathsearch.h>
35 #include <ycp/y2log.h>
36 #include <ycp/YBlock.h>
37 #include <ycp/YExpression.h>
38 #include <ycp/YStatement.h>
39 #include <ycp/YCPValue.h>
40 #include <ycp/YCPBoolean.h>
41 #include <ycp/YCPList.h>
42 #include <ycp/YCPMap.h>
43 #include <ycp/YCPString.h>
44 #include <ycp/YCPInteger.h>
45 #include <ycp/YCPFloat.h>
46 #include <ycp/YCPElement.h>
47 #include <ycp/Import.h>
48 #include <ycp/y2log.h>
53 #include "RubyLogger.h"
54 #include "Y2RubyTypePath.h"
55 #include "Y2RubyTypeTerm.h"
56 #include "Y2RubyTypeConv.h"
59 static VALUE rb_mYaST;
61 static VALUE rb_cBroker;
63 // make the compiler happy when
64 // calling rb_define_method()
65 typedef VALUE (ruby_method)(...);
68 #define RB_FINALIZER(func) ((void (*)(...))func)
70 // this macro saves us from typing
71 // (ruby_method*) & method_name
72 // in rb_define_method
73 #define RB_METHOD(func) ((VALUE (*)(...))func)
75 Y2Component *owned_uic = 0;
76 Y2Component *owned_wfmc = 0;
80 getNs (const char * ns_name, const char * func_name)
82 Import import(ns_name); // has a static cache
83 Y2Namespace *ns = import.nameSpace();
86 y2error ("... for a Ruby call of %s", func_name);
97 y2milestone("init_wfm");
98 // if (Y2WFMComponent::instance () == 0)
100 y2milestone("WFM init");
101 owned_wfmc = Y2ComponentBroker::createClient ("wfm");
104 y2error ("Cannot create WFM component");
110 rb_init_ui( int argc, VALUE *argv, VALUE self )
112 const char *ui_name = "ncurses";
116 Check_Type(argv[0], T_STRING);
117 ui_name = RSTRING(argv[0])->ptr;
121 y2error ("Zero or one arguments required (ui name, default %s", ui_name);
125 Y2Component *c = YUIComponent::uiComponent ();
128 y2debug ("UI component not created yet, creating %s", ui_name);
130 c = Y2ComponentBroker::createServer (ui_name);
133 y2error ("Cannot create component %s", ui_name);
137 if (YUIComponent::uiComponent () == 0)
139 y2error ("Component %s is not a UI", ui_name);
144 // got it - initialize, remember
145 c->setServerOptions (0, NULL);
151 y2debug ("UI component already present: %s", c->name ().c_str ());
156 typedef struct brokerinfo
158 Y2Component *component;
163 // mark for garbage collection
164 // NOT USED, ONLY WHEN USING DATA_WRAP_STRUCT
166 yast_module_mark( BrokerInfo *info )
169 // dispose a namespace
170 // NOT USED, ONLY WHEN USING DATA_WRAP_STRUCT
172 yast_module_free( BrokerInfo *info )
174 //std::cout << "Deleting namespace." << std::endl;
179 yast_module_allocate( VALUE klass )
181 BrokerInfo *info = new BrokerInfo;
182 return Data_Wrap_Struct( klass, yast_module_mark, RB_FINALIZER(yast_module_free), info );
186 yast_module_initialize( VALUE self, VALUE param_ns_name )
188 Check_Type(param_ns_name, T_STRING);
189 rb_iv_set(self, "@namespace_name", param_ns_name);
196 yast_module_name( VALUE self )
198 return rb_iv_get(self, "@namespace_name");
202 yast_module_methods( VALUE self )
207 //forward declaration
208 YCPValue ycp_call_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv );
211 yast_module_proxy_method( int argc, VALUE *argv, VALUE self )
213 VALUE symbol = argv[0];
214 VALUE namespace_name = rb_iv_get(self, "@namespace_name");
216 // the func name (1st argument, is a symbol
217 // lets convert it to string
218 VALUE symbol_str = rb_funcall(symbol, rb_intern("to_s"), 0);
219 y2internal("Dynamic Proxy: [%s::%s] with [%d] params\n", RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr, argc);
221 //Check_Type(argv[0], T_STRING);
222 //y2internal(RSTRING (symbol)->ptr);
223 //Data_Get_Struct( self, class Y2Namespace, ns );
224 //ns = gNameSpaces[self];
226 // get the name of the module
227 //VALUE namespace_name = rb_funcall(self, rb_intern("name"), 0);
231 // this is a hack before the builtin namespaces get a uniform interface:
232 if (! strcmp (RSTRING (namespace_name)->ptr, "SCR"))
234 y2internal("Dynamic Proxy: [%s::%s] is a call to SCR\n", RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr);
236 res = ycp_call_builtin( RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr, argc, argv);
237 return ycpvalue_2_rbvalue(res);
242 c = Y2ComponentBroker::getNamespaceComponent(RSTRING (namespace_name)->ptr);
245 y2internal("No component can provide namespace %s\n", RSTRING (namespace_name)->ptr);
246 rb_raise( rb_eRuntimeError, "No component can provide namespace %s\n", RSTRING (namespace_name)->ptr);
249 y2internal("component name %s\n", c->name().c_str());
251 // import the namespace
252 //Y2Namespace *ns = c->import(RSTRING (namespace_name)->ptr);
253 Y2Namespace *ns = getNs( RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr);
256 rb_raise( rb_eRuntimeError, "Component cannot import namespace %s", RSTRING (namespace_name)->ptr );
261 y2internal("Namespace created from %s\n", ns->filename().c_str());
263 // ensure it is an initialized namespace
265 y2internal("Namespace %s initialized\n", RSTRING (namespace_name)->ptr);
267 TableEntry *sym_te = ns->table()->find (RSTRING(symbol_str)->ptr);
271 y2error ("No such symbol %s::%s", RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr);
272 rb_raise( rb_eNameError, "YCP symbol '%s' not found in namespace '%s'", RSTRING(symbol_str)->ptr, RSTRING (namespace_name)->ptr );
276 if (sym_te->sentry ()->isVariable () ||
277 sym_te->sentry ()->isReference ())
280 //ret_yv = YCP_getset_variable (aTHX_ ns_name, sym_te->sentry (), args);
284 Y2Function* call = ns->createFunctionCall (RSTRING(symbol_str)->ptr, 0 /*Type::fromSignature("list<string>()")*/);
288 y2internal ("Cannot create function call %s\n", RSTRING(symbol_str)->ptr);
292 // add the parameters
293 for (int i=1; i<argc; i++)
296 YCPValue v = rbvalue_2_ycpvalue(arg);
297 //y2internal ("Appending parameter %s\n", v->toString());
298 call->appendParameter (v);
300 call->finishParameters ();
302 YCPValue res = call->evaluateCall ();
304 y2internal ("Call succeded\n");
305 //y2internal ("Result: %i\n", res->asList()->size());
306 return ycpvalue_2_rbvalue(res);
311 YCPValue ycp_call_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv )
313 // access directly the statically declared builtins
314 extern StaticDeclaration static_declarations;
315 string qualified_name_s = module_name + "::" + func_name;
316 const char *qualified_name = qualified_name_s.c_str ();
318 y2milestone("Qualified name '%s'", qualified_name);
320 this does not work across namespaces
321 TableEntry *bi_te = static_declarations.symbolTable ()->find (qualified_name);
324 y2error ("No such builtin %s",qualified_name);
328 SymbolEntry *bi_se = bi_te->sentry ();
329 assert (bi_se != NULL);
330 assert (bi_se->isBuiltin ());
331 declaration_t bi_dt = bi_se->declaration ();
333 declaration_t *bi_dt = static_declarations.findDeclaration (qualified_name);
336 y2error ("No such builtin '%s'", qualified_name);
339 y2milestone("builtin '%s' found.", module_name.c_str());
340 // construct a builtin call using the proper overloaded builtin
341 YEBuiltin *bi_call = new YEBuiltin (bi_dt);
343 // attach the parameters:
345 // we would like to know the destination type so that we could
346 // convert eg a Ruby scalar to a YCP symbol, but because the
347 // builtins may be overloaded, let's say we want Any
349 // maybe a special exceptional hack to make Path for the 1st argument?
351 // go through the actual parameters
353 for (j = 1; j < argc; ++j)
355 y2milestone("builtin param '%d'", j-1);
356 // convert the value according to the expected type:
357 constTypePtr param_tp = (j == 0)? Type::Path : Type::Any;
358 y2milestone("builtin param '%d' 1", j-1);
360 // convert the first argument to a path
363 param_v = rbvalue_2_ycppath(argv[j]);
365 param_v = rbvalue_2_ycpvalue(argv[j] /*, param_tp */);
367 y2milestone("builtin param '%d' 2", j-1);
368 if (param_v.isNull ())
370 // an error has already been reported, now refine it.
371 // Can't know parameter name?
372 y2error ("... when passing parameter #%u to builtin %s",
376 // Such YConsts without a specific type produce invalid
377 // bytecode. (Which is OK here)
378 // The actual parameter's YCode becomes owned by the function call?
379 YConst *param_c = new YConst (YCode::ycConstant, param_v);
380 // for attaching the parameter, must get the real type so that it matches
381 constTypePtr act_param_tp = Type::vt2type (param_v->valuetype ());
382 // Attach the parameter
383 // Returns NULL if OK, Type::Error if excessive argument
384 // Other errors (bad code, bad type) shouldn't happen
385 constTypePtr err_tp = bi_call->attachParameter (param_c, act_param_tp);
388 if (err_tp->isError ())
390 // TODO really need to know the place in Ruby code
391 // where we were called from.
392 y2error ("Excessive parameter to builtin %s", qualified_name);
396 y2internal ("attachParameter returned %s", err_tp->toString ().c_str ());
400 } // for each actual parameter
402 // now must check if we got fewer parameters than needed
403 // or there was another error while resolving the overload
404 constTypePtr err_tp = bi_call->finalize (RubyLogger::instance ());
407 // apparently the error was already reported?
408 y2error ("Error type %s when finalizing builtin %s",
409 err_tp->toString ().c_str (), qualified_name);
414 y2debug ("Ruby is calling builtin %s", qualified_name);
415 YCPValue ret_yv = bi_call->evaluate (false /* no const subexpr elim */);
425 //y2_logger (level, comp, file, line, function, "%s", message);
428 rb_y2_logger( int argc, VALUE *argv, VALUE self )
430 Check_Type(argv[0], T_FIXNUM);
431 Check_Type(argv[1], T_STRING);
432 Check_Type(argv[2], T_STRING);
433 Check_Type(argv[3], T_FIXNUM);
434 Check_Type(argv[4], T_STRING);
437 for ( i = 5; i < argc; i++)
439 Check_Type(argv[i], T_STRING);
441 y2_logger((loglevel_t)NUM2INT(argv[0]),RSTRING(argv[1])->ptr,RSTRING(argv[2])->ptr,NUM2INT(argv[3]),"",RSTRING(argv[5])->ptr);
450 YCPPathSearch::initialize ();
452 for ( list<string>::const_iterator it = YCPPathSearch::searchListBegin (YCPPathSearch::Module); it != YCPPathSearch::searchListEnd (YCPPathSearch::Module) ; ++it )
454 y2internal("%s\n", (*it).c_str() );
457 rb_mYaST = rb_define_module("YaST");
458 rb_mUi = rb_define_module_under(rb_mYaST, "Ui");
459 rb_define_singleton_method( rb_mUi, "init", RB_METHOD(rb_init_ui), -1);
461 rb_define_method( rb_mYaST, "y2_logger", RB_METHOD(rb_y2_logger), -1);
463 rb_cBroker = rb_define_class_under( rb_mYaST, "Module", rb_cObject);
464 //rb_define_singleton_method( rb_cBroker, "new", RB_METHOD(module_new), 1);
465 rb_define_alloc_func(rb_cBroker, yast_module_allocate);
466 rb_define_method(rb_cBroker, "initialize", RB_METHOD(yast_module_initialize), 1);
467 rb_define_method( rb_cBroker, "method_missing", RB_METHOD(yast_module_proxy_method), -1);
468 rb_define_method( rb_cBroker, "name", RB_METHOD(yast_module_name), -1);
470 ryast_path_init(rb_mYaST);
471 ryast_term_init(rb_mYaST);