How to use the Code DOM?

Directly.

        To use the Code DOM, you can create your Code DOM tree, and give it to the Eiffel Code DOM to generate the Eiffel code associated.

        First of all, we will have to create a valid Code DOM tree. Here is the code to create a valid code DOM in Eiffel.

create_code_dom_tree: SYSTEM_DLL_CODE_COMPILE_UNIT is
			-- create codeDOM tree
	local
		l_compile_unit: SYSTEM_DLL_CODE_COMPILE_UNIT
		l_namespace: SYSTEM_DLL_CODE_NAMESPACE
		l_class_1, l_class_2, l_class_3: SYSTEM_DLL_CODE_TYPE_DECLARATION
		l_parent_class: SYSTEM_DLL_CODE_TYPE_REFERENCE
		l_sys: SYSTEM_DLL_CODE_NAMESPACE_IMPORT
		added: INTEGER
		l_attribute: SYSTEM_DLL_CODE_MEMBER_FIELD
		l_procedure: SYSTEM_DLL_CODE_MEMBER_METHOD
		l_type_return_function: SYSTEM_DLL_CODE_TYPE_REFERENCE
		l_parameter: SYSTEM_DLL_CODE_PARAMETER_DECLARATION_EXPRESSION
		l_comments: SYSTEM_DLL_CODE_COMMENT_STATEMENT
		l_variable: SYSTEM_DLL_CODE_VARIABLE_DECLARATION_STATEMENT
	do
			-- defining compile unit
		createl_compile_unit.make
			-- adding referenced assemblies
		added := l_compile_unit.referenced_assemblies.add (("C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\mscorlib.dll").to_cil)
		added := l_compile_unit.referenced_assemblies.add (("C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\system.dll").to_cil)
		added := l_compile_unit.referenced_assemblies.add (("C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\system.xml.dll").to_cil)
			-- defining namespace "sample"
		create l_namespace.make_from_name (("sample").to_cil)
			-- importing namespace
		create l_sys.make_from_name_space (("system").to_cil)
		l_namespace.imports.add (l_sys)
			-- adding `namespace' to `compile_unit'
		added := l_compile_unit.namespaces.add (l_namespace)

	--------------------------- CLASS_1 ---------------------------
			-- Defining class
		create l_class_1.make_from_name (("CLASS_1").to_cil)
			-- adding comments to 'CLASS_2'
		create l_comments.make_from_text_and_doc_comment (("Class with two attributes").to_cil, true)
		added := l_class_1.comments.add (l_comments)
			-- adding class to 'l_namespace'
		added := l_namespace.types.add (l_class_1)
			-- adding an attribute to 'l_class_1'
		create l_attribute.make_from_type_and_name_2 (("System.Int32").to_cil, ("my_attribute").to_cil)
		added := l_class_1.members.add (l_attribute)
			-- adding an other attribute to 'l_class_1'
		create l_attribute.make_from_type_and_name_2 (("System.Double").to_cil, ("my_2_attribute").to_cil)
		added := l_class_1.members.add (l_attribute)

	--------------------------- CLASS_2 ---------------------------
			-- Defining class CLASS_2
		create l_class_2.make_from_name (("CLASS_2").to_cil)
			-- adding comments to 'CLASS_2'
		create l_comments.make_from_text_and_doc_comment (("This class inherit CLASS_1, and is client of CLASS_3").to_cil, true)
		added := l_class_2.comments.add (l_comments)
			-- adding 'class_2' to 'namespace'
		added := l_namespace.types.add (l_class_2)
			-- adding an attribute to 'l_class_2'
		create l_attribute.make_from_type_and_name_2 (("CLASS_1").to_cil, ("my_attribute_class_2").to_cil)
		added := l_class_2.members.add (l_attribute)
			-- adding comments to attribute
		create l_comments.make_from_text (("This comment is from the DOM").to_cil)
		added := l_attribute.comments.add (l_comments)

			-- adding inheritance : 'l_class_1' is parent 'class_2'
		createl_parent_class.make_from_type_name (l_class_1.name)
			--parent_class.set_array_element_type (feature_clause)
		added := l_class_2.base_types.add_code_type_reference (l_parent_class)

			-- adding an other attribute to 'class_2'
		create l_attribute.make_from_type_and_name_2 (("CLASS_3").to_cil, ("my_2_attribute_class_2").to_cil)
		added := l_class_2.members.add (l_attribute)

			-- adding procedure my_procedure to `class_2'
		createl_procedure.make
		added := l_class_2.members.add (l_procedure)
			-- set `my_procedure'
		l_procedure.set_name (("my_procedure").to_cil)
		create l_parameter.make_from_type_and_name_2 (("System.Single").to_cil, ("param_1").to_cil)
		added := l_procedure.parameters.add (l_parameter)
		create l_parameter.make_from_type_and_name_2 (("System.Double").to_cil, ("param_2").to_cil)
		added := l_procedure.parameters.add (l_parameter)
		create l_variable.make_from_type_and_name_2 (("System.Int32").to_cil, ("my_local_variable").to_cil)
		added := l_procedure.statements.add_code_statement (l_variable)
			-- adding comments to procedure
		create l_comments.make_from_text (("This is a function comment").to_cil)
		added := l_procedure.comments.add (l_comments)

			-- adding function my_procedure to `class_2'
		create l_procedure.make
		l_procedure.set_name (("my_function").to_cil)
		create l_parameter.make_from_type_and_name_2 (("System.Int32").to_cil, ("param_1").to_cil)
		added := l_procedure.parameters.add (l_parameter)
		create l_parameter.make_from_type_and_name_2 (("System.Double").to_cil, ("param_2").to_cil)
		added := l_procedure.parameters.add (l_parameter)
		create l_type_return_function.make_from_type_name (("System.Boolean").to_cil)
		l_procedure.set_return_type (l_type_return_function)
		added := l_class_2.members.add (l_procedure)

	--------------------------- CLASS_3 ---------------------------
			-- Defining class
		create l_class_3.make_from_name (("CLASS_3").to_cil)
			-- adding comments to 'CLASS_2'
		create l_comments.make_from_text_and_doc_comment (("Class with two attributes").to_cil, true)
		added := l_class_3.comments.add (l_comments)
			-- adding class to 'l_namespace'
		added := l_namespace.types.add (l_class_3)
			-- adding an attribute to 'l_class_3'
		create l_attribute.make_from_type_and_name_2 (("System.String").to_cil, ("my_attribute").to_cil)
		added := l_class_3.members.add (l_attribute)
			-- adding an other attribute to 'l_class_3'
		create l_attribute.make_from_type_and_name_2 (("System.Object").to_cil, ("my_2_attribute").to_cil)
		added := l_class_3.members.add (l_attribute)

		Result := l_compile_unit
	end

        Then, we have to reference the Eiffel code DOM dll, in the project. Use Project\Project settings, and select the .NET Assemblies tab. Click the Add button, scroll down the list of GAC Assemblies and select ISE.CodedomProvider.ASP.

        Now, we simply have to create an instance of the Eiffel_code_generator, and call the function `generate_code_from_compile_unit' with the above code DOM tree.

	local
		eiffel_code_generator: SYSTEM_DLL_ICODE_GENERATOR
	do
		eiffel_code_generator := (create {EIFFEL_CODE_DOM_PROVIDER}.default_create).create_generator
		eiffel_code_generator.generate_code_from_compile_unit (create_code_dom_tree, Void, Void)
	end

        We will end up with three Eiffel files (class_1.e, class_2.e, class_3.e) generated in the current directory.

Note: When you call the Eiffel code DOM generator, the second argument (STREAM) can be Void. This stream is normally used to put all the generated code. But, an Eiffel system requires each class to be generated in separated files. Then, as a code DOM tree can contain more than one class, the Eiffel code DOM will automatically generate the files it needs to generate the code. These files are generated in the current directory.

Note 2: The option parameter (third parameter) does not have any influence on the code generation, because there is only one syntax style in Eiffel!

Note 3: Make sure that the paths to the assemblies are correct.

 

With some tools (wsdl.exe and xsd.exe).

        wsdl.exe and xsd.exe are two tools given with the Framework SDK. They uses the code DOM to generate code in a given language. So that, you can specify the language you want the code to be generated in. The option to use is 'language' and you have to specify the fully-qualified name for a class implementing System.CodeDom.Compiler.CodeDomProvider. Here is the command line option to use the Eiffel Code DOM, and then generate Eiffel code:

/language:"ISE.codedomprovider.EIFFEL_CODE_DOM_PROVIDER, ISE.CodeDomProvider.ASP, Version=5.2.0.0, Culture=neutral, PublicKeyToken=def26f296efef469" 

 

- WSDL.exe

            wsdl generates the source code associated to a given URL.

            examples:

            wsdl /language:"..." http://www.capescience.com/webservices/airportweather/AirportWeather.wsdl
            wsdl /language:"..." http://www.nanonull.com/TimeService/TimeService.asmx?wsdl

            Both examples will create two ".e" files in the current directory.

 

Note: The out option is unavailable with the Eiffel Code DOM. In fact, in the previous chapter, we saw that the Code DOM does not uses the input stream to generate the code and generate the code in the current directory. It is the same here, and the associated source code will be generated in the current directory.

Note 2: wsdl will also generate an ".ace" file. This file is empty, and has no interest.

           

- XSD.exe

        xsd generates the source code associated to a given xsd file.

        We need an xsd file. We will start with the following xml file (books.xml) that we will convert into an xsd file.

<?xml version="1.0"?>
<bookstore xmlns="generic">
    <book genre="autobiography">
            <title>The Autobiography of Benjamin Franklin</title>
            <author>
		<first-name>Ben</first-name>
		<last-name>Franklin</last-name>
            </author>
            <price>89.88</price>
    </book>
    <book genre="novel">
            <title>The Confidence Man</title>
            <author>
		<first-name>John</first-name>
		<last-name>Melville</last-name>
            </author>
            <price>11.99</price>
    </book>
</bookstore>

        From the xml code above (books.xml), we can generate an xsd file (books.xsd) running the following command line:

        xsd books.xml

        When we have the xsd file, you can generate the Eiffel code corresponding, running this command line:

        xsd /language:"..." books.xsd /c

        The Eiffel code is generated in three different files (bookstore.e, bookstore_book.e, bookstore_book_author.e).

bookstore.e

indexing
	description: "<remarks/>"
	attribute: create {XML_XML_TYPE_ATTRIBUTE}.make [["namespace", ("generic").to_cil]] end,
		create {XML_XML_ROOT_ATTRIBUTE}.make_from_element_name (("bookstore").to_cil)
						[["namespace", ("generic").to_cil], ["is_nullable", False]] end

class
	BOOKSTORE

create {NONE}

feature -- Access

	Items: NATIVE_ARRAY [BOOKSTORE_BOOK]
			-- | <remarks/>
		indexing
			attribute: create {XML_XML_ELEMENT_ATTRIBUTE}.make_from_element_name (("book").to_cil) end
		end

end -- BOOKSTORE

 

bookstore_book.e

indexing
	description: "<remarks/>"
	attribute: create {XML_XML_TYPE_ATTRIBUTE}.make [["namespace", ("generic").to_cil]] end

class
	BOOKSTORE_BOOK

create {NONE}

feature -- Access

	title: SYSTEM_STRING
			-- | <remarks/>

	price: SYSTEM_STRING
			-- | <remarks/>

	author: NATIVE_ARRAY [BOOKSTORE_BOOK_AUTHOR]
			-- | <remarks/>
		indexing
			attribute: create {XML_XML_ELEMENT_ATTRIBUTE}.make_from_element_name (("author").to_cil) end
		end

	genre: SYSTEM_STRING
			-- | <remarks/>
		indexing
			attribute: create {XML_XML_ATTRIBUTE_ATTRIBUTE}.make
						[["form", feature {XML_XML_SCHEMA_FORM}.Unqualified]] end
		end

end -- BOOKSTORE_BOOK

 

bookstore_book_author.e

indexing
	description: "<remarks/>"
	attribute: create {XML_XML_TYPE_ATTRIBUTE}.make [["namespace", ("generic").to_cil]] end

class
	BOOKSTORE_BOOK_AUTHOR

create {NONE}

feature -- Access

	firstname: SYSTEM_STRING
			-- | <remarks/>
		indexing
			attribute: create {XML_XML_ELEMENT_ATTRIBUTE}.make_from_element_name (("first-name").to_cil) end
		end

	lastname: SYSTEM_STRING
			-- | <remarks/>
		indexing
			attribute: create {XML_XML_ELEMENT_ATTRIBUTE}.make_from_element_name (("last-name").to_cil) end
		end

end -- BOOKSTORE_BOOK_AUTHOR


 

Note: xsd prompt that the code is generated in the file books.ace. As we saw in the previous chapters, this file is useless, and we are only interested in the three ".e" files generated in the current directory.