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 #define GetY2Object(obj, po) \
60 Data_Get_Struct(obj, Y2Namespace, po)
62 static VALUE rb_mYaST;
63 static VALUE rb_mY2ModuleProxy;
66 static VALUE rb_cBroker;
68 // make the compiler happy when
69 // calling rb_define_method()
70 typedef VALUE (ruby_method)(...);
73 #define RB_FINALIZER(func) ((void (*)(...))func)
75 // this macro saves us from typing
76 // (ruby_method*) & method_name
77 // in rb_define_method
78 #define RB_METHOD(func) ((VALUE (*)(...))func)
80 Y2Component *owned_uic = 0;
81 Y2Component *owned_wfmc = 0;
85 getNs (const char * ns_name)
87 Import import(ns_name); // has a static cache
88 Y2Namespace *ns = import.nameSpace();
91 y2error ("Ruby call: Can't import namespace '%s'", ns_name);
102 y2milestone("init_wfm");
103 // if (Y2WFMComponent::instance () == 0)
105 y2milestone("WFM init");
106 owned_wfmc = Y2ComponentBroker::createClient ("wfm");
109 y2error ("Cannot create WFM component");
115 rb_init_ui( int argc, VALUE *argv, VALUE self )
117 const char *ui_name = "ncurses";
121 Check_Type(argv[0], T_STRING);
122 ui_name = RSTRING(argv[0])->ptr;
126 y2error ("Zero or one arguments required (ui name, default %s", ui_name);
130 Y2Component *c = YUIComponent::uiComponent ();
133 y2debug ("UI component not created yet, creating %s", ui_name);
135 c = Y2ComponentBroker::createServer (ui_name);
138 y2error ("Cannot create component %s", ui_name);
142 if (YUIComponent::uiComponent () == 0)
144 y2error ("Component %s is not a UI", ui_name);
149 // got it - initialize, remember
150 c->setServerOptions (0, NULL);
156 y2debug ("UI component already present: %s", c->name ().c_str ());
161 typedef struct brokerinfo
163 Y2Component *component;
168 // mark for garbage collection
169 // NOT USED, ONLY WHEN USING DATA_WRAP_STRUCT
171 yast_module_mark( BrokerInfo *info )
174 // dispose a namespace
175 // NOT USED, ONLY WHEN USING DATA_WRAP_STRUCT
177 yast_module_free( BrokerInfo *info )
179 //std::cout << "Deleting namespace." << std::endl;
184 yast_module_allocate( VALUE klass )
186 BrokerInfo *info = new BrokerInfo;
187 return Data_Wrap_Struct( klass, yast_module_mark, RB_FINALIZER(yast_module_free), info );
191 yast_module_initialize( VALUE self, VALUE param_ns_name )
193 Check_Type(param_ns_name, T_STRING);
194 rb_iv_set(self, "@namespace_name", param_ns_name);
201 yast_module_name( VALUE self )
203 return rb_iv_get(self, "@namespace_name");
207 yast_module_methods( VALUE self )
212 //forward declaration
213 YCPValue ycp_call_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv );
216 * looks a component for a namespace
220 ycp_module_lookup_namespace_component(VALUE self, VALUE name)
223 c = Y2ComponentBroker::getNamespaceComponent(RSTRING(name)->ptr);
226 y2internal("No component can provide namespace %s\n", RSTRING (name)->ptr);
227 rb_raise( rb_eRuntimeError, "No YaST component can provide namespace %s\n", RSTRING (name)->ptr);
229 y2internal("component name %s\n", c->name().c_str());
234 tries to import a namespace and throws a NameError if
238 ycp_module_import_namespace( VALUE self, VALUE namespace_name)
240 Y2Namespace *ns = getNs( RSTRING (namespace_name)->ptr);
243 rb_raise( rb_eNameError, "Component cannot import namespace '%s'", RSTRING (namespace_name)->ptr);
248 y2internal("Namespace created from %s\n", ns->filename().c_str());
254 ycp_module_import( VALUE self, VALUE name)
256 ycp_module_lookup_namespace_component(self,name);
257 ycp_module_import_namespace(self,name);
261 * iterates all symbols in a namespace and yields the
262 * symbol name and category
265 ycp_module_each_symbol(VALUE self, VALUE namespace_name)
267 Y2Namespace *ns = getNs( RSTRING (namespace_name)->ptr);
270 rb_raise( rb_eRuntimeError, "Error getting namespace '%s'", RSTRING (namespace_name)->ptr );
275 y2internal("Got namespace from %s\n", ns->filename().c_str());
278 for (int i=0; i < ns->symbolCount(); ++i)
280 SymbolEntryPtr s = ns->symbolEntry(i);
281 VALUE arr = rb_ary_new();
282 rb_ary_push(arr, rb_str_new2(s->name()));
283 rb_ary_push(arr, ID2SYM(rb_intern(s->catString().c_str())));
290 * Forwards a ruby call to the namespace
291 * First argument is the namespace
292 * then function name and arguments
295 ycp_module_forward_call(int argc, VALUE *argv, VALUE self)
297 VALUE symbol = argv[1];
298 VALUE namespace_name = argv[0];
300 // the func name (1st argument, is a symbol
301 // lets convert it to string
302 VALUE symbol_str = rb_funcall(symbol, rb_intern("to_s"), 0);
303 y2internal("Dynamic Proxy: [%s::%s] with [%d] params\n", RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr, argc);
305 //Check_Type(argv[0], T_STRING);
306 //y2internal(RSTRING (symbol)->ptr);
307 //Data_Get_Struct( self, class Y2Namespace, ns );
308 //ns = gNameSpaces[self];
310 // get the name of the module
311 //VALUE namespace_name = rb_funcall(self, rb_intern("name"), 0);
315 // this is a hack before the builtin namespaces get a uniform interface:
316 if (! strcmp (RSTRING (namespace_name)->ptr, "SCR"))
318 y2internal("Dynamic Proxy: [%s::%s] is a call to SCR\n", RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr);
320 res = ycp_call_builtin( RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr, argc, argv);
321 return ycpvalue_2_rbvalue(res);
325 ycp_module_lookup_namespace_component(self, namespace_name);
327 // import the namespace
328 //Y2Namespace *ns = c->import(RSTRING (namespace_name)->ptr);
329 Y2Namespace *ns = getNs( RSTRING (namespace_name)->ptr);
332 rb_raise( rb_eRuntimeError, "Component cannot import namespace '%s' for symbol '%s'", RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr );
337 y2internal("Namespace created from %s\n", ns->filename().c_str());
340 y2internal("Namespace %s initialized\n", RSTRING (namespace_name)->ptr);
342 TableEntry *sym_te = ns->table()->find (RSTRING(symbol_str)->ptr);
346 y2error ("No such symbol %s::%s", RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr);
347 rb_raise( rb_eNameError, "YCP symbol '%s' not found in namespace '%s'", RSTRING(symbol_str)->ptr, RSTRING (namespace_name)->ptr );
351 if (sym_te->sentry ()->isVariable () ||
352 sym_te->sentry ()->isReference ())
354 y2internal ("Variable or reference %s\n", RSTRING(symbol_str)->ptr);
356 //ret_yv = YCP_getset_variable (aTHX_ ns_name, sym_te->sentry (), args);
360 Y2Function* call = ns->createFunctionCall (RSTRING(symbol_str)->ptr, 0 /*Type::fromSignature("list<string>()")*/);
364 y2internal ("Cannot create function call %s\n", RSTRING(symbol_str)->ptr);
365 rb_raise( rb_eRuntimeError, "Can't create call to %s::%s", RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr);
368 // add the parameters
369 for (int i=2; i < argc; i++)
372 y2internal ("Appending parameter #%d\n", i);
373 YCPValue v = rbvalue_2_ycpvalue(arg);
374 y2internal ("Appending parameter #%s : %s\n", i, v->toString());
375 call->appendParameter (v);
377 call->finishParameters ();
379 YCPValue res = call->evaluateCall ();
381 y2internal ("Call succeded\n");
382 //y2internal ("Result: %i\n", res->asList()->size());
383 return ycpvalue_2_rbvalue(res);
388 YCPValue ycp_call_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv )
390 // access directly the statically declared builtins
391 extern StaticDeclaration static_declarations;
392 string qualified_name_s = module_name + "::" + func_name;
393 const char *qualified_name = qualified_name_s.c_str ();
395 y2milestone("Qualified name '%s'", qualified_name);
397 this does not work across namespaces
398 TableEntry *bi_te = static_declarations.symbolTable ()->find (qualified_name);
401 y2error ("No such builtin %s",qualified_name);
405 SymbolEntry *bi_se = bi_te->sentry ();
406 assert (bi_se != NULL);
407 assert (bi_se->isBuiltin ());
408 declaration_t bi_dt = bi_se->declaration ();
410 declaration_t *bi_dt = static_declarations.findDeclaration (qualified_name);
413 y2error ("No such builtin '%s'", qualified_name);
416 y2milestone("builtin '%s' found.", module_name.c_str());
417 // construct a builtin call using the proper overloaded builtin
418 YEBuiltin *bi_call = new YEBuiltin (bi_dt);
420 // attach the parameters:
422 // we would like to know the destination type so that we could
423 // convert eg a Ruby scalar to a YCP symbol, but because the
424 // builtins may be overloaded, let's say we want Any
426 // maybe a special exceptional hack to make Path for the 1st argument?
428 // go through the actual parameters
430 for (j = 1; j < argc; ++j)
432 y2milestone("builtin param '%d'", j-1);
433 // convert the value according to the expected type:
434 constTypePtr param_tp = (j == 0)? Type::Path : Type::Any;
435 y2milestone("builtin param '%d' 1", j-1);
437 // convert the first argument to a path
440 param_v = rbvalue_2_ycppath(argv[j]);
442 param_v = rbvalue_2_ycpvalue(argv[j] /*, param_tp */);
444 y2milestone("builtin param '%d' 2", j-1);
445 if (param_v.isNull ())
447 // an error has already been reported, now refine it.
448 // Can't know parameter name?
449 y2error ("... when passing parameter #%u to builtin %s",
453 // Such YConsts without a specific type produce invalid
454 // bytecode. (Which is OK here)
455 // The actual parameter's YCode becomes owned by the function call?
456 YConst *param_c = new YConst (YCode::ycConstant, param_v);
457 // for attaching the parameter, must get the real type so that it matches
458 constTypePtr act_param_tp = Type::vt2type (param_v->valuetype ());
459 // Attach the parameter
460 // Returns NULL if OK, Type::Error if excessive argument
461 // Other errors (bad code, bad type) shouldn't happen
462 constTypePtr err_tp = bi_call->attachParameter (param_c, act_param_tp);
465 if (err_tp->isError ())
467 // TODO really need to know the place in Ruby code
468 // where we were called from.
469 y2error ("Excessive parameter to builtin %s", qualified_name);
473 y2internal ("attachParameter returned %s", err_tp->toString ().c_str ());
477 } // for each actual parameter
479 // now must check if we got fewer parameters than needed
480 // or there was another error while resolving the overload
481 constTypePtr err_tp = bi_call->finalize (RubyLogger::instance ());
484 // apparently the error was already reported?
485 y2error ("Error type %s when finalizing builtin %s",
486 err_tp->toString ().c_str (), qualified_name);
491 y2debug ("Ruby is calling builtin %s", qualified_name);
492 YCPValue ret_yv = bi_call->evaluate (false /* no const subexpr elim */);
502 //y2_logger (level, comp, file, line, function, "%s", message);
505 rb_y2_logger( int argc, VALUE *argv, VALUE self )
507 Check_Type(argv[0], T_FIXNUM);
508 Check_Type(argv[1], T_STRING);
509 Check_Type(argv[2], T_STRING);
510 Check_Type(argv[3], T_FIXNUM);
511 Check_Type(argv[4], T_STRING);
514 for ( i = 5; i < argc; i++)
516 Check_Type(argv[i], T_STRING);
518 y2_logger((loglevel_t)NUM2INT(argv[0]),RSTRING(argv[1])->ptr,RSTRING(argv[2])->ptr,NUM2INT(argv[3]),"",RSTRING(argv[5])->ptr);
527 YCPPathSearch::initialize ();
529 for ( list<string>::const_iterator it = YCPPathSearch::searchListBegin (YCPPathSearch::Module); it != YCPPathSearch::searchListEnd (YCPPathSearch::Module) ; ++it )
531 y2internal("%s\n", (*it).c_str() );
534 rb_mYaST = rb_define_module("YaST");
536 //rb_mYCP = rb_define_module_under(rb_mYaST, "YCP");
537 rb_mYCP = rb_define_module("YCP");
538 rb_define_singleton_method( rb_mYCP, "import", RB_METHOD(ycp_module_import), 1);
539 rb_define_singleton_method( rb_mYCP, "forward_call", RB_METHOD(ycp_module_forward_call), -1);
540 rb_define_singleton_method( rb_mYCP, "each_symbol", RB_METHOD(ycp_module_each_symbol), 1);
543 rb_mUi = rb_define_module_under(rb_mYCP, "Ui");
544 rb_define_singleton_method( rb_mUi, "init", RB_METHOD(rb_init_ui), -1);
547 rb_define_method( rb_mYaST, "y2_logger", RB_METHOD(rb_y2_logger), -1);
549 rb_cBroker = rb_define_class_under( rb_mYaST, "Module", rb_cObject);
550 //rb_define_singleton_method( rb_cBroker, "new", RB_METHOD(module_new), 1);
551 rb_define_alloc_func(rb_cBroker, yast_module_allocate);
552 rb_define_method(rb_cBroker, "initialize", RB_METHOD(yast_module_initialize), 1);
553 //rb_define_method( rb_cBroker, "method_missing", RB_METHOD(yast_module_proxy_method), -1);
554 rb_define_method( rb_cBroker, "name", RB_METHOD(yast_module_name), -1);
556 ryast_path_init(rb_mYaST);
557 ryast_term_init(rb_mYaST);