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/Y2ComponentCreator.h>
24 #include <yui/YUIComponent.h>
25 #include <wfm/Y2WFMComponent.h>
27 #include <y2/Y2ComponentBroker.h>
28 #include <y2/Y2Namespace.h>
29 #include <y2/Y2Component.h>
30 #include <y2/Y2Function.h>
32 #include <ycp/pathsearch.h>
33 #include <ycp/y2log.h>
34 #include <ycp/YBlock.h>
35 #include <ycp/YExpression.h>
36 #include <ycp/YStatement.h>
37 #include <ycp/YCPValue.h>
38 #include <ycp/YCPBoolean.h>
39 #include <ycp/YCPList.h>
40 #include <ycp/YCPMap.h>
41 #include <ycp/YCPString.h>
42 #include <ycp/YCPInteger.h>
43 #include <ycp/YCPFloat.h>
44 #include <ycp/YCPElement.h>
45 #include <ycp/Import.h>
46 #include <ycp/y2log.h>
51 #include "RubyLogger.h"
52 #include "Y2RubyTypePath.h"
53 #include "Y2RubyTypeTerm.h"
54 #include "Y2RubyTypeConv.h"
57 #define GetY2Object(obj, po) \
58 Data_Get_Struct(obj, Y2Namespace, po)
60 static VALUE rb_mYaST;
64 // make the compiler happy when
65 // calling rb_define_method()
66 typedef VALUE (ruby_method)(...);
69 #define RB_FINALIZER(func) ((void (*)(...))func)
71 // this macro saves us from typing
72 // (ruby_method*) & method_name
73 // in rb_define_method
74 #define RB_METHOD(func) ((VALUE (*)(...))func)
76 Y2Component *owned_uic = 0;
77 Y2Component *owned_wfmc = 0;
78 //Y2Component *owned_scr = 0;
84 getNs (const char * ns_name)
86 Import import(ns_name); // has a static cache
87 Y2Namespace *ns = import.nameSpace();
90 y2error ("ruby call: Can't import namespace '%s'", ns_name);
101 y2milestone("init_wfm");
102 // if (Y2WFMComponent::instance () == 0)
104 y2milestone("WFM init");
105 owned_wfmc = Y2ComponentBroker::createClient ("wfm");
108 y2error ("Cannot create WFM component");
115 // y2milestone("init_scr");
116 // // if (Y2WFMComponent::instance () == 0)
118 // y2milestone("WFM init");
119 // owned_scr = Y2ComponentBroker::createClient ("scr");
120 // if (owned_scr == 0)
122 // y2error ("Cannot create WFM component");
128 rb_init_ui( int argc, VALUE *argv, VALUE self )
130 const char *ui_name = "ncurses";
134 Check_Type(argv[0], T_STRING);
135 ui_name = RSTRING(argv[0])->ptr;
139 y2error ("zero or one arguments required (ui name, default %s", ui_name);
143 Y2Component *c = YUIComponent::uiComponent ();
146 y2debug ("UI component not created yet, creating %s", ui_name);
148 c = Y2ComponentBroker::createServer (ui_name);
151 y2error ("can't create component %s", ui_name);
155 if (YUIComponent::uiComponent () == 0)
157 y2error ("component %s is not a UI", ui_name);
162 // got it - initialize, remember
163 c->setServerOptions (0, NULL);
169 y2debug ("UI component already present: %s", c->name ().c_str ());
174 //forward declaration
175 YCPValue _call_ycp_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv );
178 * looks a component for a namespace
182 ycp_module_lookup_namespace_component(VALUE self, VALUE name)
185 c = Y2ComponentBroker::getNamespaceComponent(RSTRING(name)->ptr);
188 y2internal("no component can provide namespace %s\n", RSTRING (name)->ptr);
189 rb_raise( rb_eRuntimeError, "no YaST component can provide namespace %s\n", RSTRING (name)->ptr);
191 y2internal("component name %s\n", c->name().c_str());
196 tries to import a namespace and throws a NameError if
200 ycp_module_import_namespace( VALUE self, VALUE namespace_name)
202 Y2Namespace *ns = getNs( RSTRING (namespace_name)->ptr);
205 rb_raise( rb_eNameError, "component cannot import namespace '%s'", RSTRING (namespace_name)->ptr);
210 y2internal("namespace created from %s\n", ns->filename().c_str());
216 ycp_module_import( VALUE self, VALUE name)
218 ycp_module_lookup_namespace_component(self,name);
219 return ycp_module_import_namespace(self,name);
223 * iterates all symbols in a namespace and yields the
224 * symbol name and category
227 ycp_module_each_symbol(VALUE self, VALUE namespace_name)
229 Y2Namespace *ns = getNs( RSTRING (namespace_name)->ptr);
232 rb_raise( rb_eRuntimeError, "error getting namespace '%s'", RSTRING (namespace_name)->ptr );
237 y2internal("got namespace from %s\n", ns->filename().c_str());
240 for (unsigned int i=0; i < ns->symbolCount(); ++i)
242 SymbolEntryPtr s = ns->symbolEntry(i);
243 VALUE arr = rb_ary_new();
244 rb_ary_push(arr, rb_str_new2(s->name()));
245 rb_ary_push(arr, ID2SYM(rb_intern(s->catString().c_str())));
254 static bool _yield_symbol_entry(const SymbolEntry & s)
256 VALUE arr = rb_ary_new();
257 rb_ary_push(arr, rb_str_new2(s.name()));
258 rb_ary_push(arr, ID2SYM(rb_intern(s.catString().c_str())));
264 * helper for each_builtin_symbol
266 static const SymbolEntry * __symbol = 0L;
267 static string __name;
270 bool __find_symbol(const SymbolEntry & s)
272 if (s.name() == __name)
281 * iterates all symbols in a namespace and yields the
282 * symbol name and category
285 ycp_module_each_builtin_symbol(VALUE self, VALUE name)
287 extern StaticDeclaration static_declarations;
288 __name = RSTRING(name)->ptr;
289 static_declarations.symbolTable()->forEach(__find_symbol);
291 const SymbolEntry *se = __symbol;
294 y2error ("no such builtin '%s'", RSTRING(name)->ptr);
295 rb_raise( rb_eRuntimeError, "no YCP builtin %s\n", RSTRING(name)->ptr);
298 // convert to a YSymbol to access child symbols
299 const YSymbolEntry *ys = dynamic_cast<const YSymbolEntry *>(se);
302 if ( ys->table() ) ys->table()->forEach(_yield_symbol_entry);
308 ycp_module_each_builtin(VALUE self)
310 extern StaticDeclaration static_declarations;
311 static_declarations.symbolTable()->forEach(_yield_symbol_entry);
316 * Forwards a ruby call to the namespace
317 * First argument is the namespace
318 * then function name and arguments
321 ycp_module_call_ycp_function(int argc, VALUE *argv, VALUE self)
323 y2internal("Dynamic Proxy: [%d] params\n", argc);
324 VALUE symbol = argv[1];
325 VALUE namespace_name = argv[0];
327 // the func name (1st argument, is a symbol
328 // lets convert it to string
329 VALUE symbol_str = rb_funcall(symbol, rb_intern("to_s"), 0);
330 y2internal("Dynamic Proxy: [%s::%s] with [%d] params\n", RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr, argc);
332 //Check_Type(argv[0], T_STRING);
333 //y2internal(RSTRING (symbol)->ptr);
334 //Data_Get_Struct( self, class Y2Namespace, ns );
335 //ns = gNameSpaces[self];
337 // get the name of the module
338 //VALUE namespace_name = rb_funcall(self, rb_intern("name"), 0);
340 ycp_module_lookup_namespace_component(self, namespace_name);
342 // import the namespace
343 //Y2Namespace *ns = c->import(RSTRING (namespace_name)->ptr);
344 Y2Namespace *ns = getNs( RSTRING (namespace_name)->ptr);
347 rb_raise( rb_eRuntimeError, "Component cannot import namespace '%s' for symbol '%s'", RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr );
352 y2internal("Namespace created from %s\n", ns->filename().c_str());
355 y2internal("Namespace %s initialized\n", RSTRING (namespace_name)->ptr);
357 TableEntry *sym_te = ns->table()->find (RSTRING(symbol_str)->ptr);
361 y2error ("No such symbol %s::%s", RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr);
362 rb_raise( rb_eNameError, "YCP symbol '%s' not found in namespace '%s'", RSTRING(symbol_str)->ptr, RSTRING (namespace_name)->ptr );
366 if (sym_te->sentry ()->isVariable () ||
367 sym_te->sentry ()->isReference ())
369 y2internal ("Variable or reference %s\n", RSTRING(symbol_str)->ptr);
371 //ret_yv = YCP_getset_variable (aTHX_ ns_name, sym_te->sentry (), args);
375 Y2Function* call = ns->createFunctionCall (RSTRING(symbol_str)->ptr, 0 /*Type::fromSignature("list<string>()")*/);
379 y2internal ("cannot create function call %s\n", RSTRING(symbol_str)->ptr);
380 rb_raise( rb_eRuntimeError, "can't create call to %s::%s", RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr);
383 // add the parameters
384 for (int i=2; i < argc; i++)
386 YCPValue v = rbvalue_2_ycpvalue(argv[i]);
387 call->appendParameter (v);
389 call->finishParameters ();
391 YCPValue res = call->evaluateCall ();
393 y2internal ("call succeded\n");
394 //y2internal ("Result: %i\n", res->asList()->size());
395 return ycpvalue_2_rbvalue(res);
400 YCPValue _call_ycp_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv )
402 // access directly the statically declared builtins
403 extern StaticDeclaration static_declarations;
405 string qualified_name_s = module_name + "::" + func_name;
406 const char *qualified_name = qualified_name_s.c_str ();
408 y2milestone("qualified name '%s', %d args", qualified_name, argc);
410 declaration_t *bi_dt = static_declarations.findDeclaration (qualified_name);
413 y2error ("no such builtin '%s'", qualified_name);
414 rb_raise( rb_eRuntimeError, "no YCP builtin %s\n", RSTRING(qualified_name)->ptr);
417 y2milestone("builtin '%s' found.", module_name.c_str());
418 // construct a builtin call using the proper overloaded builtin
419 YEBuiltin *bi_call = new YEBuiltin (bi_dt);
421 // attach the parameters:
423 // we would like to know the destination type so that we could
424 // convert eg a Ruby scalar to a YCP symbol, but because the
425 // builtins may be overloaded, let's say we want Any
426 // maybe a special exceptional hack to make Path for the 1st argument?
427 // go through the actual parameters
429 for (j = 0; j < argc; ++j)
431 // convert the value according to the expected type:
432 constTypePtr param_tp = (j == 0)? Type::Path : Type::Any;
434 // convert the first argument to a path
436 // HACK SCR path conversion
437 if ( (j == 0) && (module_name == "SCR") )
438 param_v = rbvalue_2_ycppath(argv[j]);
440 param_v = rbvalue_2_ycpvalue(argv[j] /*, param_tp */);
442 if (param_v.isNull ())
444 // an error has already been reported, now refine it.
445 // Can't know parameter name?
446 y2error ("... when passing parameter #%u to builtin %s",
450 // Such YConsts without a specific type produce invalid
451 // bytecode. (Which is OK here)
452 // The actual parameter's YCode becomes owned by the function call?
453 YConst *param_c = new YConst (YCode::ycConstant, param_v);
454 // for attaching the parameter, must get the real type so that it matches
455 constTypePtr act_param_tp = Type::vt2type (param_v->valuetype ());
456 // Attach the parameter
457 // Returns NULL if OK, Type::Error if excessive argument
458 // Other errors (bad code, bad type) shouldn't happen
459 constTypePtr err_tp = bi_call->attachParameter (param_c, act_param_tp);
462 if (err_tp->isError ())
464 // TODO really need to know the place in Ruby code
465 // where we were called from.
466 y2error ("Excessive parameter to builtin %s", qualified_name);
470 y2internal ("attachParameter returned %s", err_tp->toString ().c_str ());
474 } // for each actual parameter
476 // now must check if we got fewer parameters than needed
477 // or there was another error while resolving the overload
478 constTypePtr err_tp = bi_call->finalize (RubyLogger::instance ());
481 // apparently the error was already reported?
482 y2error ("Error type %s when finalizing builtin %s",
483 err_tp->toString ().c_str (), qualified_name);
488 y2debug ("Ruby is calling builtin %s", qualified_name);
489 YCPValue ret_yv = bi_call->evaluate (false /* no const subexpr elim */);
496 ycp_module_call_ycp_builtin( int argc, VALUE *argv, VALUE self )
498 VALUE symbol = argv[1];
499 VALUE namespace_name = argv[0];
501 // the func name (1st argument, is a symbol
502 // lets convert it to string
503 VALUE symbol_str = rb_funcall(symbol, rb_intern("to_s"), 0);
505 y2internal("builtin proxy: [%s::%s] is a builtin call with %d params\n", RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr, argc);
507 res = _call_ycp_builtin( RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr, argc-2, argv+2);
508 return ycpvalue_2_rbvalue(res);
512 //y2_logger (level, comp, file, line, function, "%s", message);
515 rb_y2_logger( int argc, VALUE *argv, VALUE self )
517 Check_Type(argv[0], T_FIXNUM);
518 Check_Type(argv[1], T_STRING);
519 Check_Type(argv[2], T_STRING);
520 Check_Type(argv[3], T_FIXNUM);
521 Check_Type(argv[4], T_STRING);
524 for ( i = 5; i < argc; i++)
526 Check_Type(argv[i], T_STRING);
528 y2_logger((loglevel_t)NUM2INT(argv[0]),RSTRING(argv[1])->ptr,RSTRING(argv[2])->ptr,NUM2INT(argv[3]),"",RSTRING(argv[5])->ptr);
539 YCPPathSearch::initialize ();
542 for ( list<string>::const_iterator it = YCPPathSearch::searchListBegin (YCPPathSearch::Module); it != YCPPathSearch::searchListEnd (YCPPathSearch::Module) ; ++it )
544 y2internal("search path %s\n", (*it).c_str() );
547 rb_mYaST = rb_define_module("YaST");
549 //rb_mYCP = rb_define_module_under(rb_mYaST, "YCP");
550 rb_mYCP = rb_define_module("YCP");
551 rb_define_singleton_method( rb_mYCP, "import", RB_METHOD(ycp_module_import), 1);
552 rb_define_singleton_method( rb_mYCP, "call_ycp_function", RB_METHOD(ycp_module_call_ycp_function), -1);
553 rb_define_singleton_method( rb_mYCP, "call_ycp_builtin", RB_METHOD(ycp_module_call_ycp_builtin), -1);
555 rb_define_singleton_method( rb_mYCP, "each_symbol", RB_METHOD(ycp_module_each_symbol), 1);
556 rb_define_singleton_method( rb_mYCP, "each_builtin_symbol", RB_METHOD(ycp_module_each_builtin_symbol), 1);
557 rb_define_singleton_method( rb_mYCP, "each_builtin", RB_METHOD(ycp_module_each_builtin), 0);
559 rb_mUi = rb_define_module_under(rb_mYCP, "Ui");
560 rb_define_singleton_method( rb_mUi, "init", RB_METHOD(rb_init_ui), -1);
563 rb_define_method( rb_mYaST, "y2_logger", RB_METHOD(rb_y2_logger), -1);
565 ryast_path_init(rb_mYaST);
566 ryast_term_init(rb_mYaST);