rubidium@9820: # $Id$ rubidium@9526: # rubidium@9526: # Awk script to automatically generate the code needed rubidium@9526: # to export the AI API to Squirrel. rubidium@9526: # rubidium@9526: # Note that arrays are 1 based... rubidium@9526: # rubidium@9526: rubidium@9526: # Simple insertion sort. rubidium@9526: function array_sort(ARRAY, ELEMENTS, temp, i, j) { rubidium@9526: for (i = 2; i <= ELEMENTS; i++) rubidium@9526: for (j = i; ARRAY[j - 1] > ARRAY[j]; --j) { rubidium@9526: temp = ARRAY[j] rubidium@9526: ARRAY[j] = ARRAY[j - 1] rubidium@9526: ARRAY[j - 1] = temp rubidium@9526: } rubidium@9526: return rubidium@9526: } rubidium@9526: rubidium@9594: function dump_class_templates(name) { rubidium@9594: print " template <> " name " *GetParam(ForceType<" name " *>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (" name " *)instance; }" rubidium@9594: print " template <> " name " &GetParam(ForceType<" name " &>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(" name " *)instance; }" rubidium@9594: print " template <> const " name " *GetParam(ForceType, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (" name " *)instance; }" rubidium@9594: print " template <> const " name " &GetParam(ForceType, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(" name " *)instance; }" truelight@9680: print " template <> int Return<" name " *>(HSQUIRRELVM vm, " name " *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, \"" name "\", res, NULL, DefSQDestructorCallback<" name ">); return 1; }" rubidium@9594: } rubidium@9594: rubidium@9526: BEGIN { rubidium@9526: enum_size = 0 rubidium@9532: enum_value_size = 0 rubidium@9861: enum_string_to_error_size = 0 rubidium@9861: enum_error_to_string_size = 0 rubidium@9526: struct_size = 0 rubidium@9526: method_size = 0 rubidium@9532: static_method_size = 0 rubidium@9572: virtual_class = "false" rubidium@9594: super_cls = "" rubidium@9526: cls = "" rubidium@9526: start_squirrel_define_on_next_line = "false" rubidium@9526: cls_level = 0 rubidium@9526: } rubidium@9526: rubidium@9596: /@file/ { rubidium@9596: print "#include \"" $3 "\"" rubidium@9596: } rubidium@9596: rubidium@9526: # Remove the old squirrel stuff rubidium@9526: /#ifdef DEFINE_SQUIRREL_CLASS/ { squirrel_stuff = "true"; next; } rubidium@9526: /^#endif \/\* DEFINE_SQUIRREL_CLASS \*\// { if (squirrel_stuff == "true") { squirrel_stuff = "false"; next; } } rubidium@9526: { if (squirrel_stuff == "true") next; } rubidium@9526: truelight@9587: # Ignore forward declarations of classes truelight@9587: /^( *)class(.*);/ { next; } rubidium@9526: # We only want to have public functions exported for now rubidium@9567: /^( *)class/ { rubidium@9567: if (cls_level == 0) { rubidium@9567: public = "false" truelight@9610: cls_param[0] = "" truelight@9610: cls_param[1] = 1 truelight@9610: cls_param[2] = "x" rubidium@9567: cls = $2 rubidium@9594: if (match($4, "public") || match($4, "protected") || match($4, "private")) { rubidium@9594: super_cls = $5 rubidium@9594: } else { rubidium@9594: super_cls = $4 rubidium@9594: } rubidium@9567: } else if (cls_level == 1) { rubidium@9567: struct_size++ rubidium@9567: structs[struct_size] = cls "::" $2 rubidium@9567: } rubidium@9567: cls_level++ rubidium@9567: next rubidium@9567: } rubidium@9526: /^( *)public/ { if (cls_level == 1) public = "true"; next; } rubidium@9526: /^( *)protected/ { if (cls_level == 1) public = "false"; next; } rubidium@9526: /^( *)private/ { if (cls_level == 1) public = "false"; next; } rubidium@9526: rubidium@9526: # Ignore the comments rubidium@9526: /^#/ { next; } rubidium@9526: /\/\*.*\*\// { comment = "false"; next; } rubidium@9526: /\/\*/ { comment = "true"; next; } rubidium@9526: /\*\// { comment = "false"; next; } rubidium@9526: { if (comment == "true") next } rubidium@9526: rubidium@9526: # We need to make specialized conversions for structs rubidium@9527: /^( *)struct/ { rubidium@9527: cls_level++ rubidium@9567: if (public == "false") next rubidium@9567: if (cls_level != 1) next rubidium@9567: struct_size++ rubidium@9567: structs[struct_size] = cls "::" $2 rubidium@9527: next rubidium@9527: } rubidium@9526: rubidium@9526: # We need to make specialized conversions for enums rubidium@9526: /^( *)enum/ { rubidium@9526: cls_level++ rubidium@9526: if (public == "false") next; rubidium@9526: in_enum = "true" rubidium@9526: enum_size++ rubidium@9526: enums[enum_size] = cls "::" $2 rubidium@9526: next rubidium@9526: } rubidium@9526: rubidium@9526: # Maybe the end of the class, if so we can start with the Squirrel export pretty soon rubidium@9526: /};/ { rubidium@9526: cls_level-- rubidium@9526: if (cls_level != 0) { rubidium@9526: in_enum = "false"; rubidium@9526: next; rubidium@9526: } rubidium@9526: if (cls == "") { rubidium@9526: next; rubidium@9526: } rubidium@9526: start_squirrel_define_on_next_line = "true" rubidium@9526: next; rubidium@9526: } rubidium@9526: rubidium@9526: # Empty/white lines. When we may do the Squirrel export, do that export. rubidium@9526: /^([ ]*)$/ { rubidium@9526: if (start_squirrel_define_on_next_line == "false") next rubidium@9526: spaces = " "; rubidium@9526: public = "false" rubidium@9526: namespace_opened = "false" rubidium@9526: rubidium@9596: print "" rubidium@9596: rubidium@9526: # First check whether we have enums to print rubidium@9526: if (enum_size != 0) { rubidium@9526: if (namespace_opened == "false") { rubidium@9526: print "namespace SQConvert {" rubidium@9526: namespace_opened = "true" rubidium@9526: } rubidium@9526: print " /* Allow enums to be used as Squirrel parameters */" rubidium@9526: for (i = 1; i <= enum_size; i++) { rubidium@9526: print " template <> " enums[i] " GetParam(ForceType<" enums[i] ">, HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (" enums[i] ")tmp; }" rubidium@9526: print " template <> int Return<" enums[i] ">(HSQUIRRELVM vm, " enums[i] " res) { sq_pushinteger(vm, (int32)res); return 1; }" rubidium@9526: delete enums[i] rubidium@9526: } rubidium@9526: } rubidium@9526: rubidium@9567: # Then check whether we have structs/classes to print rubidium@9567: if (struct_size != 0) { rubidium@9567: if (namespace_opened == "false") { rubidium@9567: print "namespace SQConvert {" rubidium@9567: namespace_opened = "true" rubidium@9567: } rubidium@9567: print " /* Allow inner classes/structs to be used as Squirrel parameters */" rubidium@9567: for (i = 1; i <= struct_size; i++) { rubidium@9594: dump_class_templates(structs[i]) rubidium@9567: delete structs[i] rubidium@9567: } rubidium@9567: } rubidium@9567: rubidium@9526: if (namespace_opened == "false") { rubidium@9526: print "namespace SQConvert {" rubidium@9526: namespace_opened = "true" rubidium@9526: } else { rubidium@9526: print "" rubidium@9526: } rubidium@9526: print " /* Allow " cls " to be used as Squirrel parameter */" rubidium@9594: dump_class_templates(cls) rubidium@9526: rubidium@9526: print "}; // namespace SQConvert" rubidium@9526: rubidium@9653: print ""; rubidium@9653: # Then do the registration functions of the class. */ truebrain@9741: print "void SQ" cls "_Register(Squirrel *engine) {" rubidium@9653: print " DefSQClass <" cls "> SQ" cls "(\"" cls "\");" rubidium@9653: if (super_cls == "AIObject" || super_cls == "AIAbstractList::Valuator") { rubidium@9653: print " SQ" cls ".PreRegister(engine);" rubidium@9653: } else { rubidium@9653: print " SQ" cls ".PreRegister(engine, \"" super_cls "\");" rubidium@9653: } rubidium@9572: if (virtual_class == "false") { truelight@9635: print " SQ" cls ".AddConstructor(engine, \"" cls_param[2] "\");" rubidium@9653: } rubidium@9653: print "" rubidium@9526: rubidium@9653: # Enum values rubidium@9653: mlen = 0 rubidium@9653: for (i = 1; i <= enum_value_size; i++) { rubidium@9653: if (mlen <= length(enum_value[i])) mlen = length(enum_value[i]) rubidium@9653: } rubidium@9653: for (i = 1; i <= enum_value_size; i++) { rubidium@9653: print " SQ" cls ".DefSQConst(engine, " cls "::" enum_value[i] ", " substr(spaces, 1, mlen - length(enum_value[i])) "\"" enum_value[i] "\");" rubidium@9653: delete enum_value[i] rubidium@9653: } rubidium@9653: if (enum_value_size != 0) print "" rubidium@9572: rubidium@9861: # Mapping of OTTD strings to errors truebrain@9844: mlen = 0 rubidium@9861: for (i = 1; i <= enum_string_to_error_size; i++) { rubidium@9861: if (mlen <= length(enum_string_to_error_mapping_string[i])) mlen = length(enum_string_to_error_mapping_string[i]) truebrain@9844: } rubidium@9861: for (i = 1; i <= enum_string_to_error_size; i++) { rubidium@9861: print " AIError::RegisterErrorMap(" enum_string_to_error_mapping_string[i] ", " substr(spaces, 1, mlen - length(enum_string_to_error_mapping_string[i])) cls "::" enum_string_to_error_mapping_error[i] ");" truebrain@9844: rubidium@9861: delete enum_string_to_error_mapping_string[i] truebrain@9844: } rubidium@9861: if (enum_string_to_error_size != 0) print "" rubidium@9861: rubidium@9861: # Mapping of errors to human 'readable' strings. rubidium@9861: mlen = 0 rubidium@9861: for (i = 1; i <= enum_error_to_string_size; i++) { rubidium@9861: if (mlen <= length(enum_error_to_string_mapping[i])) mlen = length(enum_error_to_string_mapping[i]) rubidium@9861: } rubidium@9861: for (i = 1; i <= enum_error_to_string_size; i++) { rubidium@9861: print " AIError::RegisterErrorMapString(" cls "::" enum_error_to_string_mapping[i] ", " substr(spaces, 1, mlen - length(enum_error_to_string_mapping[i])) "\"" enum_error_to_string_mapping[i] "\");" rubidium@9861: delete enum_error_to_string_mapping[i] rubidium@9861: } rubidium@9861: if (enum_error_to_string_size != 0) print "" truebrain@9844: rubidium@9653: # Static methods rubidium@9653: mlen = 0 rubidium@9653: for (i = 1; i <= static_method_size; i++) { rubidium@9653: if (mlen <= length(static_methods[i, 0])) mlen = length(static_methods[i, 0]) rubidium@9653: } rubidium@9653: for (i = 1; i <= static_method_size; i++) { rubidium@9653: print " SQ" cls ".DefSQStaticMethod(engine, &" cls "::" static_methods[i, 0] ", " substr(spaces, 1, mlen - length(static_methods[i, 0])) "\"" static_methods[i, 0] "\", " substr(spaces, 1, mlen - length(static_methods[i, 0])) "" static_methods[i, 1] ", \"" static_methods[i, 2] "\");" rubidium@9653: delete static_methods[i] rubidium@9653: } rubidium@9653: if (static_method_size != 0) print "" rubidium@9572: rubidium@9653: if (virtual_class == "false") { rubidium@9572: # Non-static methods rubidium@9572: mlen = 0 rubidium@9572: for (i = 1; i <= method_size; i++) { rubidium@9572: if (mlen <= length(methods[i, 0])) mlen = length(methods[i, 0]) rubidium@9572: } rubidium@9572: for (i = 1; i <= method_size; i++) { truebrain@9814: if (methods[i, 2] == "v") { truebrain@9814: print " SQ" cls ".DefSQAdvancedMethod(engine, &" cls "::" methods[i, 0] ", " substr(spaces, 1, mlen - length(methods[i, 0]) - 8) "\"" methods[i, 0] "\");" truebrain@9814: } else { truebrain@9814: print " SQ" cls ".DefSQMethod(engine, &" cls "::" methods[i, 0] ", " substr(spaces, 1, mlen - length(methods[i, 0])) "\"" methods[i, 0] "\", " substr(spaces, 1, mlen - length(methods[i, 0])) "" methods[i, 1] ", \"" methods[i, 2] "\");" truebrain@9814: } rubidium@9572: delete methods[i] rubidium@9572: } rubidium@9572: if (method_size != 0) print "" rubidium@9532: } rubidium@9653: print " SQ" cls ".PostRegister(engine);" rubidium@9653: print "}" rubidium@9526: rubidium@9532: enum_size = 0 rubidium@9532: enum_value_size = 0 rubidium@9861: enum_string_to_error_size = 0 rubidium@9861: enum_error_to_string_size = 0 rubidium@9532: struct_size = 0 rubidium@9532: method_size = 0 rubidium@9532: static_method_size = 0 rubidium@9572: virtual_class = "false" rubidium@9526: cls = "" rubidium@9526: start_squirrel_define_on_next_line = "false" rubidium@9532: cls_level = 0 rubidium@9526: } rubidium@9526: rubidium@9526: # Skip non-public functions rubidium@9526: { if (public == "false") next } rubidium@9526: rubidium@9526: # Add enums rubidium@9526: { rubidium@9526: if (in_enum == "true") { rubidium@9526: enum_value_size++ truelight@9681: sub(",", "", $1) rubidium@9526: enum_value[enum_value_size] = $1 truebrain@9844: truebrain@9844: # Check if this a special error enum truebrain@9844: if (match(enums[enum_size], ".*::ErrorMessages") != 0) { truebrain@9844: # syntax: truebrain@9844: # enum ErrorMessages { truebrain@9844: # ERR_SOME_ERROR, // [STR_ITEM1, STR_ITEM2, ...] truebrain@9844: # } truebrain@9844: truebrain@9844: # Set the mappings rubidium@9861: if (match($0, "\\[.*\\]") != 0) { truebrain@9844: mappings = substr($0, RSTART, RLENGTH); truebrain@9844: gsub("([\\[[:space:]\\]])", "", mappings); truebrain@9844: truebrain@9844: split(mappings, mapitems, ","); truebrain@9844: for (i = 1; i <= length(mapitems); i++) { rubidium@9861: enum_string_to_error_size++ rubidium@9861: enum_string_to_error_mapping_string[enum_string_to_error_size] = mapitems[i] rubidium@9861: enum_string_to_error_mapping_error[enum_string_to_error_size] = $1 truebrain@9844: } truebrain@9844: rubidium@9861: enum_error_to_string_size++ rubidium@9861: enum_error_to_string_mapping[enum_error_to_string_size] = $1 truebrain@9844: } truebrain@9844: } rubidium@9526: next rubidium@9526: } rubidium@9526: } rubidium@9526: rubidium@9526: # Add a method to the list truelight@9587: /^.*\(.*\).*$/ { rubidium@9526: if (cls_level != 1) next rubidium@9653: if (match($0, "~")) next rubidium@9532: rubidium@9532: is_static = match($0, "static") rubidium@9572: if (match($0, "virtual")) { rubidium@9572: virtual_class = "true" rubidium@9572: } rubidium@9526: gsub("virtual", "", $0) rubidium@9526: gsub("static", "", $0) rubidium@9532: gsub("const", "", $0) rubidium@9828: gsub("{.*", "", $0) rubidium@9541: param_s = $0 rubidium@9533: gsub("\\*", "", $0) rubidium@9533: gsub("\\(.*", "", $0) rubidium@9541: rubidium@9541: sub(".*\\(", "", param_s) rubidium@9541: sub("\\).*", "", param_s) rubidium@9541: truelight@9609: funcname = $2 truelight@9677: if ($1 == cls && funcname == "") { truelight@9610: cls_param[0] = param_s truelight@9610: if (param_s == "") next truelight@9610: } else if (funcname == "") next truelight@9609: rubidium@9541: split(param_s, params, ",") rubidium@9541: types = "x" rubidium@9541: for (len = 1; params[len] != ""; len++) { rubidium@9541: sub("^[ ]*", "", params[len]) rubidium@9594: if (match(params[len], "\\*") || match(params[len], "&")) { rubidium@9541: if (match(params[len], "^char")) { rubidium@9541: types = types "s" truelight@9651: } else if (match(params[len], "^void")) { truelight@9651: types = types "p" rubidium@9541: } else { truelight@9583: types = types "x" rubidium@9541: } rubidium@9541: } else if (match(params[len], "^bool")) { rubidium@9541: types = types "b" truebrain@9814: } else if (match(params[len], "^HSQUIRRELVM")) { truebrain@9814: types = "v" rubidium@9541: } else { rubidium@9541: types = types "i" rubidium@9541: } rubidium@9541: } rubidium@9541: truelight@9677: if ($1 == cls && funcname == "") { truelight@9610: cls_param[1] = len; truelight@9610: cls_param[2] = types; truelight@9610: } else if (is_static) { rubidium@9532: static_method_size++ truelight@9542: static_methods[static_method_size, 0] = funcname rubidium@9541: static_methods[static_method_size, 1] = len rubidium@9541: static_methods[static_method_size, 2] = types rubidium@9532: } else { rubidium@9532: method_size++ truelight@9542: methods[method_size, 0] = funcname rubidium@9541: methods[method_size, 1] = len rubidium@9541: methods[method_size, 2] = types rubidium@9532: } rubidium@9526: next rubidium@9526: }