Files
php-gtk-src/generator/generator.php
2001-03-07 15:03:35 +00:00

549 lines
17 KiB
PHP

<?php
/*
* PHP-GTK - The PHP language bindings for GTK+
*
* Copyright (C) 2001 Andrei Zmievski <andrei@php.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
/* $Id$ */
/*
* Significant portions of this generator are based on the pygtk code generator
* developed by James Henstridge <jamesh@daa.com.au>.
*
*/
require "arg_types.php";
require "override.php";
require "scheme.php";
require "templates.php";
class Generator {
var $parser = null;
var $overrides = null;
var $prefix = null;
var $constants = "/* Generated from gtk.defs */\n\n";
var $function_entry = "\nstatic function_entry %s_functions[] = {\n";
var $function_entry_end = "\t{NULL, NULL, NULL}\n};\n\n";
var $register_classes = "\nvoid php_gtk_register_classes(void)\n{\n\tzend_class_entry ce;\n";
var $byref_def = array();
function Generator(&$parser, &$overrides, $prefix)
{
$this->parser = &$parser;
$this->overrides = &$overrides;
$this->prefix = $prefix;
}
function register_types()
{
global $matcher;
foreach ($this->parser->objects as $object)
$matcher->register_object($object->c_name);
foreach ($this->parser->enums as $enum) {
if ($enum->def_type == 'flags')
$matcher->register_flag($enum->c_name);
else
$matcher->register_enum($enum->c_name);
}
}
function parse_byref($parse_type)
{
$byref_name = "NULL";
if (trim(implode('', $parse_type))) {
$byref_name = str_replace(' ', 'A', implode('', $parse_type));
if (!isset($this->byref_def[$byref_name])) {
$this->byref_def[$byref_name] = sprintf("unsigned char byref_" . $byref_name . "[] = {%d, %s};\n", sizeof($parse_type), str_replace(' ', 'BYREF_NONE', str_replace('F', 'BYREF_FORCE', implode(',', $parse_type))));
}
$byref_name = "byref_$byref_name";
}
return $byref_name;
}
function write_constants($fp)
{
fwrite($fp, "\nvoid php_gtk_register_constants(int module_number ELS_DC)\n");
fwrite($fp, "{\n");
foreach ($this->parser->enums as $enum) {
if ($this->overrides->is_ignored($enum->c_name)) continue;
fwrite($fp, "\n /* " . $enum->def_type . " " . $enum->c_name . " */\n");
foreach ($enum->values as $enum_value) {
fwrite($fp, " REGISTER_LONG_CONSTANT(\"$enum_value[1]\", $enum_value[1], CONST_CS | CONST_PERSISTENT);\n");
}
}
fwrite($fp, "}\n\n");
}
function write_method($fp, $obj_name, $method)
{
global $matcher,
$method_call_tpl,
$method_tpl;
$specs = '';
$var_list = new Var_List();
$parse_list = array('');
$arg_list = array('');
$extra_code = array();
$after_code = array();
$parse_type = array();
if ($method->varargs)
trigger_error("varargs functions not supported", E_USER_ERROR);
foreach ($method->params as $params_array) {
list($param_type, $param_name, $param_default, $param_null) = $params_array;
if (isset($param_default) && strpos($specs, '|') === false)
$specs .= '|';
$handler = &$matcher->get($param_type);
if ($handler === null) {
error_log("Could not write method $method->name (parameter type $param_type)");
return;
}
$specs .= $handler->write_param($param_type,
$param_name,
$param_default,
$param_null,
$var_list,
$parse_list,
$arg_list,
$extra_code,
$after_code,
$parse_type,
false);
}
$arg_list = implode(', ', $arg_list);
$parse_list = implode(', ', $parse_list);
$extra_code = implode('', $extra_code);
$after_code = implode('', $after_code);
$method_call = sprintf($method_call_tpl,
$method->c_name,
substr(convert_typename($obj_name), 1),
$arg_list);
$ret_handler = &$matcher->get($method->return_type);
if ($ret_handler === null) {
error_log("Could not write function $method->name (return type $method->return_type)");
return;
}
$return_tpl = $ret_handler->write_return($method->return_type, $var_list);
$return_code = sprintf($return_tpl,
$method_call,
$after_code);
$method_code = sprintf($method_tpl,
strtolower($method->c_name),
$var_list->to_string(),
$specs,
$parse_list,
$extra_code,
$return_code);
fwrite($fp, $method_code);
return $this->parse_byref($parse_type);
}
function write_constructor($fp, $obj_name, $constructor)
{
global $matcher,
$constructor_tpl;
$specs = '';
$var_list = new Var_List();
$parse_list = array('');
$arg_list = array();
$extra_code = array();
$after_code = array();
$parse_type = array();
foreach ($constructor->params as $params_array) {
list($param_type, $param_name, $param_default, $param_null) = $params_array;
if (isset($param_default) && strpos($specs, '|') === false)
$specs .= '|';
$handler = &$matcher->get($param_type);
if ($handler === null) {
error_log("Could not write constructor $constructor->name (parameter type $param_type)");
return;
}
$specs .= $handler->write_param($param_type,
$param_name,
$param_default,
$param_null,
$var_list,
$parse_list,
$arg_list,
$extra_code,
$after_code,
$parse_type,
true);
}
$arg_list = implode(', ', $arg_list);
$parse_list = implode(', ', $parse_list);
$extra_code = implode('', $extra_code);
$after_code = implode('', $after_code);
$var_list->add('GtkObject', '*wrapped_obj');
$constructor_code = sprintf($constructor_tpl,
strtolower($constructor->c_name),
$var_list->to_string(),
$specs,
$parse_list,
$extra_code,
$constructor->c_name,
$arg_list,
$obj_name);
fwrite($fp, $constructor_code);
return $this->parse_byref($parse_type);
}
function write_function($fp, $function)
{
global $matcher,
$function_call_tpl,
$function_tpl;
$specs = '';
$var_list = new Var_List();
$parse_list = array('');
$arg_list = array();
$extra_code = array();
$after_code = array();
$parse_type = array();
if ($function->varargs)
trigger_error("varargs functions not supported", E_USER_ERROR);
foreach ($function->params as $params_array) {
list($param_type, $param_name, $param_default, $param_null) = $params_array;
if (isset($param_default) && strpos($specs, '|') === false)
$specs .= '|';
$handler = &$matcher->get($param_type);
if ($handler === null) {
error_log("Could not write function $function->name (parameter type $param_type)");
return;
}
$specs .= $handler->write_param($param_type,
$param_name,
$param_default,
$param_null,
$var_list,
$parse_list,
$arg_list,
$extra_code,
$after_code,
$parse_type,
false);
}
$arg_list = implode(', ', $arg_list);
$parse_list = implode(', ', $parse_list);
$extra_code = implode('', $extra_code);
$after_code = implode('', $after_code);
$function_call = sprintf($function_call_tpl,
$function->c_name,
$arg_list);
$ret_handler = &$matcher->get($function->return_type);
if ($ret_handler === null) {
error_log("Could not write function $function->name (return type $function->return_type)");
return;
}
$return_tpl = $ret_handler->write_return($function->return_type, $var_list);
$return_code = sprintf($return_tpl,
$function_call,
$after_code);
$function_code = sprintf($function_tpl,
strtolower($function->c_name),
$var_list->to_string(),
$specs,
$parse_list,
$extra_code,
$return_code);
fwrite($fp, $function_code);
return $this->parse_byref($parse_type);
}
function write_prop_getter($fp, $object)
{
global $matcher,
$prop_check_tpl,
$prop_getter_tpl;
$obj_cast = substr(convert_typename($object->c_name), 1);
$prop_checks = '';
$else_clause = "\t";
foreach ($object->fields as $field_def) {
list($field_type, $field_name) = $field_def;
$var_list = new Var_List();
$handler = &$matcher->get($field_type);
if ($handler === null) {
error_log("Could not write getter for $object->c_name '$field_name' field (field type $field_type)");
continue;
}
$prop_tpl = $handler->write_return($field_type, $var_list);
$prop_code = sprintf($prop_tpl,
$obj_cast . '(PHP_GTK_GET(object))->' . $field_name, "");
$prop_code = str_replace("\n", "\n\t", $prop_code);
$var_list_code = $var_list->to_string();
$prop_checks .= sprintf($prop_check_tpl,
$else_clause,
$field_name,
$var_list_code ? $var_list_code . "\t" : '',
$prop_code);
$else_clause = ' else ';
}
fwrite($fp, sprintf($prop_getter_tpl,
strtolower($object->in_module . '_' . $object->name),
$prop_checks));
}
function write_static_vars($fp) {
fwrite($fp, "\n/* static variables */\n");
foreach ($this->parser->objects as $object)
fwrite($fp, "static zend_class_entry *$object->ce;\n");
}
function write_objects($fp)
{
global $function_entry_tpl,
$register_getter_tpl,
$init_class_tpl,
$get_type_tpl;
foreach ($this->parser->objects as $object) {
$object_module = strtolower($object->in_module);
$object_lname = strtolower($object->name);
fwrite($fp, "\n/* object $object->c_name */\n");
$this->register_classes .= sprintf($init_class_tpl,
$object_module . $object_lname,
'php_' . $object_module . '_' . $object_lname,
count($object->fields) ? 'php_gtk_get_property' : 'NULL');
if ($object->parent == null)
$this->register_classes .= "\t$object->ce = zend_register_internal_class_ex(&ce, NULL, NULL);\n";
else {
$parent_obj = $this->parser->find_parent($object);
$this->register_classes .= "\t$object->ce = zend_register_internal_class_ex(&ce, $parent_obj->ce, NULL);\n" .
"\tg_hash_table_insert(php_gtk_class_hash, g_strdup(\"Gtk$object->name\"), $object->ce);\n";
}
if (count($object->fields)) {
$this->register_classes .= sprintf($register_getter_tpl, $object->ce, $object_module . '_' . $object_lname);
}
$function_entry = sprintf($this->function_entry, $this->prefix . "_" . $object_lname);
$constructor = $this->parser->find_constructor($object);
if ($this->overrides->is_overriden($constructor->c_name)) {
list(, $constructor_override) = $this->overrides->get_override($constructor->c_name);
fwrite($fp, $constructor_override . "\n");
$function_entry .= sprintf($function_entry_tpl,
strtolower($constructor->is_constructor_of),
strtolower($constructor->c_name),
'NULL');
}
else if ($constructor != null && !$this->overrides->is_ignored($constructor->c_name)) {
if ($byref = $this->write_constructor($fp, $object->c_name, $constructor)) {
$function_entry .= sprintf($function_entry_tpl,
strtolower($constructor->is_constructor_of),
strtolower($constructor->c_name),
$byref);
} else {
$function_entry .= sprintf($function_entry_tpl,
strtolower($constructor->is_constructor_of),
'no_constructor', 'NULL');
}
}
/* insert get_type() as class method */
$lclass = strtolower(substr(convert_typename($object->c_name), 1));
$function_entry .= sprintf($function_entry_tpl,
'get_type',
$lclass . '_get_type',
'NULL');
fwrite($fp, sprintf($get_type_tpl, $lclass, $lclass));
foreach ($this->parser->find_methods($object) as $method) {
if ($this->overrides->is_overriden($method->c_name)) {
list($method_name, $method_override) = $this->overrides->get_override($method->c_name);
fwrite($fp, $method_override . "\n");
if (!isset($method_name))
$method_name = $method->name;
$function_entry .= sprintf($function_entry_tpl,
strtolower($method->name),
strtolower($method->c_name),
'NULL');
}
else if (!$this->overrides->is_ignored($method->c_name)) {
if ($byref = $this->write_method($fp, $object->c_name, $method)) {
$function_entry .= sprintf($function_entry_tpl,
strtolower($method->name),
strtolower($method->c_name),
$byref);
}
}
}
if (isset($this->overrides->extra_methods[$object->c_name])) {
foreach ($this->overrides->extra_methods[$object->c_name] as $method_cname => $method_data) {
list($method_name, $method_override) = $method_data;
fwrite($fp, $method_override . "\n");
if (!isset($method_name))
$method_name = $method_cname;
$function_entry .= sprintf($function_entry_tpl,
strtolower($method_name),
strtolower($method_cname),
'NULL');
}
}
$function_entry .= $this->function_entry_end;
fwrite($fp, $function_entry);
if (count($object->fields))
$this->write_prop_getter($fp, $object);
}
}
function write_functions($fp)
{
global $function_entry_tpl;
fwrite($fp, "\n/* object Gtk */\n");
fwrite($fp, "static zend_class_entry *gdk_ce;\n");
fwrite($fp, "static zend_class_entry *gtk_ce;\n");
$this->register_classes .= "\n\tINIT_CLASS_ENTRY(ce, \"gdk\", php_gdk_functions);\n"
. "\tgdk_ce = zend_register_internal_class_ex(&ce, NULL, NULL);\n";
$this->register_classes .= "\n\tINIT_CLASS_ENTRY(ce, \"gtk\", php_gtk_functions);\n"
. "\tgtk_ce = zend_register_internal_class_ex(&ce, NULL, NULL);\n";
$function_entry["gdk"] = sprintf($this->function_entry, 'php_gdk');
$function_entry["gtk"] = sprintf($this->function_entry, $this->prefix);
foreach ($this->parser->functions as $function) {
if ($this->overrides->is_overriden($function->c_name)) {
list($function_name, $function_override) = $this->overrides->get_override($function->c_name);
fwrite($fp, $function_override . "\n");
if ($function->name == $function->c_name)
$function_name = substr($function->name, 4);
else
$function_name = $function->name;
$function_entry[substr($function->c_name, 0, 3)] .= sprintf($function_entry_tpl,
strtolower($function_name),
strtolower($function->c_name),
'NULL');
}
else if (!$this->overrides->is_ignored($function->c_name)) {
if ($byref = $this->write_function($fp, $function)) {
if ($function->name == $function->c_name)
$function_name = substr($function->name, 4);
else
$function_name = $function->name;
$function_entry[substr($function->c_name, 0, 3)] .= sprintf($function_entry_tpl,
$function_name,
strtolower($function->c_name),
$byref);
}
}
}
$function_entry["gdk"] .= $this->function_entry_end;
$function_entry["gtk"] .= $this->function_entry_end;
fwrite($fp, $function_entry["gdk"]);
fwrite($fp, $function_entry["gtk"]);
}
function write_no_constructor($fp)
{
fwrite($fp, "PHP_FUNCTION(wrap_no_constructor)\n" .
"{\n" .
" php_error(E_WARNING, \"%s: An abstract or unimplemented class\", get_active_function_name());\n" .
" php_gtk_invalidate(this_ptr);\n" .
"}\n\n");
}
function create_source()
{
/* Rename to php_gtk_gen.c */
if ($fp = fopen("../src/php_gtk_gen.c", "w")) {
fwrite($fp, "\n#include \"php_gtk.h\"\n");
fwrite($fp, "\n#if HAVE_PHP_GTK\n");
fwrite($fp, "\n#include \"php_gtk_gen.h\"\n");
$this->write_constants($fp);
$this->write_static_vars($fp);
$this->write_functions($fp);
$this->write_no_constructor($fp);
$this->write_objects($fp);
fwrite($fp, $this->register_classes . "}\n");
fwrite($fp, "\n#endif HAVE_PHP_GTK\n");
fclose($fp);
}
if ($fp = fopen("../src/php_gtk_gen.h", "w")) {
fwrite($fp, implode('', $this->byref_def));
fclose($fp);
}
}
}
$argc = $HTTP_SERVER_VARS['argc'];
$argv = $HTTP_SERVER_VARS['argv'];
if ($argc < 2)
die("usage: php -q generator.php defsfile [overridesfile [prefix]]\n");
if ($argc > 2) {
$overrides = new Overrides($argv[2]);
if ($argc > 3)
$prefix = $argv[3];
else
$prefix = 'php_gtk';
}
else
$overrides = new Overrides();
$parser = new Defs_Parser($argv[1]);
$generator = new Generator($parser, $overrides, $prefix);
$parser->start_parsing();
$generator->register_types();
$generator->create_source();
?>