From 0b11cd649a3811a8f9872f2749156b44fa7379fd Mon Sep 17 00:00:00 2001 From: Per Hedbor <ph@opera.com> Date: Tue, 30 Sep 2014 21:18:39 +0200 Subject: [PATCH] [precompiler] Use the correct types for classes and objects This includes programs in the cmod file and external programs. This makes the typechecker less odd, as an example the IOBuffer class functions that return an IOBuffer will not give warnings along the lines of "object of type IOBuffer can not be returned from a function returning object(IOBuffer=__Stdio()->IOBuffer)". You can also use any object type as arguments and return types, although you still have to use object(X.Y) in most places due to the parser. --- .../Standalone.pmod/precompile.pike | 172 ++++++++++++++---- 1 file changed, 140 insertions(+), 32 deletions(-) diff --git a/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike b/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike index f234d18b5e..c5ef827c68 100644 --- a/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike +++ b/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike @@ -19,10 +19,13 @@ constant precompile_api_version = "3"; constant want_args = 1; constant description = "Converts .pmod-files to .c files"; + +mapping map_types = ([]), need_obj_defines = ([]); + string usage = #"[options] <from> > <to> - This script is used to process *.cmod files into *.c files, it + This script is used to process *.cmod files into *.c files, it reads Pike style prototypes and converts them into C code. Supported options are: @@ -827,8 +830,12 @@ class PikeType case "longest": return "tInt"; - case "object": return "tObj"; + case "object": + return "tObj"; default: + string define = "tObjImpl_"+replace(upper_case(ret), ".", "_"); + if( !need_obj_defines[define] ) + need_obj_defines[define] = ret; return sprintf("tName(%O, tObjImpl_%s)", ret, replace(upper_case(ret), ".", "_")); } @@ -1682,6 +1689,8 @@ array generate_overload_func_for(array(FuncData) d, return out; } +int gid; + // Parses a block of cmod code, separating it into declarations, // functions to add, exit functions and other code. class ParseBlock @@ -1690,6 +1699,7 @@ class ParseBlock array addfuncs=({}); array exitfuncs=({}); array declarations=({}); + int local_id = ++gid; void create(array(array|PC.Token) x, string base, string class_name) { @@ -1881,6 +1891,9 @@ sprintf(" } else {\n" ret+=subclass->declarations; ret+=subclass->code; + need_obj_defines["tObjImpl_"+upper_case(lname)] = 1; + map_types[subclass->local_id] = ({ define, "return "+program_var+"->id;" }); + addfuncs+= IFDEF(define, ({ @@ -1898,7 +1911,10 @@ sprintf(" } else {\n" proto[0]->line), IFDEF("tObjImpl_"+upper_case(lname), 0, - DEFINE("tObjImpl_"+upper_case(lname), "tObj")), + DEFINE("tObjIs_"+upper_case(lname), + sprintf("%O",sprintf("\3\1\x7f%3c", subclass->local_id)))+ + DEFINE("tObjImpl_"+upper_case(lname), + sprintf("%O",sprintf("\3\0\x7f%3c", subclass->local_id)))), })+ subclass->addfuncs+ ({ @@ -2415,7 +2431,7 @@ static struct %s *%s_gdb_dummy_ptr; ret+=({ PC.Token(sprintf("if (args > %d &&" " (TYPEOF(Pike_sp[%d%s]) != PIKE_T_INT ||" - " Pike_sp[%d%s].u.integer)) {\n", + " Pike_sp[%d%s].u.integer)) {\n", argnum, argnum, check_argbase, argnum, check_argbase), arg->line()), @@ -2711,7 +2727,8 @@ static struct %s *%s_gdb_dummy_ptr; })); } else { addfuncs+=IFDEF(define, ({ - PC.Token(sprintf(" %s =\n", func_num)), + IFDEF(func_num+"_used", + ({PC.Token(sprintf(" %s =", func_num))})), PC.Token(sprintf(" ADD_FUNCTION2(%O, %s, %s, %s, %s);\n", attributes->name || name, funcname, @@ -2792,27 +2809,65 @@ class Handler { void create(mapping|void predefines) { ::create(); - if (predefines) this::predefines = predefines; + if (predefines) this_program::predefines = predefines; } } int find_identifier( array in, string ident ) { - foreach( in, mixed q ) + foreach( in, mixed q ) + { + if( objectp(q) ) { - if( objectp(q) ) - { - if( q == ident ) return 1; - } - else if( arrayp( q ) ) - { - if( find_identifier( q, ident ) ) - return 1; - } - else - /* generated by us, not useful currentrly. */ - ; + if( q == ident ) { + return 1; + } + } + else if( arrayp( q ) ) + { + if( find_identifier( q, ident ) ) + return 1; + } + } +} + +array resolve_obj_defines() +{ + array res = ({}); + + foreach( need_obj_defines; string key; int|string id ) + { + if( intp( id ) ) + { + m_delete( need_obj_defines, key ); + continue; /* type in this file. Not external. */ } + } + if( sizeof( need_obj_defines ) ) + { + res += ({ "{ int i=0;\n"}); + res += ({ " ___cmod_ext_used=xalloc(sizeof(___cmod_ext_used[0]) * "+(sizeof(need_obj_defines)||1)+");\n" }); + foreach( need_obj_defines; string key; string id ) + { + int local_id = ++gid; + res += ({ + sprintf("#ifndef %s\n" + "# define %[0]s %s\n" + "{\n" + " struct program *tmp = resolve_program(" + allocate_string(sprintf("%O",id)) + ");\n" + " if( tmp ) {\n" + " ___cmod_ext_used[i].from = %d;\n" + " ___cmod_ext_used[i].to = tmp->id;\n" + " i++;\n" + " }\n" + "}\n" + "#endif\n" + ,key,sprintf("%O",sprintf("\3\0\x7f%3c", local_id)),local_id) + }); + } + res += ({ " ___cmod_ext_used[i].from = 0;\n}\n"}); + } + return res; } int main(int argc, array(string) argv) @@ -2979,7 +3034,10 @@ int main(int argc, array(string) argv) tmp->declarations += ({ "\n\n" + "#define CMOD_MAP_PROGRAM_IDS_DEFINED 1\n" + "static int ___cmod_map_program_ids(int id);\n" "#ifndef TYPEOF\n" + "static void set_program_id_to_id(void*UNUSED(id)){}\n" "/* Compat with older Pikes. */\n" "#define TYPEOF(SVAL)\t((SVAL).type)\n" "#define SUBTYPEOF(SVAL)\t((SVAL).subtype)\n" @@ -2992,15 +3050,26 @@ int main(int argc, array(string) argv) " SET_SVAL_TYPE((SVAL), (TYPE));\t\t\t\\\n" " SET_SVAL_SUBTYPE((SVAL), (SUBTYPE));\t\t\\\n" " } while(0)\n" + "#else /* */\n" + "PMOD_EXPORT void set_program_id_to_id( int (*to)(int) );\n" "#endif /* !TYPEOF */\n" "\n\n", - // FIXME: Ought to default to static in 7.9. + "#ifndef DEFAULT_CMOD_STORAGE\n" "#define CMOD_COND_USED\n" "#define DEFAULT_CMOD_STORAGE static\n" "#endif\n" }); + + tmp->addfuncs = + IFDEF("CMOD_MAP_PROGRAM_IDS_DEFINED", + ({"set_program_id_to_id( ___cmod_map_program_ids );"})) + + resolve_obj_defines() + + tmp->addfuncs + + IFDEF("CMOD_MAP_PROGRAM_IDS_DEFINED", + ({"set_program_id_to_id( 0 );"})); + if (last_str_id) { // Add code for allocation and deallocation of the strings. tmp->addfuncs = @@ -3044,22 +3113,47 @@ int main(int argc, array(string) argv) } } - x=tmp->code; + x = tmp->code; - foreach( check_used; string key; ) + x +=({ + "\n" + "#ifdef CMOD_MAP_PROGRAM_IDS_DEFINED\n" + "static int ___cmod_map_program_ids(int id)\n" + "{\n" + " int i = 0;\n" + " if( (id&0x7f000000) != 0x7f000000 ) return id;\n" + " id = id&0x00ffffff;\n" + }); + + foreach( map_types; int i; string how ) { - tmp->declarations += ({ - "#ifndef CMOD_COND_USED\n" - "# define "+key+"_used 1\n" - "#else\n" - }); - if( find_identifier( x, key ) ) - tmp->declarations +=({ "#define "+key+"_used 1\n" }); - else - tmp->declarations += ({ "#undef "+key+"_used\n" }); - tmp->declarations += ({ "#endif\n" }); + if( how[0] ) + x += ({ "#ifdef "+how[0]+"\n" }); + x += ({ "if(id=="+i+") "+how[1]+"\n" }); + if( how[0] ) + x += ({ "#endif\n" }); } + if( sizeof( need_obj_defines ) ) + { + tmp->declarations += ({ + "static struct ext_used { INT32 from;INT32 to; } *___cmod_ext_used;\n" + }); + + x += ({ + " while(___cmod_ext_used[i].from ) {\n" + " if( ___cmod_ext_used[i].from == id ) return ___cmod_ext_used[i].to;\n" + " i++;\n" + " }\n" + }); + } + x += ({ + " return 0;\n" + "}\n" + "#endif /* CMOD_MAP_PROGRAM_IDS_DEFINED */\n" + }); + + tmp->code = x; x=recursive(replace,x,PC.Token("INIT",0),tmp->addfuncs); int need_init; if ((need_init = equal(x, tmp->code))) @@ -3095,6 +3189,20 @@ int main(int argc, array(string) argv) // FIXME: This line is fishy; there is no optfuncs in ParseBlock. x=recursive(replace,x,PC.Token("OPTIMIZE",0),tmp->optfuncs); + foreach( check_used; string key; ) + { + tmp->declarations += ({ + "#ifndef CMOD_COND_USED\n" + "# define "+key+"_used 1\n" + "#else\n" + }); + if( find_identifier( x, key ) ) + tmp->declarations +=({ "#define "+key+"_used 1\n" }); + else + tmp->declarations += ({ "#undef "+key+"_used\n" }); + tmp->declarations += ({ "#endif\n" }); + } + tmp->code = x; x=recursive(replace,x,PC.Token("DECLARATIONS",0),tmp->declarations); -- GitLab