<?xml version="1.0"?> 

<!--
	description:

		"Adding a new Eiffel built-in routine"

	library: "Gobo Eiffel Tools Library"
	copyright: "Copyright (c) 2010, Eric Bezault and others"
	license: "MIT License"
	date: "$Date$"
	revision: "$Revision$"
-->

<chapter xmlns="http://www.gobosoft.com/eiffel/gobo/documentation" id="tools/new_builtin_routine">
<chapterinfo>
	<copyright>
		<year>2010</year>
		<holder>Eric Bezault</holder>
	</copyright>
	<author>
		<firstname>Eric</firstname><surname>Bezault</surname>
	</author>
	<email>ericb@gobosoft.com</email>
	<date>27 June 2010</date>
</chapterinfo>

<title>Adding a new Eiffel built-in routine</title>

<para>
The following sections will describe step by step what needs to be done
in order to add support for new built-in routines in the Eiffel compiler.
</para>

<section><title>Class and Feature names</title>
<para>
The first thing to do is to declare the name of the built-in feature and
the name of its class. Let's assume that the built-in feature <featurename>foo</featurename>
has been declared in class <classname>BAR</classname>. These feature and
class names will have to be declared as follows in class <classname>ET_TOKEN_CONSTANTS</classname>
if not already done:
<blockquote><programlisting>
feature -- Class names

	bar_class_name: ET_CLASS_NAME
			-- "BAR" class name
		once
			create {ET_IDENTIFIER} Result.make (capitalized_bar_name)
		ensure
			bar_class_name_not_void: Result /= Void
		end

feature -- Feature names

	foo_feature_name: ET_FEATURE_NAME
			-- 'foo' feature name
		once
			create {ET_IDENTIFIER} Result.make (foo_name)
		ensure
			foo_feature_name_not_void: Result /= Void
		end

feature -- Keyword and symbol names

	capitalized_bar_name: STRING = "BAR"
			-- Name of Eiffel class "BAR"

	foo_name: STRING = "foo"
			-- Name of Eiffel feature 'foo'
</programlisting></blockquote>
It is a good practice to keep these features in alphabetic order in their
respective feature clauses. Note that <featurename>capitalized_bar_name</featurename>
and <featurename>foo_name</featurename> also need to be listed in feature <featurename>strings</featurename>
from class <classname>ET_EIFFEL_SCANNER_SKELETON</classname>:
<blockquote><programlisting>
	strings: DS_HASH_TABLE [INTEGER, STRING]
			-- Strings known by the current scanner, and the associated
			-- hash codes when they are used as identifier
		once
			...
				-- Class names.
			Result.force_new (-1, tokens.capitalized_bar_name)
			...
				-- Feature names.
			Result.force_new (-1, tokens.foo_name)
			...
		end
</programlisting></blockquote>
Again, try to keep them in alphabetic order in their respective sections.
</para>
</section>

<section><title>Built-in feature codes</title>
<para>
Each built-in feature is associated with a code which is made up of a
class identifier and a feature identifier within this class. Still assuming that
the built-in feature <featurename>foo</featurename>
has been declared in class <classname>BAR</classname>, the following
features need to be declared in class <classname>ET_TOKEN_CODES</classname>
if not already done:
<blockquote><programlisting>
feature -- Built-in codes

	builtin_bar_feature (a_feature_code: INTEGER): INTEGER
			-- Full code for built-in feature from class "BAR"
		do
			Result := builtin_bar_class * builtin_capacity + a_feature_code
		end

	builtin_bar_class: INTEGER = XX
	builtin_bar_foo: INTEGER = YY
			-- Codes for built-in features from class "BAR"
</programlisting></blockquote>
where XX is the class identifier whose value should be different of all other
<featurename>builtin_*_class</featurename> declared in this feature clause, and YY
is a unique identifier within the built-in features of this class. Note that the
value of YY should be between 1 and <featurename>builtin_capacity</featurename> - 1.
The value of <featurename>builtin_capacity</featurename> will need to be adjusted
if there are more built-in features within a given class.
</para>
</section>

<section><title>Validity checker</title>
<para>
When features are flattened, the Eiffel compiler checks whether features declared
as built-in are known and if they have the expected signature. This is done in class
<classname>ET_BUILTIN_FEATURE_CHECKER</classname>. Let's assume first that the
feature <featurename>foo</featurename> in class <classname>BAR</classname> is
a built-in procedure with one argument of type 'like Current'. The following features
need to be modified or added in class
<classname>ET_BUILTIN_FEATURE_CHECKER</classname>:
<blockquote><programlisting>
	check_builtin_function_validity (a_feature: ET_EXTERNAL_FUNCTION)
			-- Check validity of built-in `a_feature', written in `current_class'.
			-- Set `has_fatal_error' if a fatal error occurred.
		require
			a_feature_not_void: a_feature /= Void
		local
			l_name: ET_CLASS_NAME
		do
			l_name := current_class.name
			if ... then
			...
			elseif l_name.same_class_name (tokens.bar_class_name) then
				check_builtin_bar_function_validity (a_feature)
			...
			else
					-- Unknown built-in routine.
				a_feature.set_builtin_code (tokens.builtin_unknown)
				if unknown_builtin_reported then
					set_fatal_error
					error_handler.report_gvkbu1a_error (current_class, a_feature)
				end
			end
		end

	check_builtin_bar_function_validity (a_feature: ET_EXTERNAL_FUNCTION)
			-- Check validity of built-in `a_feature' from class "BAR".
			-- Set `has_fatal_error' if a fatal error occurred.
		require
			a_feature_not_void: a_feature /= Void
		local
			l_formals: ET_FORMAL_ARGUMENT_LIST
		do
				-- List function names first, then procedure names.
			if ... then
			...
			elseif a_feature.name.same_feature_name (tokens.foo_feature_name) then
					-- 'BAR.foo' should be a procedure.
				a_feature.set_builtin_code (tokens.builtin_bar_feature (tokens.builtin_bar_foo))
				set_fatal_error
				error_handler.report_gvkbs0a_error (current_class, a_feature, &lt;&lt;tokens.like_current.type&gt;&gt;, Void)
			...
			else
					-- Unknown built-in routine.
				a_feature.set_builtin_code (tokens.builtin_unknown)
				if unknown_builtin_reported then
					set_fatal_error
					error_handler.report_gvkbu1a_error (current_class, a_feature)
				end
			end
		end

	check_builtin_procedure_validity (a_feature: ET_EXTERNAL_PROCEDURE)
			-- Check validity of built-in `a_feature', written in `current_class'.
			-- Set `has_fatal_error' if a fatal error occurred.
		require
			a_feature_not_void: a_feature /= Void
		local
			l_name: ET_CLASS_NAME
		do
			l_name := current_class.name
			if ... then
			...
			elseif l_name.same_class_name (tokens.bar_class_name) then
				check_builtin_bar_procedure_validity (a_feature)
			...
			else
					-- Unknown built-in routine.
				a_feature.set_builtin_code (tokens.builtin_unknown)
				if unknown_builtin_reported then
					set_fatal_error
					error_handler.report_gvkbu1a_error (current_class, a_feature)
				end
			end
		end

	check_builtin_bar_procedure_validity (a_feature: ET_EXTERNAL_PROCEDURE)
			-- Check validity of built-in `a_feature' from class "BAR".
			-- Set `has_fatal_error' if a fatal error occurred.
		require
			a_feature_not_void: a_feature /= Void
		local
			l_formals: ET_FORMAL_ARGUMENT_LIST
		do
				-- List procedure names first, then function names.
			if ... then
			...
			elseif a_feature.name.same_feature_name (tokens.foo_feature_name) then
				a_feature.set_builtin_code (tokens.builtin_bar_feature (tokens.builtin_bar_foo))
				l_formals := a_feature.arguments
				if l_formals = Void or else l_formals.count /= 1 then
						-- The signature should be 'foo (a: like Current)'.
					set_fatal_error
					error_handler.report_gvkbs0a_error (current_class, a_feature, &lt;&lt;tokens.like_current.type&gt;&gt;, Void)
				elseif not l_formals.formal_argument (1).type.same_syntactical_type (tokens.like_current, current_class, current_class) then
						-- The signature should be 'foo (a: like Current)'.
					set_fatal_error
					error_handler.report_gvkbs0a_error (current_class, a_feature, &lt;&lt;tokens.like_current.type&gt;&gt;, Void)
				end
			...
			else
					-- Unknown built-in routine.
				a_feature.set_builtin_code (tokens.builtin_unknown)
				if unknown_builtin_reported then
					set_fatal_error
					error_handler.report_gvkbu1a_error (current_class, a_feature)
				end
			end
		end
</programlisting></blockquote>
</para>
<para>
Now if feature <featurename>foo</featurename> is a built-in function of type <classname>INTEGER</classname>,
here is how the features <featurename>check_builtin_bar_function_validity</featurename> and
<featurename>check_builtin_bar_procedure_validity</featurename> of class
<classname>ET_BUILTIN_FEATURE_CHECKER</classname> will look like:
<blockquote><programlisting>
	check_builtin_bar_function_validity (a_feature: ET_EXTERNAL_FUNCTION)
			-- Check validity of built-in `a_feature' from class "BAR".
			-- Set `has_fatal_error' if a fatal error occurred.
		require
			a_feature_not_void: a_feature /= Void
		local
			l_formals: ET_FORMAL_ARGUMENT_LIST
		do
				-- List function names first, then procedure names.
			if ... then
			...
			elseif a_feature.name.same_feature_name (tokens.foo_feature_name) then
				a_feature.set_builtin_code (tokens.builtin_bar_feature (tokens.builtin_bar_foo))
				l_formals := a_feature.arguments
				if l_formals = Void or else l_formals.count /= 1 then
						-- The signature should be 'foo (a: like Current): INTEGER'.
					set_fatal_error
					error_handler.report_gvkbs0a_error (current_class, a_feature, &lt;&lt;tokens.like_current.type&gt;&gt;, current_universe.integer_type)
				elseif not l_formals.formal_argument (1).type.same_syntactical_type (tokens.like_current, current_class, current_class) then
						-- The signature should be 'foo (a: like Current): INTEGER'.
					set_fatal_error
					error_handler.report_gvkbs0a_error (current_class, a_feature, &lt;&lt;tokens.like_current.type&gt;&gt;, current_universe.integer_type)
				elseif not a_feature.type.same_syntactical_type (current_universe.integer_type, current_class, current_class) then
						-- The signature should be 'foo (a: like Current): INTEGER'.
					set_fatal_error
					error_handler.report_gvkbs0a_error (current_class, a_feature, &lt;&lt;tokens.like_current.type&gt;&gt;, current_universe.integer_type)
				end
			...
			else
					-- Unknown built-in routine.
				a_feature.set_builtin_code (tokens.builtin_unknown)
				if unknown_builtin_reported then
					set_fatal_error
					error_handler.report_gvkbu1a_error (current_class, a_feature)
				end
			end
		end

	check_builtin_bar_procedure_validity (a_feature: ET_EXTERNAL_PROCEDURE)
			-- Check validity of built-in `a_feature' from class "BAR".
			-- Set `has_fatal_error' if a fatal error occurred.
		require
			a_feature_not_void: a_feature /= Void
		local
			l_formals: ET_FORMAL_ARGUMENT_LIST
		do
				-- List procedure names first, then function names.
			if ... then
			...
			elseif a_feature.name.same_feature_name (tokens.foo_feature_name) then
					-- 'BAR.foo' should be a function.
				a_feature.set_builtin_code (tokens.builtin_bar_feature (tokens.builtin_bar_foo))
				set_fatal_error
				error_handler.report_gvkbs0a_error (current_class, a_feature, &lt;&lt;tokens.like_current.type&gt;&gt;, current_universe.integer_type)
			...
			else
					-- Unknown built-in routine.
				a_feature.set_builtin_code (tokens.builtin_unknown)
				if unknown_builtin_reported then
					set_fatal_error
					error_handler.report_gvkbu1a_error (current_class, a_feature)
				end
			end
		end
</programlisting></blockquote>
</para>
<para>
Various examples with different combinations of argument and result types can be
found in class <classname>ET_BUILTIN_FEATURE_CHECKER</classname>.
</para>
</section>

<section><title>Dynamic type sets</title>
<para>
The Gobo Eiffel compiler uses the dynamic type sets of the target of the
feature calls to implement dynamic binding and CAT-call checking. Each
expression is associated with a dynamic type set which is then propagated
when there is an assignment or argument passing. The dynamic type set of
the 'Result' entity of built-in functions needs to be built. If it is only
made up of exactly one type which is the declared type of the 'Result'
entity of the built-in function, then nothing special needs to be done.
The default implementation will take care of this case. On the other
hand, if the dynamic type set is more complicated or if the built-in
feature calls internally another feature whose dynamic type sets need to
be updated as well (for example feature <featurename>twin</featurename>
calls feature <featurename>copy</featurename>), then the following code
needs to appear in class <classname>ET_DYNAMIC_TYPE_BUILDER</classname>:
<blockquote><programlisting>
feature {NONE} -- Feature validity

	check_external_builtin_function_validity (a_feature: ET_EXTERNAL_FUNCTION)
			-- Check validity of `a_feature'.
			-- `a_feature' is a built-in function.
			-- Set `has_fatal_error' if a fatal error occurred.
		require
			a_feature_not_void: a_feature /= Void
			a_feature_is_builtin: a_feature.is_builtin
			builtin_feature_known: not a_feature.is_builtin_unknown
		local
			l_builtin_class: INTEGER
		do
			l_builtin_class := a_feature.builtin_code // builtin_capacity
			inspect l_builtin_class
			...
			when builtin_bar_class then
				inspect a_feature.builtin_code \\ builtin_capacity
				when builtin_bar_foo then
					report_builtin_bar_foo (a_feature)
				else
					report_builtin_function (a_feature)
				end
			...
			else
				report_builtin_function (a_feature)
			end
		end

feature {NONE} -- Built-in features

	report_builtin_bar_foo (a_feature: ET_EXTERNAL_FUNCTION)
			-- Report that built-in feature 'BAR.foo' is being analyzed.
		require
			no_error: not has_fatal_error
			a_feature_not_void: a_feature /= Void
		local
			l_result_type: ET_DYNAMIC_TYPE
		do
			if current_type = current_dynamic_type.base_type then
				...
				l_result_type := result_type_set.static_type
				propagate_builtin_result_dynamic_types (l_result_type, current_dynamic_feature)
				...
			end
		end
</programlisting></blockquote>
By default, nothing needs to be done for built-in procedures. But there are some
special cases when the built-in procedure will call internally another feature or
will have an effect on the dynamic type set of some entities (for example in class
<classname>SPECIAL</classname>, the procedure <featurename>put</featurename> will
have an effect on the dynamic type set of <featurename>item</featurename>).
In this case, code similar to the one above will be needed for these built-in
procedures. Examples can be found in class <classname>ET_DYNAMIC_TYPE_BUILDER</classname>.
</para>
</section>

<section><title>Generation of C code</title>
<para>
The last thing to do is to make sure that the C code of the built-in feature is
properly generated. Let's assume again that the built-in feature is a function
<featurename>foo</featurename> declared in class <classname>BAR</classname>. Then
the following code needs to appear in class <classname>ET_C_GENERATOR</classname>:
<blockquote><programlisting>
feature {NONE} -- Feature generation

	print_external_builtin_function_body (a_feature: ET_EXTERNAL_ROUTINE)
			-- Print to `current_file' the body of built-in feature `a_feature'.
			-- `a_feature' is a built-in function.
		require
			a_feature_not_void: a_feature /= Void
			a_feature_is_function: a_feature.is_function
			a_feature_is_builtin: a_feature.is_builtin
			valid_feature: current_feature.static_feature = a_feature
		local
			l_builtin_class: INTEGER
		do
			l_builtin_class := a_feature.builtin_code // builtin_capacity
			inspect l_builtin_class
			...
			when builtin_bar_class then
				print_external_builtin_bar_function_body (a_feature)
			...
			else
					-- Internal error: unknown built-in feature.
					-- This error should already have been reported in ET_FEATURE_FLATTENER.
				set_fatal_error
				error_handler.report_giaaa_error
			end
		end

	print_external_builtin_bar_function_body (a_feature: ET_EXTERNAL_ROUTINE)
			-- Print to `current_file' the body of built-in feature `a_feature'.
			-- `a_feature' is a built-in function introduced in class "BAR".
		require
			a_feature_not_void: a_feature /= Void
			a_feature_is_function: a_feature.is_function
			a_feature_is_builtin: a_feature.is_builtin
			a_feature_is_builtin_platform: (a_feature.builtin_code // builtin_capacity) = builtin_bar_class
			valid_feature: current_feature.static_feature = a_feature
		do
			inspect a_feature.builtin_code \\ builtin_capacity
			...
			when builtin_bar_foo then
				print_builtin_bar_foo_body (a_feature)
			...
			else
					-- Internal error: unknown built-in feature.
					-- This error should already have been reported in ET_FEATURE_FLATTENER.
				set_fatal_error
				error_handler.report_giaaa_error
			end
		end

feature {NONE} -- Built-in feature generation

	print_builtin_bar_foo_body (a_feature: ET_EXTERNAL_ROUTINE)
			-- Print to `current_file' the body of `a_feature' corresponding
			-- to built-in feature 'BAR.foo'.
		require
			a_feature_not_void: a_feature /= Void
			valid_feature: current_feature.static_feature = a_feature
		do
			...
		end
</programlisting></blockquote>
In some cases, the C code can be inlined. This is when the call to the C function
can be avoided by calling the C code directly. In that case the code above in class
<classname>ET_C_GENERATOR</classname> can be changed by replacing
<featurename>print_builtin_bar_foo_body</featurename> by <featurename>print_builtin_bar_foo_call</featurename>,
by adding features <featurename>print_builtin_query_call</featurename>
and <featurename>print_builtin_bar_query_call</featurename>,
and by modifying feature <featurename>print_external_builtin_bar_function_body</featurename>
as follows:
<blockquote><programlisting>
feature {NONE} -- Feature generation

	print_external_builtin_bar_function_body (a_feature: ET_EXTERNAL_ROUTINE)
			-- Print to `current_file' the body of built-in feature `a_feature'.
			-- `a_feature' is a built-in function introduced in class "BAR".
		require
			a_feature_not_void: a_feature /= Void
			a_feature_is_function: a_feature.is_function
			a_feature_is_builtin: a_feature.is_builtin
			a_feature_is_builtin_platform: (a_feature.builtin_code // builtin_capacity) = builtin_bar_class
			valid_feature: current_feature.static_feature = a_feature
		do
			inspect a_feature.builtin_code \\ builtin_capacity
			...
			when builtin_bar_foo then
				fill_call_formal_arguments (a_feature)
				print_indentation_assign_to_result
				print_builtin_bar_foo_call (current_feature, current_type, False)
				print_semicolon_newline
				call_operands.wipe_out
			...
			else
					-- Internal error: unknown built-in feature.
					-- This error should already have been reported in ET_FEATURE_FLATTENER.
				set_fatal_error
				error_handler.report_giaaa_error
			end
		end

feature {NONE} -- Query call generation

	print_builtin_query_call (a_feature: ET_DYNAMIC_FEATURE; a_target_type: ET_DYNAMIC_TYPE; a_check_void_target: BOOLEAN)
			-- Print to `current_file' a call to query `a_feature' (static binding).
			-- `a_feature' is a built-in feature.
			-- `a_target_type' is the dynamic type of the target.
			-- `a_check_void_target' means that we need to check whether the target is Void or not.
			-- Operands can be found in `call_operands'.
			-- Note that the result of the query is not adapted to match the kind
			-- of result type expected by the caller. It is recommended to use
			-- `print_adapted_query_call' whenever possible.
		require
			a_feature_not_void: a_feature /= Void
			a_feature_is_query: a_feature.result_type_set /= Void
			a_feature_is_builtin: a_feature.is_builtin
			a_target_type_not_void: a_target_type /= Void
			call_operands_not_empty: not call_operands.is_empty
		local
			l_builtin_class: INTEGER
		do
			l_builtin_class := a_feature.builtin_code // builtin_capacity
			inspect l_builtin_class
			...
			when builtin_bar_class then
				print_builtin_bar_query_call (a_feature, a_target_type, a_check_void_target)
			...
			else
				print_non_inlined_query_call (a_feature, a_target_type, a_check_void_target)
			end
		end

	print_builtin_bar_query_call (a_feature: ET_DYNAMIC_FEATURE; a_target_type: ET_DYNAMIC_TYPE; a_check_void_target: BOOLEAN)
			-- Print to `current_file' a call to query `a_feature' (static binding).
			-- `a_feature' is a built-in feature introduced in class "BAR".
			-- `a_target_type' is the dynamic type of the target.
			-- `a_check_void_target' means that we need to check whether the target is Void or not.
			-- Operands can be found in `call_operands'.
			-- Note that the result of the query is not adapted to match the kind
			-- of result type expected by the caller. It is recommended to use
			-- `print_adapted_query_call' whenever possible.
		require
			a_feature_not_void: a_feature /= Void
			a_feature_is_query: a_feature.result_type_set /= Void
			a_feature_is_builtin: a_feature.is_builtin
			a_feature_is_builtin_platform: (a_feature.builtin_code // builtin_capacity) = builtin_bar_class
			a_target_type_not_void: a_target_type /= Void
			call_operands_not_empty: not call_operands.is_empty
		do
			inspect a_feature.builtin_code \\ builtin_capacity
			...
			when builtin_bar_foo then
				print_builtin_bar_foo_call (a_feature, a_target_type, a_check_void_target)
			...
			else
				print_non_inlined_query_call (a_feature, a_target_type, a_check_void_target)
			end
		end

feature {NONE} -- Built-in feature generation

	print_builtin_bar_foo_call (a_feature: ET_DYNAMIC_FEATURE; a_target_type: ET_DYNAMIC_TYPE; a_check_void_target: BOOLEAN)
			-- Print to `current_file' a call (static binding) to `a_feature'
			-- corresponding to built-in feature 'BAR.foo'.
			-- `a_target_type' is the dynamic type of the target.
			-- `a_check_void_target' means that we need to check whether the target is Void or not.
			-- Operands can be found in `call_operands'.
		require
			a_feature_not_void: a_feature /= Void
			a_target_type_not_void: a_target_type /= Void
			call_operands_not_empty: not call_operands.is_empty
		do
			...
		end
</programlisting></blockquote>
The code is very similar when the built-in feature is a procedure. First the case
where the C code cannot be inlined:
<blockquote><programlisting>
feature {NONE} -- Feature generation

	print_external_builtin_procedure_body (a_feature: ET_EXTERNAL_ROUTINE)
			-- Print to `current_file' the body of built-in feature `a_feature'.
			-- `a_feature' is a built-in procedure.
		require
			a_feature_not_void: a_feature /= Void
			a_feature_is_procedure: a_feature.is_procedure
			a_feature_is_builtin: a_feature.is_builtin
			valid_feature: current_feature.static_feature = a_feature
		local
			l_builtin_class: INTEGER
		do
			l_builtin_class := a_feature.builtin_code // builtin_capacity
			inspect l_builtin_class
			...
			when builtin_bar_class then
				print_external_builtin_bar_procedure_body (a_feature)
			...
			else
					-- Internal error: unknown built-in feature.
					-- This error should already have been reported in ET_FEATURE_FLATTENER.
				set_fatal_error
				error_handler.report_giaaa_error
			end
		end

	print_external_builtin_bar_procedure_body (a_feature: ET_EXTERNAL_ROUTINE)
			-- Print to `current_file' the body of built-in feature `a_feature'.
			-- `a_feature' is a built-in procedure introduced in class "BAR".
		require
			a_feature_not_void: a_feature /= Void
			a_feature_is_procedure: a_feature.is_procedure
			a_feature_is_builtin: a_feature.is_builtin
			a_feature_is_builtin_any: (a_feature.builtin_code // builtin_capacity) = builtin_bar_class
			valid_feature: current_feature.static_feature = a_feature
		do
			inspect a_feature.builtin_code \\ builtin_capacity
			...
			when builtin_bar_foo then
				print_builtin_bar_foo_body (a_feature)
			...
			else
					-- Internal error: unknown built-in feature.
					-- This error should already have been reported in ET_FEATURE_FLATTENER.
				set_fatal_error
				error_handler.report_giaaa_error
			end
		end

feature {NONE} -- Built-in feature generation

	print_builtin_bar_foo_body (a_feature: ET_EXTERNAL_ROUTINE)
			-- Print to `current_file' the body of `a_feature' corresponding
			-- to built-in feature 'BAR.foo'.
		require
			a_feature_not_void: a_feature /= Void
			valid_feature: current_feature.static_feature = a_feature
		do
			...
		end
</programlisting></blockquote>
And finally when the C code of the built-in procedure can be inlined, replacing
<featurename>print_builtin_bar_foo_body</featurename> by <featurename>print_builtin_bar_foo_call</featurename>,
adding features <featurename>print_builtin_procedure_call</featurename>
and <featurename>print_builtin_bar_procedure_call</featurename>,
and by modifying feature <featurename>print_external_builtin_bar_procedure_body</featurename>
as follows::
<blockquote><programlisting>
feature {NONE} -- Feature generation

	print_external_builtin_bar_procedure_body (a_feature: ET_EXTERNAL_ROUTINE)
			-- Print to `current_file' the body of built-in feature `a_feature'.
			-- `a_feature' is a built-in procedure introduced in class "BAR".
		require
			a_feature_not_void: a_feature /= Void
			a_feature_is_procedure: a_feature.is_procedure
			a_feature_is_builtin: a_feature.is_builtin
			a_feature_is_builtin_any: (a_feature.builtin_code // builtin_capacity) = builtin_bar_class
			valid_feature: current_feature.static_feature = a_feature
		do
			inspect a_feature.builtin_code \\ builtin_capacity
			...
			when builtin_bar_foo then
				fill_call_formal_arguments (a_feature)
				print_builtin_bar_foo_call (current_feature, current_type, False)
				call_operands.wipe_out
			...
			else
					-- Internal error: unknown built-in feature.
					-- This error should already have been reported in ET_FEATURE_FLATTENER.
				set_fatal_error
				error_handler.report_giaaa_error
			end
		end

feature {NONE} -- Procedure call generation

	print_builtin_procedure_call (a_feature: ET_DYNAMIC_FEATURE; a_target_type: ET_DYNAMIC_TYPE; a_check_void_target: BOOLEAN)
			-- Print to `current_file' a call to procedure `a_feature' (static binding).
			-- `a_feature' is a built-in feature.
			-- `a_target_type' is the dynamic type of the target.
			-- `a_check_void_target' means that we need to check whether the target is Void or not.
			-- Operands can be found in `call_operands'.
		require
			a_feature_not_void: a_feature /= Void
			a_feature_is_builtin: a_feature.is_builtin
			a_target_type_not_void: a_target_type /= Void
			call_operands_not_empty: not call_operands.is_empty
		local
			l_builtin_class: INTEGER
		do
			l_builtin_class := a_feature.builtin_code // builtin_capacity
			inspect l_builtin_class
			...
			when builtin_bar_class then
				print_builtin_bar_procedure_call (a_feature, a_target_type, a_check_void_target)
			...
			else
				print_non_inlined_procedure_call (a_feature, a_target_type, a_check_void_target)
			end
		end

	print_builtin_bar_procedure_call (a_feature: ET_DYNAMIC_FEATURE; a_target_type: ET_DYNAMIC_TYPE; a_check_void_target: BOOLEAN)
			-- Print to `current_file' a call to procedure `a_feature' (static binding).
			-- `a_feature' is a built-in feature introduced in class "BAR".
			-- `a_target_type' is the dynamic type of the target.
			-- `a_check_void_target' means that we need to check whether the target is Void or not.
			-- Operands can be found in `call_operands'.
		require
			a_feature_not_void: a_feature /= Void
			a_feature_is_builtin: a_feature.is_builtin
			a_feature_is_builtin_any: (a_feature.builtin_code // builtin_capacity) = builtin_bar_class
			a_target_type_not_void: a_target_type /= Void
			call_operands_not_empty: not call_operands.is_empty
		do
			inspect a_feature.builtin_code \\ builtin_capacity
			when builtin_bar_foo then
				print_builtin_bar_foo_call (a_feature, a_target_type, a_check_void_target)
			...
			else
				print_non_inlined_procedure_call (a_feature, a_target_type, a_check_void_target)
			end
		end

feature {NONE} -- Built-in feature generation

	print_builtin_bar_foo_call (a_feature: ET_DYNAMIC_FEATURE; a_target_type: ET_DYNAMIC_TYPE; a_check_void_target: BOOLEAN)
			-- Print to `current_file' a call (static binding) to `a_feature'
			-- corresponding to built-in feature 'BAR.foo'.
			-- `a_target_type' is the dynamic type of the target.
			-- `a_check_void_target' means that we need to check whether the target is Void or not.
			-- Operands can be found in `call_operands'.
		require
			a_feature_not_void: a_feature /= Void
			a_target_type_not_void: a_target_type /= Void
			call_operands_not_empty: not call_operands.is_empty
		do
			...
		end
</programlisting></blockquote>
</para>
</section>

</chapter>
