Home modules.gotpike.org
Username: Password: [Create Account]
[Forgot Password?]
Return to module

File Contents

Contents of /wx-0.5/bindgen.pike:

/*
   wxPike - (c) 2005 Julio César Gázquez
 
   bindgen.pike:
   C++ bindings generator
 
*/

class BindingType
{
	string ctype;
	string piketype;
	
	string parameterMacro;
}

class VoidType
{
	inherit BindingType;
	static void create()
	{
		parameterMacro="tVoid";
		ctype="void";
		piketype="void";
	}
	string resultReturn(string scall, string modifier)
	{
		return "\t"+scall+";\n";
	}
	string overrideReturn(string modifier)
	{
		return "\tpop_stack();\n";
	}
}

class IntType
{
	inherit BindingType;
	
	static void create()
	{
		parameterMacro="tInt";
		ctype="int";
		piketype="int";
	}
	string parameterRetrieving(string funcname, int n, string defaultvalue, string modifier)
	{
		string s="\n";
		s+="\tINT_TYPE par"+(string)n+";\n";
		if (defaultvalue) {
			s+="\tif (args<"+(string)(n+1)+")\n";
			s+="\t\tpar"+(string)n+"="+defaultvalue+";\n";
			s+="\telse {\n";
		}
		s+="\tif (Pike_sp["+(string)n+"-args].type!=T_INT)\n";
		s+="\t\tSIMPLE_BAD_ARG_ERROR(\""+funcname+"\","+(string)n+",\"integer\");\n";
		// Guardo el valor
		s+="\tpar"+(string)n;
		s+="=Pike_sp["+(string)n+"-args].u.integer;\n";
		if (defaultvalue)
			s+="\t}\n";
		return s;
	}

	string resultReturn(string scall, string modifier)
	{
		return "\tpush_int("+scall+");\n";
	}
	string overrideReturn(string modifier)
	{
		return "\tint r=Pike_sp[-1].u.integer;\n"
			+"\tpop_stack();\n"	
			+"\treturn r;\n";
	}	
}

class LongType {

	inherit IntType;
	
	static void create()
	{
		parameterMacro="tInt";
		ctype="long";
		piketype="int";
	}
	string overrideReturn(string modifier)
	{
		return "\tlong r=Pike_sp[-1].u.integer;\n"
			+"\tpop_stack();\n"	
			+"\treturn r;\n";
	}	
}
// Should be mixed
class BoolType
{
	inherit BindingType;
	
	static void create()
	{
		parameterMacro="tInt";
		ctype="bool";
		piketype="int";
	}
	string parameterRetrieving(string funcname, int n, string defaultvalue, string modifier)
	{
		string s="\n";
		
		s+="\tbool par"+(string)n+";\n";
		if (defaultvalue) {
			s+="\tif (args<"+(string)(n+1)+")\n";
			s+="\t\tpar"+(string)n+"="+defaultvalue+";\n";
			s+="\telse {\n";
		}

		s+="\tif (Pike_sp["+(string)n+"-args].type!=T_INT)\n";
		s+="\t\tSIMPLE_BAD_ARG_ERROR(\""+funcname+"\","+(string)n+",\"integer\");\n";
		// Guardo el valor
		s+="\tpar"+(string)n;
		s+="=Pike_sp["+(string)n+"-args].u.integer;\n";
		if (defaultvalue)
			s+="\t}\n";		
		return s;
	}
	
	string resultReturn(string scall, string modifier)
	{
		return "\tpush_int("+scall+" ? 1 : 0);\n";
	}
	string overrideReturn(string modifier)
	{
		return "\tbool r=Pike_sp[-1].u.integer;\n"
			+"\tpop_stack();\n"	
			+"\treturn r;\n";
	}		
}
	
class FloatType
{
	inherit BindingType;
	static void create()
	{
		parameterMacro="tFloat";
		ctype="float";
		piketype="float";		
	}
	string parameterRetrieving(string funcname, int n, string defaultvalue, string modifier)
	{
		string s="\n";
		
		s+="\tFLOAT_TYPE par"+(string)n+";\n";
		if (defaultvalue) {
			s+="\tif (args<"+(string)(n+1)+")\n";
			s+="\t\tpar"+(string)n+"="+defaultvalue+";\n";
			s+="\telse {\n";
		} 
		s+="\tif (Pike_sp["+(string)n+"-args].type!=T_FLOAT)\n";
		s+="\t\tSIMPLE_BAD_ARG_ERROR(\""+funcname+"\","+(string)n+",\"float\");\n";
		// Guardo el valor
		s+="\tpar"+(string)n;
		s+="=Pike_sp["+(string)n+"-args].u.float_number;\n";
		if (defaultvalue)
			s+="\t}\n";
		return s;
	}	
	string resultReturn(string scall, string modifier)
	{
		return "\tpush_float("+scall+");\n";
	}
	string overrideReturn(string modifier)
	{
		return "\tfloat r=Pike_sp[-1].u.float_number;\n"
			+"\tpop_stack();\n"	
			+"\treturn r;\n";
	}	
}


class StringType
{
	inherit BindingType;
	static void create()
	{
		parameterMacro="tString"; 
		ctype="wxString";
		piketype="string";
	}

	string parameterRetrieving(string funcname, int n, string defaultvalue, string modifier)
	{
		string s="\n";
		
		s+="\twxString par"+(string)n+";\n";
		if (defaultvalue) {
			s+="\tif (args<"+(string)(n+1)+")\n";
			s+="\t\tpar"+(string)n+"="+defaultvalue+";\n";
			s+="\telse {\n";
		} 
		s+="\tif (Pike_sp["+(string)n+"-args].type!=T_STRING)\n";
		s+="\t\tSIMPLE_BAD_ARG_ERROR(\""+funcname+"\","+(string)n+",\"string\");\n";
		s+="\tstruct pike_string *pstr"+(string)n;
		s+="=(Pike_sp["+(string)n+"-args].u.string);\n";
		s+="\tpar"+(string)n;
		s+="=pstr"+(string)n+"->str;\n";
		if (defaultvalue)
			s+="\t}\n";
		return s;
	} 
	// Unicode? 
	string resultReturn(string scall, string modifier)
	{
		string s="";
		s+="\tconst char *rval=(const char *)"+scall+".c_str();\n";
		s+="\tstruct pike_string *str=make_shared_string(rval);\n";
		s+="\tpush_string(str);\n";
		return s;
	}
	string overrideReturn(string modifier)
	{
		return "\twxString r=Pike_sp[-1].u.string->str;\n"
			+"\tpop_stack();\n"	
			+"\treturn r;\n";
	}	
}


// Este es el único tipo que ha de tener múltiples instancias
// una por cada clase, a fin de poder usarlas como tipo
class ObjectType
{
	inherit BindingType;
	string className;
	static void create(string _className)
	{
		// To allow null references
		parameterMacro="tOr(tObj,tZero)";
		className=_className;
		ctype=_className;
		piketype=_className;
	}
	string parameterRetrieving(string funcname, int n, string defaultvalue, string modifier, string directive)
	{
		string s="\n";
		// Control de tipo
		// No sé si estará bien chequear contra T_OBJECT
		// Guardo el valor
		if (modifier=="*") {
			s+="\t"+className+"* par"+(string)n+";\n";
			if (defaultvalue) {
				s+="\tif (args<"+(string)(n+1)+")\n";
				s+="\t\tpar"+(string)n+"="+defaultvalue+";\n";
				s+="\telse {\n";
			}
			s+="\n\tif (Pike_sp["+(string)n+"-args].type==T_OBJECT) {\n";
			s+="\t\tpar"+(string)n;
			s+="=static_cast<"+className+"*>(  STORAGE(Pike_sp["+(string)n+ "-args].u.object,"+className+")->cppobject);\n";			
			s+="\t} else\n";
			s+="\t\tpar"+(string)n+"=NULL;\n";
			if (defaultvalue)
				s+="\t}\n";
		} else {
			s+="\tif ( Pike_sp["+(string)n+"-args].type!=T_OBJECT";
			if (defaultvalue)
				s+=" && !(args<"+(string)(n+1)+")";
			s+=")\n";
			s+="\t\tSIMPLE_BAD_ARG_ERROR(\""+funcname+"\","+(string)n+",\"object\");\n";
			s+="\t"+className+"& par"+(string)n;
			if (defaultvalue) {
				s+="= (args<"+(string)(n+1)+")\n\t\t? const_cast<"+className+"&>("+defaultvalue+")\n\t\t:  *("+className+"*) STORAGE(Pike_sp["+(string)n+"-args].u.object,"+className+")->cppobject;\n";			
			} else
				s+="=*static_cast<"+className+"*>(STORAGE(Pike_sp["+(string)n+"-args].u.object,"+className+")->cppobject);\n";
		}
		if (directive=="addref") {
			s+="\tif (args>="+(string)(n+1)+")\n";
			s+="\t\tadd_ref(Pike_sp["+(string)n+"-args].u.object);\n";
		} else if (directive=="subref") {
			s+="\tif (args>="+(string)(n+1)+")\n";
			s+="\tfree_object(Pike_sp["+(string)n+"-args.u.object]);\n";
		}
		return s;
	}	

	string resultReturn(string scall, string modifier)
	{
		string s="";
		s+="\tstruct object *o=NULL;\n";

		BindingClass classObj=classIndex[className];
		int virtualClass = classObj ? classObj->virtual : 0;
		
		if (virtualClass && modifier=="*") {
			s+="\t"+className+"__pv* ptr=dynamic_cast<"+className+"__pv*>("+scall+");\n";
			s+="\tif (ptr) {\n";
			s+="\t\to=ptr->pike_object;\n";
			s+="\t\tpush_object( o );\n";
			s+="\t } else\n";
			s+="\t\tpush_undefined();\n";
		} else {
			s+="\to = low_clone( "+className+"_program );\n";
			s+="\tcall_c_initializers( o );\n";
			s+="\tSTORAGE(o,"+className+")->cppobject=";
			
			if (modifier=="*") {
				s+=scall+";\n";
				// object doesn't belong to the wrapper
				// hence it can't delete it
				s+="\tSTORAGE(o,"+className+")->foreign=true;\n";
			} else if (modifier=="&"){
				s+="&("+scall+");\n";
				s+="\tSTORAGE(o,"+className+")->foreign=true;\n";
			} else {// If returns by value, we copy it from the stack
				// and the object 
				s+="new "+className+"("+scall+");\n";
				s+="\tSTORAGE(o,"+className+")->foreign=false;\n";
			}
			s+="\tpush_object( o );\n";
		}
		
		return s;
	}
	string overrideReturn(string modifier)
	{
		string s="\t"+className+"* r=static_cast<"+className+"*>(STORAGE(Pike_sp[-1].u.object,"+className+")->cppobject);\n"
			+"\tpop_stack();\n";
			
		if (modifier=="*")
			s+="\treturn r;\n";
		else
			s+="\treturn *r;\n";
			
		return s;
	}		
}

/* Those currently are just for extern definitions */
class ProgramType
{
	inherit BindingType;

	static void create()
	{
		parameterMacro="tProgram(tObj)"; 
		ctype="struct program*";
		piketype="program";
	}
}

class FunctionType
{
	inherit BindingType;

	static void create()
	{
		parameterMacro="tFuncV(tNone,tMix,tVoid)"; 
		ctype="struct callable*";
		piketype="function";
	}
}

class ArrayIntType
{
	inherit BindingType;

	static void create()
	{
		parameterMacro="tOr(tArr(tInt),tZero)"; 
		ctype="int*";
		piketype="array(int)";
	}
}

class ArrayPCharType
{
	inherit BindingType;

	static void create()
	{
		parameterMacro="tOr(tArr(tString),tZero)"; 
		ctype="char**";
		piketype="array(string)";
	}
}

class ArraywxStringType
{
	inherit BindingType;

	static void create()
	{
		parameterMacro="tOr(tArr(tString),tZero)"; 
		ctype="wxString[]";
		piketype="array(string)";
	}
}


BindingType voidType=VoidType();

mapping(string:BindingType) bindingTypes = ([
	"void":VoidType(),
	"bool":BoolType(),
	"char":IntType(),
	"int":IntType(),
	"long":LongType(),	
	"float":FloatType(),
	"string":StringType(),
	"object":ObjectType("object"),
	"program":ProgramType(),
	"function":FunctionType(),
	"wxString":StringType(),
	"int[]":ArrayIntType(),
	"wxString[]":ArraywxStringType(),
	"*char[]":ArrayPCharType()
	]);

class BindingConstant
{
	string name;
	string value;
	
	void create(string _name, string _value)
	{
		name=_name;
		value=_value;
	}

}
class BindingIntConstant
{
	inherit BindingConstant;
	string pikeDeclaration()
	{
		string pikename=name;
		// Prefix stripping
		if (prefix)
			if (pikename[0..sizeof(prefix)-1]==prefix)
				pikename=pikename[sizeof(prefix)..];
		return "\tADD_INT_CONSTANT(\""+pikename+"\","+value+",0);\n";
	}
	
}

class BindingFloatConstant
{
	inherit BindingConstant;
	string pikeDeclaration()
	{
		string pikename=name;
		// Prefix stripping
		if (prefix)
			if (pikename[0..sizeof(prefix)-1]==prefix)
				pikename=pikename[sizeof(prefix)..];
		return "\tADD_FLOAT_CONSTANT(\""+pikename+"\","+value+",0);\n";
	}
	
}

class BindingStringConstant
{
	inherit BindingConstant;
	string pikeDeclaration()
	{
		string pikename=name;
		// Prefix stripping
		if (prefix)
			if (pikename[0..sizeof(prefix)-1]==prefix)
				pikename=pikename[sizeof(prefix)..];
		return "\tadd_string_constant(\""+pikename+"\","+value+",0);\n";
	}
	
}

class BindingObjectConstant
{
	inherit BindingConstant;
	string className;
	string name;
	string value;
	
	void create(string _className, string _name, string _value)
	{
		className=_className;
		name=_name;
		value=_value;
	}

	string pikeDeclaration()
	{
		string pikename=name;
		string s;
		// Prefix stripping
		if (prefix)
			if (pikename[0..sizeof(prefix)-1]==prefix)
				pikename=pikename[sizeof(prefix)..];
		s="\t{\n";
		s+="\t\tstruct object *o = low_clone( "+className+"_program );\n";
		s+="\t\tcall_c_initializers( o );\n";
		s+="\t\tSTORAGE(o,"+className+")->cppobject=const_cast<"+className+"*>(&"+name+");\n";
		s+="\t\tSTORAGE(o,"+className+")->foreign=true;\n";
		s+="\t\tadd_object_constant(\""+pikename+"\",o,0);\n";
		s+="\t}\n";
		return s;
	}
	
}


class Parameter
{
	BindingType type;
	string modifier;
	string defaultvalue;
	string directive; // addref/subref inc/dec object reference counter
}

class BindingFunction
{
	string name;		// Method Name
	string bfname;		// Binding Function name
	string cppname;		// C++ Method name (Different than Pike's 
				// when implementing a polymorphic C++ 
				// method)
	BindingType returnType;
	string returnMod; // '*' pointer, '&' reference
	array(Parameter) parameters;
	int minParam;
	multiset(string) modifiers;
	
		   // (Coded by hand)
		
	static void create(string _name, string _cppname, BindingType _rt, string _rm, array(BindingType) _params, multiset(string) _modifiers)
	{
		name=_name;
		cppname=_cppname;
		returnType=_rt;
		returnMod=_rm;
		parameters=_params;
		modifiers=_modifiers;
		bfname="f_"+name;
		minParam=sizeof(Array.filter(parameters, lambda(Parameter x) { return !(x->defaultvalue); } ));
	}
	
	string cppDeclaration()
	{
		return "void "+bfname+"(INT32 args)";
	}
	
	string parameterManagementDefinition()
	{
		string s="";
		// Param count check;
		if (minParam>0) {
			s+="\tif (args<"+(string)minParam+")\n";
			s+="\t\tSIMPLE_WRONG_NUM_ARGS_ERROR(\""+name+"\",1);\n";
		}
		// Param type check 
		int i=0;
		BindingType p;
		foreach(parameters, p) {
			s+=p->type->parameterRetrieving(name, i, p->defaultvalue, p->modifier,p->directive);
			i++;
		}
		return s;
	}
	
	string cppCallingDefinition()
	{
		// C++ method call
		string s=cppname+"(";
		int i=0;
		BindingType p;
		foreach(parameters, p) {
			// method call parameters
			if (i>0) s+=", ";
			s+="par"+(int)i;
			i++;
		}
		s+=")";
		return s;
	}
	
	string definition()
	{
		if (modifiers["extern"]) return "";
		// function head;
		string s="void "+bfname+"(INT32 args)\n";
		s+="{\n";
		
		s+=parameterManagementDefinition();
		
		string scall=cppCallingDefinition();
		
		// Discard parameters
		s+="\tpop_n_elems(args);\n";
				
		s+=returnType->resultReturn(scall, returnMod);
		s+="}\n"; 
		return s;
	}
	string pikeDeclaration()
	{
		string s="";
		string pikename=name;
		// Prefix stripping
		if (prefix)
			if (pikename[0..sizeof(prefix)-1]==prefix)
				pikename=pikename[sizeof(prefix)..];		
		s="ADD_FUNCTION(\""+pikename+"\", "+bfname+",tFunc(";
		if (sizeof(parameters)==0)
			s+="tNone";
		else {
			BindingType p;
			foreach(parameters, p) {
				if (p->defaultvalue!=0)
					s+=sprintf(" tOr(tVoid,%s)", p->type->parameterMacro);
				else
					s+=" "+p->type->parameterMacro;
			}
		}
		s+=","+returnType->parameterMacro;
		s+="), 0);";
		return s;	
	}

}

class BindingMethod
{
	inherit BindingFunction;
	string classname;	// Class Name	
		
	static void create(string _classname, string _name, string _cppname, BindingType _rt, string _rm, array(BindingType) _params, multiset(string) _modifiers)
	{
		BindingFunction::create(_name, _cppname, _rt, _rm, _params, _modifiers);
		classname=_classname;	
		bfname="f_"+classname+"__"+name;
	}
	// Declaration for binding's virtual methods override
	string bindingOverrideDeclaration()
	{
		string s="\t"+returnType->ctype+returnMod+" "+cppname+"(";
		s+=");\n";
		return s;
	}
	// Definition for binding's virtual methods override
	string bindingOverrideDefinition()
	{
		string s=returnType->ctype+returnMod+" "+classname+"__pv::"+cppname+"(";
		// Faltan los parametros
		s+=")\n";
		s+="{\n";
		s+="\tpush_method(\""+name+"\");\n";
		// Aca van los push de los parametros
		// el parametro de f_call_function es 1 por el
		// parametro funcion
		// + la cant de parametros que corresponda
		s+="\tf_call_function(1);\n";
		s+=returnType->overrideReturn(returnMod);
		s+="}\n";
		return s;
	}
	// C++ method Calling
	string cppCallingDefinition()
	{
		// C++ method call
		string s;
		if (modifiers["virtual"])
//			s="(("+classname+"*)(THIS->cppobject))->"c+name+"(";
			s="static_cast<"+classname+"*>(THIS->cppobject)->"+classname+"::"+cppname+"(";
		else
			s="static_cast<"+classname+"*>(THIS->cppobject)->"+cppname+"(";
		int i=0;
		BindingType p;
		foreach(parameters, p) {
			// method call parameters
			if (i>0) s+=", ";
			s+="par"+(int)i;
			i++;
		}
		s+=")";
		return s;
	}
	string definition()
	{
		if (modifiers["extern"]) return "";
		// function head;
		string s="void "+bfname+"(INT32 args)\n";
		s+="{\n";
		
		s+=parameterManagementDefinition();
		
		string scall=cppCallingDefinition();
		
		// Discard parameters
		s+="\tpop_n_elems(args);\n";
				
		s+=returnType->resultReturn(scall, returnMod);
		if (modifiers["addrefthis"])
			s+="\tadd_ref(Pike_fp->current_object);\n";
		else if (modifiers["subrefthis"])
			s+="\tfree_object(Pike_fp->current_object);\n";

		s+="}\n";
		return s;
	}
	
	string pikeDeclaration()
	{
		string s="";
		
		s="ADD_FUNCTION(\""+name+"\", "+bfname+",tFunc(";
		if (sizeof(parameters)==0)
			s+="tNone";
		else {
			BindingType p;
			foreach(parameters, p) {
				if (p->defaultvalue!=0)
					s+=sprintf(" tOr(tVoid,%s)", p->type->parameterMacro);
				else
					s+=" "+p->type->parameterMacro;
			}
		}
		s+=","+returnType->parameterMacro;
		s+="), 0);";
		return s;	
	}
	
}

class BindingCreate
{
	inherit BindingMethod;
	string pl;
	
	static void create(string _classname, array(BindingType) _params, multiset(string) _modifiers)
	{
		BindingMethod::create(_classname, "create", 0, voidType, 0, _params, _modifiers );
	}
	string cppDeclaration()
	{
		return "void f_"+classname+"__create(INT32 args)";
	}
	string definition()
	{
		if (modifiers["extern"]) return "";
		BindingType p;
		int i;
		
		// function head;
		string s="void f_"+classname+"__create(INT32 args)\n";
		s+="{\n";
		// Param count check;
		if (minParam>0) {
			s+="\tif (args<"+(string)minParam+")\n";
			s+="\t\tSIMPLE_WRONG_NUM_ARGS_ERROR(\""+name+"\",1);\n";	
		}
		// Param type check 
		i=0;
		foreach(parameters, p) {
			s+=p->type->parameterRetrieving(name, i ,p->defaultvalue, p->modifier,p->directive);
			i++;
		}
		// C++ method call
		string scall;
		if (classIndex[classname]->virtual)
			scall="THIS->cppobject = new "+classname+"__pv(";
		else
			scall="THIS->cppobject = new "+classname+"("; // Constructor
		
		i=0;
		foreach(parameters, p) {
			// method call parameters
			if (i>0) scall+=", ";
			scall+="par"+(int)i;
			i++;
		}
		scall+=")";	

		// Discard parameters
		s+="\tpop_n_elems(args);\n";
				
		// create functions are void, then there are no push returns
		s+="\t"+scall+";\n";
		if (modifiers["addrefthis"])
			s+="\tadd_ref(Pike_fp->current_object);\n";
		else if (classIndex[classname]->virtual)
		if (modifiers["nodestroywrapped"])
			s+="\tTHIS->foreign=true;\n";		
		else
			s+="\tTHIS->foreign=false;\n";
		if (classIndex[classname]->virtual)
		s+="\tstatic_cast<"+classname+"__pv*>(THIS->cppobject)->pike_object=Pike_fp->current_object;\n";
		s+="}\n";
		return s;
	}
	string parameterList()
	{
		if (!pl) {
			pl="";
			BindingType p;
			int i=0;
			foreach(parameters,p) {
				if (i!=0) pl+=", ";
				if (p->modifier)
					pl+=sprintf("%s%s par%d", p->type->ctype,p->modifier,i);
				else
					pl+=sprintf("%s par%d", p->type->ctype,i);
				i++;
			}
		}
		return pl;
	}
	string bindingOverrideDeclaration()
	{
		string s="\t"+classname+"__pv(";
		s+=parameterList();
		s+=");\n";
		return s;
	}
	string bindingOverrideDefinition() 
	{
		string s=classname+"__pv::"+classname+"__pv(";
		string pl=parameterList();
		s+=pl;
		s+=")\n";
		s+="\t: "+classname+"(";
		
		BindingType p;
		int i=0;
		foreach(parameters,p) {
			if (i!=0) s+=", ";
			s+="par"+(string)i;
				i++;
		}
		s+=")\n";
		s+="{\n";
		s+="}\n";
		return s;
	}

}
class BindingClass
{
	string name;
	string storagename;
	string include;
	BindingClass parent;
	array(BindingMethod) functions;

	int virtual; // The class have virtual methods?
	int abstract; // The class is abstract
	
	static void create(string _name, BindingClass|void _parent)
	{
		name=_name;
		parent=_parent;
		functions=({ });
	}
	void addFunction(BindingMethod f)
	{
		functions += ({ f });
	}	
	string cppDeclarations()
	{
		BindingMethod f;
		string s="";
		int hasConstructor=0;
		
		foreach(functions, f) 
			if (f->name=="create") hasConstructor=1;
		if (!hasConstructor && !abstract) {
			functions += ({ BindingCreate(name, ({ }), (< >) ) });
		} 
		foreach(functions, f) {
			s+=f->cppDeclaration()+";\n";
		}
		s+="static void "+name+"_exit_callback( struct object *o );\n";
		return s;
	}
	
	string storageDeclaration()
	{
		string s="";
		BindingMethod f;
		storagename=name;

		// Classes with virtual functions require the definition
		// of a subclass in order to bind those functions with
		// its possible Pike reimplementations.
		if (virtual) {
			storagename+="__pv";
			s+="class "+storagename+" : public "+name+"\n";
			s+="{\n";
			s+="\tpublic:\n";
			s+="\tobject* pike_object;\n";			
			foreach(functions, f) {
				if (f->modifiers["virtual"] || f->name=="create") {
					// Declarar overrides aqui
					s+=f->bindingOverrideDeclaration();
				}
			}
			s+="};\n";
				
		}

		return s;
	}
	
	string bindingOverrideDefinitions()
	{
		string s="";
		if (virtual) {		
			BindingMethod f;
			foreach(functions, f) {
				if (f->modifiers["virtual"] || f->name=="create") {
					// Declarar overrides aqui
					s+=f->bindingOverrideDefinition();
				}
			}
		}
		return s;
	}
	
	string functionsImplementation()
	{
		BindingMethod f;
		string s="";
			
		// method definitions
		foreach(functions, f) {
			s+=f->definition()+"\n\n";
		}
		// Delete C++ object along Pike object is necessary
		// Note: Using THIS seems ok (checked in std modules)
		s+="static void "+name+"_exit_callback( struct object *o )\n";
		s+="{\n";
		s+="\tif (o->prog == "+name+"_program)\n";
		s+="\tif (!THIS->foreign) {\n";
		s+="\t\tdelete static_cast<"+name+"*>(THIS->cppobject);\n";
		s+="\t\tTHIS->foreign=TRUE; // Inherited callbacks must not try to delete it again!\n";
		s+="\t}\n";
		s+="}\n\n";
		return s;
	}

	string pikeDeclarations()
	{
		BindingMethod f;
		
		string s="\tstart_new_program();\n";

		if (parent) {
			s+="\tlow_inherit("+parent->name+"_program, 0,0,0,0,0);\n";
		} else {
			s+="\tADD_STORAGE(wrapper_storage);\n";
		}
  		s+="\tset_exit_callback( "+name+"_exit_callback );\n";

		foreach(functions, f) {
			s+="\t"+f->pikeDeclaration()+"\n";
		}
//		s+="\t"+name+"_program=end_class(\""+name+"\", 0);\n";
		string pikename=name;
		// Prefix stripping
		if (prefix)
			if (pikename[0..sizeof(prefix)-1]==prefix)
				pikename=pikename[sizeof(prefix)..];

		s+="\tadd_program_constant(\""+pikename+"\", ("+name+"_program=end_program()), 0);\n";
		return s;
	}	
}

/*******************************************************************
  Main class here
*******************************************************************/

array(string) includes = ({ });

array(BindingConstant) bindingConstants = ({ });
array(BindingFunction) bindingFunctions = ({ });
array(BindingClass) bindingClasses = ({ });
mapping(string:BindingClass) classIndex = ([ ]);

string prefix;
int verbose;

void parse_const(array(string) words)
{
	// A constant with no value takes the C++
	// macro/const value
	string value=sizeof(words)>3 ? words[3] : words[2];
	BindingConstant c;
	switch (words[1]) {
	case "int":
		c=BindingIntConstant(words[2],value);
		break;
	case "float":
		c=BindingFloatConstant(words[2],value);
		break;
	case "char*":
		c=BindingStringConstant(words[2],value);
		break;
	case "string":
		 c=BindingStringConstant(words[2],value+".c_str");
		break;
	default:
		if (classIndex[words[1]])
			c=BindingObjectConstant(words[1],words[2],value);
		else
			throw("Error: Class not defined\n");	
	}
	bindingConstants += ({ c });
}

BindingClass parse_class(array(string) words, int abstract)
{		
	BindingClass c,p=0;
				
	if (verbose)
		write("Parsing class "+words[1]+"\n");
	if (c=classIndex[words[1]]) {
		write("Notice: class "+words[1]+" already defined\n");
		return c;
	}
	if (sizeof(words)>2) {
		p=classIndex[words[2]];
		if (!p) {
			throw("Error: parent class not defined\n");
		}
	}
	c=BindingClass(words[1],p);
	c->abstract=abstract;
	bindingClasses += ({ c });
	classIndex[words[1]]=c;
	// classes are types
	bindingTypes += ([ words[1] : ObjectType(words[1]) ]);
	return c;
}

void parse_typedef(array(string) words)
{
	if (!bindingTypes[words[1]]) {
		BindingType t=bindingTypes[words[2]];
		if (t) 
			bindingTypes[words[1]]=t;
		else {				
			throw("Error: type not defined\n");
		}
	} else 
		write("Warning: type already defined\n");
}

array(Parameter) parse_parameters(string paramstr)
{
	if (paramstr=="") {
		if (verbose) write("\n");
		return ({ });
	}
	array(string) pstrings=paramstr / ",";
	string p;
	array(Parameter) params = ({ });
	string head,tail;
	
	foreach (pstrings, p) {
		Parameter param=Parameter();
		
		p=String.trim_all_whites(p);
		head="";
		tail="";
		if (sscanf(p,"%s %s",head,tail)>=2) {
			param->directive=head;
		} else
			tail= head==""? p : head;
			
		tail=String.trim_all_whites(tail);
		if (sscanf(tail,"%s=%s",head,tail)>=2) {
			param->defaultvalue=String.trim_all_whites(tail);
		} else
			head=tail;

		string pm=" "; pm[0]=head[-1];
		if (pm=="*" || pm=="&") {
			param->modifier=pm;
			head=head[0..sizeof(head)-2];
		}
		param->type=bindingTypes[head];
		if (!param->type) {
			throw(head+"\nerror: type not defined\n");
		}
		
		params += ({ param });
	}
	if (verbose) write((string)sizeof(params)+" parameters\n");
	return params;
}

void parse_function(array(string) words, string paramstr, BindingClass c)
{
	multiset(string) modifiers = (< >);
	
	while ( (< "extern", "virtual", "sideeffect", "extdep",
			"addrefthis","subrefthis","destroywrapped",
			"nodestroywrapped" >)[words[0]] ) {
		modifiers[words[0]]=1;
		words=words[1..];
	}
	
	int efun = (words[0]=="function");

	if (efun)
		words=words[1..];

	BindingType rt;
	string rm=" ";
	string fname, cppname;
	
	if (words[0]=="create") {// constructor=>create
		if (verbose)
			write("Parsing constructor "+words[0]+"...");
	
		rt=bindingTypes["void"];
		fname="create";
		words=words[1..];
	} else {
		rm[0]=words[0][-1]; // last char;
		if (rm!="*" && rm!="&")
			rm="";
		else 
			words[0]=words[0][0..sizeof(words[0])-2];
			
		rt=bindingTypes[words[0]];

		if (verbose)
			write("Parsing "+(efun ? "function " : "method ")+words[1]+"...");
		if (efun && modifiers["virtual"])
			write("Warning: function "+words[-1]+ "can't be virtual\n");

		array names=words[1] / "#";
		if (sizeof(names)==1)
			fname=cppname=names[0];
		else {
			cppname=names[0];
			fname=names[1];
		}
		
		if (!rt) {
			throw("error: type not defined\n");
		}
		words=words[2..];
	}

	array(BindingType) params = parse_parameters(paramstr);

	BindingFunction f;
	if (efun) {
		f=BindingFunction(fname, cppname, rt, rm,
			params, modifiers);
		bindingFunctions += ({ f });
	} else {
		if (fname=="create")
			f=BindingCreate(c->name, params, modifiers);
		else
			f=BindingMethod(c->name,fname, cppname,
				rt, rm, params, modifiers);
		c->virtual |= modifiers["virtual"]; // ored between all the funcs
		c->addFunction(f);
	}

}
void parse_input(string filename)
{
	Stdio.FILE file=Stdio.FILE(filename);
	string s, wordstr, paramstr;
	BindingClass c;
	int i;
	while (s=file->gets())
	{
		s=String.trim_all_whites(s);

		i++;
		if (sizeof(s)==0) continue;
		if (s[0..1]=="//") continue;
		
		wordstr="";
		paramstr="";

		if (sscanf(s,"%s(%s)",wordstr,paramstr)==0) {
			wordstr=s;
		}
		wordstr=String.trim_all_whites(wordstr);
		
		array(string) words = wordstr / " ";

		mixed error=catch {
			if (words[0]=="#include") 
				includes += ({ words[1] });
			else if (words[0]=="strip_prefix") 
				prefix=words[1];
			else if (words[0]=="const") 
				parse_const(words);
			else if (words[0]=="class") {
				c=parse_class(words,0);
			} else if (words[0]=="abstract" && words[1]=="class") {
				words=words[1..];
				c=parse_class(words,1);
			} else if (words[0]=="typedef") {
				parse_typedef(words);
			} else {
				parse_function(words,paramstr,c);
			}
		};
		if (error) {
			write((string)i+":"+s+"\n");
			write("Error!\n");
			write(sprintf("%O\n",error));
			exit(0);
		}
	}
	file->close();	
}

string generic_headers()
{
	return  
#"/* Generated automatically */
#undef __UNICODE__

/*
    Pike headers are C
*/

extern \"C\"  {
#include \"global.h\"
#include \"stralloc.h\"
#include \"error.h\"
#include \"pike_macros.h\"
#include \"object.h\"
#include \"constants.h\"
#include \"interpret.h\"
#include \"svalue.h\"
#include \"mapping.h\"
#include \"builtin_functions.h\"
#include \"module_support.h\"
#include \"operators.h\"
}

struct wrapper_storage {
\tvoid* cppobject;
\tbool foreign;
};

#define THIS ((struct wrapper_storage *)Pike_fp->current_storage)

#define STORAGE(OBJ,CLASS) ( (struct wrapper_storage*)get_storage(OBJ,CLASS##_program))

";
}

string class_headers()
{
	string s, inc;
	
	s = "";

	foreach(includes, inc)
		s+="#include "+inc+"\n";
	s += "\n";	
	return s;
}

string function_declarations()
{
	BindingFunction f;
	BindingClass c;
	
	string s;
	
	s = "/*\n"
	  + "    Functions that interface with Pike needs C interfaces\n"
	  + "*/\n"
	  + "extern \"C\" {\n";
	// efuns
	foreach(bindingFunctions, f) {
		s+=f->cppDeclaration();
		s+=";\n";
	}
	// class methods
	foreach(bindingClasses, c) {
		s+=c->cppDeclarations();
	}
	s += "void pike_module_init(void);\n";
	s += "void pike_module_exit(void);\n";
	s += "}\n\n";	
	return s;
}

// Returns all the storage struct declarations
string class_storage()
{
	BindingClass c;
	string s="";
	
	foreach(bindingClasses, c) {
		s+=c->storageDeclaration();
	}
	s+="\n";	
	return s;
}

string override_definitions()
{
	BindingClass c;
	string s="";
			
	// This macro is used to call virtual methods
	s+="#define push_method(method) { \\\n";
	s+="\tref_push_object(this->pike_object);\\\n";
	s+="\tpush_text(method);\\\n";
	s+="\tf_index(2); } \n\n";
	
	foreach(bindingClasses, c) {
		s+=c->bindingOverrideDefinitions();
	}
	
	s+="#undef push_method\n\n\n";
	return s;
}

// Returns all pointer to Pike programs definitions
string class_programs()
{
	BindingClass c;
	string s="";
	
	foreach(bindingClasses, c) {
		s+="struct program* "+c->name+"_program;\n";
	}
	s+="\n";
	return s;
}

// Returns all the C++ function (Pike efuns) definitions

string efun_functions()
{
	BindingFunction f;
	string s="";

	foreach(bindingFunctions, f) {
		s+=f->definition()+"\n\n";
	}	
	s+="\n";
	return s;
}

// Returns all the C++ function (Pike methods) definitions
string class_functions()
{
	BindingClass c;
	string s="";
	
	foreach(bindingClasses, c) {
		s+=c->functionsImplementation();
	}
	s+="\n";
	return s;
}

// Returns the main module function 
string main_function()
{
	BindingConstant con;
	BindingFunction f;
	BindingClass c;
	
	string s;
	s="void pike_module_init(void)\n";
	s+="{\n";

	foreach(bindingFunctions, f) {
		s+="\t"+f->pikeDeclaration()+"\n";
	}
	
	foreach(bindingClasses, c) {
		s+=c->pikeDeclarations();
	}
	// Constants are defined after classes, so object
	// constants can be created.
	foreach(bindingConstants, con)
	{
		s+=con->pikeDeclaration();
	} 
	s+="}\n\n";
	
	s+="void pike_module_exit(void)\n";
	s+="{\n";
	s+="}\n";
	return s;
}

int main(int argc, array(string) argv)
{
	if (argc<3) {
		write("Syntax: bindgen [-v] inputfile outputfile\n");
		return 1;
	}
	if (argv[1]=="-v") {
		verbose=1;
		argv=argv[0..0]+argv[2..];
		write("Verbose mode\n");
	}
	write("Parsing...\n");
	parse_input(argv[1]);

	write("Generating...\n");
	Stdio.File o=Stdio.File();
	
	if(!o->open(argv[2]+".h","wct"))
	{
		write("Failed to open file.\n");
		return 2;
	}
	o->write(generic_headers());
	o->write(class_headers());
	o->write(class_storage());
	o->close();
	
	if(!o->open(argv[2]+".cc","wct"))
	{
		write("Failed to open file.\n");
		return 2;
	}
	o->write("/* Generated automatically */\n\n");
	o->write("#include \""+argv[2]+".h\"\n\n");	
	
	o->write(function_declarations());
	o->write(class_programs());
	o->write(override_definitions());
	o->write(efun_functions());
	o->write(class_functions());
	o->write(main_function());

	o->close();
	write("Done.\n");

	return 0;
}

gotpike.org | Copyright © 2004 - 2011 | Pike is a trademark of Department of Computer and Information Science, Linköping University