# Copyright (C) 2001 Tobias Peters # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this library; if not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. class Idl_Module attr_reader :name attr_reader :constants attr_reader :exceptions attr_reader :interfaces attr_reader :node_constants # create a "module" object by parsing the W3C IDL file def initialize(istream) @name = "dom" @constants = [] @exceptions = [] @interfaces = [] @node_constants = [] # load IDL file into memory lines = istream.readlines() # skip all lines above the module declaration nil until (lines.shift =~ /^module dom/) lines.shift # skip 1 more line # parse exceptions, constants and interfaces until (lines.empty?) case lines[0] when /^\s*exception/ # parse an exception @exceptions << Idl_Exception.new(self, lines) when /^\s*const/ # parse a constant @constants << Idl_Constant.new(self, nil, lines.shift) when /^\s*interface.*\{/ # parse an interface declaration @interfaces << Idl_Interface.new(self, lines) else lines.shift # skip empty lines and comments end end end def get_c_value_name C_NAME_PREFIX + "_module" end def get_rb_name "DOM" end def get_cpp_name "DOM" end # collect all node type constants in a special array def add_node_constant(node_constant) @node_constants << node_constant end # The module stores references to all Idl_Interface objects and can thus # return such a reference to code which knows the name of this interface def get_interface_with_name(name) interface = nil @interfaces.each {|i| if (i.name() == name) interface = i end } interface end #################### def create_ruby_code (gdome_ruby_c) # We have 5 different areas where code is generated: # Here we define the VALUEs that store the class objects and the module # object @values = (" \n\n\n" + "/* \n" + " * VALUE declarations \n" + " */ \n") # functions for casting ruby DOM objects into their C correspondents @conversion_rb2c =(" \n\n\n" + "/* \n" + " * conversion from ruby to c\n" + " */ \n") # casting the other way 'round (wrapping) @conversion_c2rb =(" \n\n\n" + "/* \n" + " * conversion from c to ruby\n" + " */ \n") # The C functions that implement the behaviour of the DOM API methods @methods = (" \n\n\n" + "/* \n" + " * method definitions \n" + " */ \n") # The function that initializes the class and module VALUEs, defines the # constants, and binds the methods to the classes @init_func = (" \n\n\n" + "/* \n" + " * Init the dom module \n" + " */ \n" + " \n" + "void Init_gdome() \n" + "{ \n") # the module object @values << "static VALUE " + get_c_value_name() + ";\n" # the bootstrap method as a method of the module @methods << "static VALUE #{C_NAME_PREFIX}_implementation(VALUE self) \n" + "{ \n" + " return #{c2rb_name('DOMImplementation')}(gdome_di_mkref()); \n" + "} \n" # an exception raiser @conversion_rb2c << " static VALUE rbdom_raise(GdomeException e) { if (e) { rb_raise(#{rbdom_class_name('DOMException')}, \"%d\", (int)e); } return Qnil; }\n" # initialize the module VALUE, bind the bootstrap method @init_func << (" #{get_c_value_name()} = rb_define_module(\"Dom\"); \n" + " \n" + " rb_define_module_function(#{get_c_value_name()}, \n" + " \"implementation\", \n" + " &#{C_NAME_PREFIX}_implementation, \n" + " 0); \n\n") # an adapter method @methods << <<-EOS static char* gdome_di_saveDocToString(GdomeDOMImplementation * di, GdomeDocument * doc, unsigned int mode, GdomeException * e) { char * return_value = NULL; gdome_di_saveDocToMemory(di, doc, &return_value, mode, e); return return_value; } EOS # tell objects contained in this module to generate their code (@exceptions + @interfaces + @constants).each{|idl_object| idl_object.create_ruby_code() } @init_func << "}\n"; # write all the code to a file [@values, @conversion_rb2c, @conversion_c2rb, @methods, @init_func].each {|s| gdome_ruby_c.puts (s + "\n\n\n") } end # ruby code is added piece by piece to the member strings def add_ruby_code (where, what) case (where) when "values" @values << what when "conversion_rb2c" @conversion_rb2c << what when "conversion_c2rb" @conversion_c2rb << what when "methods" @methods << what when "init_func" @init_func << what else raise ("unknown region '#{where}' for code addition") end end ################### def create_cpp_code (gdome_cpp_hh, # the header file, open for writing gdome_cpp_cc, # the implementation file, as above extra_declarations) # extra method declarations outside # the DOM API # tell objects contained in this module to generate their code if (@constants.size > 0) gdome_cpp_hh << (" \n" + " /* \n" + " Constants: We use enums so that you can use constants as \n" + " case labels \n" + " */ \n" + " enum { \n") @constants.each{|c| c.create_cpp_code(gdome_cpp_hh) } gdome_cpp_hh << (" }; \n\n") end gdome_cpp_hh << (" \n" + " /* Exceptions: */ \n") @exceptions.each{|e| e.create_cpp_code(gdome_cpp_hh, gdome_cpp_cc) } gdome_cpp_hh << (" \n" + " /* Forward declarations of all interfaces: */ \n") @interfaces.each{|i| i.create_forward_declaration(gdome_cpp_hh) } gdome_cpp_hh << (" \n" + " /* All interface declarations: */ \n") @interfaces.each{|i| i.create_cpp_code(gdome_cpp_hh, gdome_cpp_cc, extra_declarations) } end end