diff --git a/bin/precompile.pike b/bin/precompile.pike index e1db4fa44983a97a7ab0a99f0e2018ca1a7d8628..a198cbbd88f6408e19d0a3dee7b217d73355ffbd 100644 --- a/bin/precompile.pike +++ b/bin/precompile.pike @@ -10,11 +10,11 @@ * attributes; * { * - * PIKEFUNC int function_name (int x) + * PIKEFUNC int function_name (int x, CTYPE char * foo) * attribute; * attribute value; * { - * C code using 'x'. + * C code using 'x' and 'foo'. * * RETURN x; * } @@ -145,14 +145,52 @@ string uname(mixed type) } } +array convert_ctype(array tokens) +{ + switch((string)tokens[0]) + { + case "char": /* char* */ + if(sizeof(tokens) >1 && "*" == (string)tokens[1]) + return ({ PC.Token("string") }); + + case "short": + case "int": + case "long": + case "size_t": + case "ptrdiff_t": + case "INT32": + return ({ PC.Token("int") }); + + case "double": + case "float": + return ({ PC.Token("float") }); + + default: + werror("Unknown C type.\n"); + exit(0); + } +} + mapping(string:string) parse_arg(array x) { mapping ret=(["name":x[-1]]); ret->type=x[..sizeof(x)-2]; ret->basetype=x[0]; - if(sizeof(ret->type/({"|"}))>1) - ret->basetype="mixed"; - ret->ctype=cname(ret->basetype); + if(ret->basetype == PC.Token("CTYPE")) + { + ret->cname = merge(ret->type[1..]); + ret->type = convert_ctype(ret->type[1..]); + ret->is_c_type=1; + }else{ + array ored_types=ret->type/({"|"}); + if(sizeof(ored_types)>1) + ret->basetype="mixed"; + + if(search(ored_types,PC.Token("void"))!=-1) + ret->optional=1; + + ret->ctype=cname(ret->type); + } ret->typename=trim(merge(recursive(strip_type_assignments,ret->type))); ret->line=ret->name->line; return ret; @@ -190,13 +228,28 @@ string convert_type(array s) convert_type((tmp/({":"}))[0])+","+ convert_type((tmp/({":"}))[1])+")"; } - case "object": + case "object": /* FIXME: support object is/implements */ return "tObj"; case "program": return "tProgram"; case "function": - return "tFunc"; + { + if(sizeof(s)<2) return "tFunction"; + array args=s[1][1..sizeof(s[1])-2]; + [ args, array ret ] = args / PC.Token(":"); + if(args[-1]=="...") + { + return sprintf("tFunc(%s,%s)", + map(convert_type,args)*" ", + convert_type(ret)); + }else{ + return sprintf("tFuncV(%s,,%s)", + map(convert_type,args[..sizeof(args)-2])*" ", + convert_type(args[-1]), + convert_type(ret)); + } + } case "mixed": return "tMix"; @@ -452,7 +505,6 @@ array convert(array x, string base) args=args[1..sizeof(args)-2]/({","}); // werror("FIX RETURN: %O\n",body); - body=recursive(fix_return,body, rettype[0], cname(rettype), sizeof(args)); // werror("name=%s\n",name); // werror(" rettype=%O\n",rettype); @@ -465,6 +517,11 @@ array convert(array x, string base) }); args=map(args,parse_arg); + int min_args=sizeof(args); + int max_args=sizeof(args); /* FIXME: check for ... */ + + while(min_args>0 && args[min_args-1]->optional) + min_args--; foreach(args, mapping arg) ret+=({ @@ -505,35 +562,81 @@ array convert(array x, string base) int argnum; argnum=0; - ret+=({ - PC.Token(sprintf("if(args != %d) wrong_number_of_args_error(%O,args,%d);\n", - sizeof(args), - name, - sizeof(args)), proto[0]->line) - }); + string argbase; + string num_arguments; + if(min_args == max_args) + { + ret+=({ + PC.Token(sprintf("if(args != %d) wrong_number_of_args_error(%O,args,%d);\n", + sizeof(args), + name, + sizeof(args)), proto[0]->line) + }); + argbase=(string) (-sizeof(args)); + num_arguments=(string)sizeof(args); + }else{ + argbase="-args"; + num_arguments="args"; + if(min_args > 0) { + ret+=({ + PC.Token(sprintf("if(args < %d) wrong_number_of_args_error(%O,args,%d);\n", + min_args, + name, + min_args), proto[0]->line) + }); + } + + if(max_args != -1) { + ret+=({ + PC.Token(sprintf("if(args > %d) wrong_number_of_args_error(%O,args,%d);\n", + max_args, + name, + max_args), proto[0]->line) + }); + } + } - int sp=-sizeof(args); foreach(args, mapping arg) { + if(arg->optional && "mixed" != (string)arg->basetype) + { + ret+=({ + PC.Token(sprintf("if(args >= %s) ",argnum)), + }); + } + if(arg->is_c_type && arg->basetype == "string") + { + /* Special case for 'char *' */ + /* This will have to be amended when we want to support + * wide strings + */ + ret+=({ + PC.Token(sprintf("if(sp[%d%s].type != PIKE_T_STRING || sp[%d%s].ustring -> width)", + argnum,argbase, + argnum,argbase, + upper_case(arg->basetype->text)),arg->line) + }); + }else + switch((string)arg->basetype) { default: ret+=({ - PC.Token(sprintf("if(Pike_sp[%d].type != PIKE_T_%s)", - sp,upper_case(arg->basetype->text)),arg->line) + PC.Token(sprintf("if(Pike_sp[%d%s].type != PIKE_T_%s)", + argnum,argbase, + upper_case(arg->basetype->text)),arg->line) }); break; case "program": ret+=({ - PC.Token(sprintf("if(!( %s=program_from_svalue(sp%+d)))", - arg->name,sp),arg->line) + PC.Token(sprintf("if(!( %s=program_from_svalue(sp%+d%s)))", + arg->name,argnum,argbase),arg->line) }); break; case "mixed": } - switch((string)arg->basetype) { default: @@ -547,45 +650,75 @@ array convert(array x, string base) case "mixed": } + if(arg->optional) + { + ret+=({ + PC.Token(sprintf("if(args >= %s) { ",argnum)), + }); + } + switch(objectp(arg->basetype) ? arg->basetype->text : arg->basetype ) { case "int": ret+=({ - sprintf("%s=Pike_sp[%d].u.integer;\n",arg->name,sp) + sprintf("%s=Pike_sp[%d%s].u.integer;\n",arg->name,argnum,argbase) }); break; case "float": ret+=({ - sprintf("%s=Pike_sp[%d].u.float_number;\n", + sprintf("%s=Pike_sp[%d%s].u.float_number;\n", arg->name, - sp) + argnum,argbase) }); break; case "mixed": ret+=({ - PC.Token(sprintf("%s=sp%+d; dmalloc_touch_svalue(sp%+d);\n", + PC.Token(sprintf("%s=sp%+d%s; dmalloc_touch_svalue(sp%+d%s);\n", arg->name, - sp,sp),arg->line), + argnum,argbase,argnum,argbase),arg->line), }); break; default: - ret+=({ - PC.Token(sprintf("debug_malloc_pass(%s=Pike_sp[%d].u.%s);\n", - arg->name, - sp, - arg->basetype),arg->line) - }); + if(arg->is_c_type && arg->basetype == "string") + { + /* some sort of 'char *' */ + /* This will have to be amended when we want to support + * wide strings + */ + ret+=({ + PC.Token(sprintf("%s=Pike_sp[%d%s].u.string->str; debug_malloc_touch(Pike_sp[%d%s].u.string)\n", + arg->name, + argnum,argbase, + argnum,argbase),arg->line) + }); + + }else{ + ret+=({ + PC.Token(sprintf("debug_malloc_pass(%s=sp[%d%s].u.%s);\n", + arg->name, + argnum,argbase, + arg->basetype),arg->line) + }); + } case "program": } + + if(arg->optional) + { + ret+=({ + PC.Token(sprintf("}",argnum)), + }); + } + argnum++; - sp++; } + body=recursive(fix_return,body, rettype[0], cname(rettype), num_arguments); if(sizeof(body)) ret+=({body}); ret+=({ "}\n" });