diff --git a/GenC.fu b/GenC.fu index bb9b7cae..a3906d9a 100644 --- a/GenC.fu +++ b/GenC.fu @@ -2001,6 +2001,7 @@ public class GenC : GenCCpp WriteEnumHasFlag(obj, args, parent); break; case FuId.IntTryParse: + Include("limits.h"); this.IntFunctions.Add(FuId.IntTryParse); Write("FuInt"); WriteTryParse(obj, args); @@ -3488,7 +3489,7 @@ public class GenC : GenCCpp this.CurrentMethod = null; } - void WriteIntMaxMin!(string klassName, string method, string type, int op) + void StartLibraryMethod!(string type, string klassName, string method, string paramType) { WriteNewLine(); Write("static "); @@ -3498,7 +3499,12 @@ public class GenC : GenCCpp WriteChar('_'); Write(method); WriteChar('('); - Write(type); + Write(paramType); + } + + void WriteIntMaxMin!(string klassName, string method, string type, int op) + { + StartLibraryMethod(type, klassName, method, type); Write(" x, "); Write(type); WriteLine(" y)"); @@ -3509,21 +3515,17 @@ public class GenC : GenCCpp CloseBlock(); } - void WriteTryParseLibrary!(string signature, string call) + void StartTryParseLibrary!(string klassName, string type, string baseParam) { - WriteNewLine(); - Write("static bool Fu"); - WriteLine(signature); + StartLibraryMethod("bool", klassName, "TryParse", type); + Write(" *result, const char *str"); + Write(baseParam); + WriteCharLine(')'); OpenBlock(); WriteLine("if (*str == '\\0')"); WriteLine("\treturn false;"); WriteLine("char *end;"); WriteLine("errno = 0;"); - Write("*result = strto"); - Write(call); - WriteLine(");"); - WriteLine("return *end == '\\0' && errno == 0;"); - CloseBlock(); } void WriteIntLibrary!(string klassName, string type, SortedSet methods) @@ -3533,13 +3535,7 @@ public class GenC : GenCCpp if (methods.Contains(FuId.MathMax)) WriteIntMaxMin(klassName, "Max", type, '>'); if (methods.Contains(FuId.MathClamp)) { - WriteNewLine(); - Write("static "); - Write(type); - Write(" Fu"); - Write(klassName); - Write("_Clamp("); - Write(type); + StartLibraryMethod(type, klassName, "Clamp", type); Write(" x, "); Write(type); Write(" minValue, "); @@ -3550,10 +3546,19 @@ public class GenC : GenCCpp CloseBlock(); } if (methods.Contains(FuId.IntTryParse)) { - if (klassName == "Long") - WriteTryParseLibrary("Long_TryParse(int64_t *result, const char *str, int base)", "ll(str, &end, base"); - else - WriteTryParseLibrary("Int_TryParse(int *result, const char *str, int base)", "l(str, &end, base"); + StartTryParseLibrary(klassName, type, ", int base"); + if (klassName == "Int") { + WriteLine("long l = strtol(str, &end, base);"); + WriteLine("if (l < INT_MIN || l > INT_MAX || *end != '\\0' || errno != 0)"); + WriteLine("\treturn false;"); + WriteLine("*result = (int) l;"); + WriteLine("return true;"); + } + else { + WriteLine("*result = strtoll(str, &end, base);"); + WriteLine("return *end == '\\0' && errno == 0;"); + } + CloseBlock(); } } @@ -3562,8 +3567,12 @@ public class GenC : GenCCpp WriteIntLibrary("Int", "int", this.IntFunctions); WriteIntLibrary("NInt", "ptrdiff_t", this.NIntFunctions); WriteIntLibrary("Long", "int64_t", this.LongFunctions); - if (this.DoubleTryParse) - WriteTryParseLibrary("Double_TryParse(double *result, const char *str)", "d(str, &end"); + if (this.DoubleTryParse) { + StartTryParseLibrary("Double", "double", ""); + WriteLine("*result = strtod(str, &end);"); + WriteLine("return *end == '\\0' && errno == 0;"); + CloseBlock(); + } if (this.StringAssign) { WriteNewLine(); WriteLine("static void FuString_Assign(char **str, char *value)"); diff --git a/libfut.cpp b/libfut.cpp index 28afad88..d3403dc2 100644 --- a/libfut.cpp +++ b/libfut.cpp @@ -11437,6 +11437,7 @@ void GenC::writeCallExpr(const FuExpr * obj, const FuMethod * method, const std: writeEnumHasFlag(obj, args, parent); break; case FuId::intTryParse: + include("limits.h"); this->intFunctions.insert(FuId::intTryParse); write("FuInt"); writeTryParse(obj, args); @@ -12935,7 +12936,7 @@ void GenC::writeMethod(const FuMethod * method) this->currentMethod = nullptr; } -void GenC::writeIntMaxMin(std::string_view klassName, std::string_view method, std::string_view type, int op) +void GenC::startLibraryMethod(std::string_view type, std::string_view klassName, std::string_view method, std::string_view paramType) { writeNewLine(); write("static "); @@ -12945,7 +12946,12 @@ void GenC::writeIntMaxMin(std::string_view klassName, std::string_view method, s writeChar('_'); write(method); writeChar('('); - write(type); + write(paramType); +} + +void GenC::writeIntMaxMin(std::string_view klassName, std::string_view method, std::string_view type, int op) +{ + startLibraryMethod(type, klassName, method, type); write(" x, "); write(type); writeLine(" y)"); @@ -12956,21 +12962,17 @@ void GenC::writeIntMaxMin(std::string_view klassName, std::string_view method, s closeBlock(); } -void GenC::writeTryParseLibrary(std::string_view signature, std::string_view call) +void GenC::startTryParseLibrary(std::string_view klassName, std::string_view type, std::string_view baseParam) { - writeNewLine(); - write("static bool Fu"); - writeLine(signature); + startLibraryMethod("bool", klassName, "TryParse", type); + write(" *result, const char *str"); + write(baseParam); + writeCharLine(')'); openBlock(); writeLine("if (*str == '\\0')"); writeLine("\treturn false;"); writeLine("char *end;"); writeLine("errno = 0;"); - write("*result = strto"); - write(call); - writeLine(");"); - writeLine("return *end == '\\0' && errno == 0;"); - closeBlock(); } void GenC::writeIntLibrary(std::string_view klassName, std::string_view type, const std::set * methods) @@ -12980,13 +12982,7 @@ void GenC::writeIntLibrary(std::string_view klassName, std::string_view type, co if (methods->contains(FuId::mathMax)) writeIntMaxMin(klassName, "Max", type, '>'); if (methods->contains(FuId::mathClamp)) { - writeNewLine(); - write("static "); - write(type); - write(" Fu"); - write(klassName); - write("_Clamp("); - write(type); + startLibraryMethod(type, klassName, "Clamp", type); write(" x, "); write(type); write(" minValue, "); @@ -12997,10 +12993,19 @@ void GenC::writeIntLibrary(std::string_view klassName, std::string_view type, co closeBlock(); } if (methods->contains(FuId::intTryParse)) { - if (klassName == "Long") - writeTryParseLibrary("Long_TryParse(int64_t *result, const char *str, int base)", "ll(str, &end, base"); - else - writeTryParseLibrary("Int_TryParse(int *result, const char *str, int base)", "l(str, &end, base"); + startTryParseLibrary(klassName, type, ", int base"); + if (klassName == "Int") { + writeLine("long l = strtol(str, &end, base);"); + writeLine("if (l < INT_MIN || l > INT_MAX || *end != '\\0' || errno != 0)"); + writeLine("\treturn false;"); + writeLine("*result = (int) l;"); + writeLine("return true;"); + } + else { + writeLine("*result = strtoll(str, &end, base);"); + writeLine("return *end == '\\0' && errno == 0;"); + } + closeBlock(); } } @@ -13009,8 +13014,12 @@ void GenC::writeLibrary() writeIntLibrary("Int", "int", &this->intFunctions); writeIntLibrary("NInt", "ptrdiff_t", &this->nIntFunctions); writeIntLibrary("Long", "int64_t", &this->longFunctions); - if (this->doubleTryParse) - writeTryParseLibrary("Double_TryParse(double *result, const char *str)", "d(str, &end"); + if (this->doubleTryParse) { + startTryParseLibrary("Double", "double", ""); + writeLine("*result = strtod(str, &end);"); + writeLine("return *end == '\\0' && errno == 0;"); + closeBlock(); + } if (this->stringAssign) { writeNewLine(); writeLine("static void FuString_Assign(char **str, char *value)"); diff --git a/libfut.cs b/libfut.cs index d1a6cb49..10eaff6d 100644 --- a/libfut.cs +++ b/libfut.cs @@ -11693,6 +11693,7 @@ protected override void WriteCallExpr(FuExpr obj, FuMethod method, List WriteEnumHasFlag(obj, args, parent); break; case FuId.IntTryParse: + Include("limits.h"); this.IntFunctions.Add(FuId.IntTryParse); Write("FuInt"); WriteTryParse(obj, args); @@ -13163,7 +13164,7 @@ protected override void WriteMethod(FuMethod method) this.CurrentMethod = null; } - void WriteIntMaxMin(string klassName, string method, string type, int op) + void StartLibraryMethod(string type, string klassName, string method, string paramType) { WriteNewLine(); Write("static "); @@ -13173,7 +13174,12 @@ void WriteIntMaxMin(string klassName, string method, string type, int op) WriteChar('_'); Write(method); WriteChar('('); - Write(type); + Write(paramType); + } + + void WriteIntMaxMin(string klassName, string method, string type, int op) + { + StartLibraryMethod(type, klassName, method, type); Write(" x, "); Write(type); WriteLine(" y)"); @@ -13184,21 +13190,17 @@ void WriteIntMaxMin(string klassName, string method, string type, int op) CloseBlock(); } - void WriteTryParseLibrary(string signature, string call) + void StartTryParseLibrary(string klassName, string type, string baseParam) { - WriteNewLine(); - Write("static bool Fu"); - WriteLine(signature); + StartLibraryMethod("bool", klassName, "TryParse", type); + Write(" *result, const char *str"); + Write(baseParam); + WriteCharLine(')'); OpenBlock(); WriteLine("if (*str == '\\0')"); WriteLine("\treturn false;"); WriteLine("char *end;"); WriteLine("errno = 0;"); - Write("*result = strto"); - Write(call); - WriteLine(");"); - WriteLine("return *end == '\\0' && errno == 0;"); - CloseBlock(); } void WriteIntLibrary(string klassName, string type, SortedSet methods) @@ -13208,13 +13210,7 @@ void WriteIntLibrary(string klassName, string type, SortedSet methods) if (methods.Contains(FuId.MathMax)) WriteIntMaxMin(klassName, "Max", type, '>'); if (methods.Contains(FuId.MathClamp)) { - WriteNewLine(); - Write("static "); - Write(type); - Write(" Fu"); - Write(klassName); - Write("_Clamp("); - Write(type); + StartLibraryMethod(type, klassName, "Clamp", type); Write(" x, "); Write(type); Write(" minValue, "); @@ -13225,10 +13221,19 @@ void WriteIntLibrary(string klassName, string type, SortedSet methods) CloseBlock(); } if (methods.Contains(FuId.IntTryParse)) { - if (klassName == "Long") - WriteTryParseLibrary("Long_TryParse(int64_t *result, const char *str, int base)", "ll(str, &end, base"); - else - WriteTryParseLibrary("Int_TryParse(int *result, const char *str, int base)", "l(str, &end, base"); + StartTryParseLibrary(klassName, type, ", int base"); + if (klassName == "Int") { + WriteLine("long l = strtol(str, &end, base);"); + WriteLine("if (l < INT_MIN || l > INT_MAX || *end != '\\0' || errno != 0)"); + WriteLine("\treturn false;"); + WriteLine("*result = (int) l;"); + WriteLine("return true;"); + } + else { + WriteLine("*result = strtoll(str, &end, base);"); + WriteLine("return *end == '\\0' && errno == 0;"); + } + CloseBlock(); } } @@ -13237,8 +13242,12 @@ void WriteLibrary() WriteIntLibrary("Int", "int", this.IntFunctions); WriteIntLibrary("NInt", "ptrdiff_t", this.NIntFunctions); WriteIntLibrary("Long", "int64_t", this.LongFunctions); - if (this.DoubleTryParse) - WriteTryParseLibrary("Double_TryParse(double *result, const char *str)", "d(str, &end"); + if (this.DoubleTryParse) { + StartTryParseLibrary("Double", "double", ""); + WriteLine("*result = strtod(str, &end);"); + WriteLine("return *end == '\\0' && errno == 0;"); + CloseBlock(); + } if (this.StringAssign) { WriteNewLine(); WriteLine("static void FuString_Assign(char **str, char *value)"); diff --git a/libfut.hpp b/libfut.hpp index 04238319..6f1b7baa 100644 --- a/libfut.hpp +++ b/libfut.hpp @@ -2336,8 +2336,9 @@ class GenC : public GenCCpp void writeDestructFields(const FuSymbol * symbol); void writeNewDelete(const FuClass * klass, bool define); static bool canThrow(const FuType * type); + void startLibraryMethod(std::string_view type, std::string_view klassName, std::string_view method, std::string_view paramType); void writeIntMaxMin(std::string_view klassName, std::string_view method, std::string_view type, int op); - void writeTryParseLibrary(std::string_view signature, std::string_view call); + void startTryParseLibrary(std::string_view klassName, std::string_view type, std::string_view baseParam); void writeIntLibrary(std::string_view klassName, std::string_view type, const std::set * methods); void writeLibrary(); }; diff --git a/libfut.js b/libfut.js index 072a3725..a35ef6bf 100644 --- a/libfut.js +++ b/libfut.js @@ -12148,6 +12148,7 @@ export class GenC extends GenCCpp this.writeEnumHasFlag(obj, args, parent); break; case FuId.INT_TRY_PARSE: + this.include("limits.h"); this.#intFunctions.add(FuId.INT_TRY_PARSE); this.write("FuInt"); this.#writeTryParse(obj, args); @@ -13640,7 +13641,7 @@ export class GenC extends GenCCpp this.currentMethod = null; } - #writeIntMaxMin(klassName, method, type, op) + #startLibraryMethod(type, klassName, method, paramType) { this.writeNewLine(); this.write("static "); @@ -13650,7 +13651,12 @@ export class GenC extends GenCCpp this.writeChar(95); this.write(method); this.writeChar(40); - this.write(type); + this.write(paramType); + } + + #writeIntMaxMin(klassName, method, type, op) + { + this.#startLibraryMethod(type, klassName, method, type); this.write(" x, "); this.write(type); this.writeLine(" y)"); @@ -13661,21 +13667,17 @@ export class GenC extends GenCCpp this.closeBlock(); } - #writeTryParseLibrary(signature, call) + #startTryParseLibrary(klassName, type, baseParam) { - this.writeNewLine(); - this.write("static bool Fu"); - this.writeLine(signature); + this.#startLibraryMethod("bool", klassName, "TryParse", type); + this.write(" *result, const char *str"); + this.write(baseParam); + this.writeCharLine(41); this.openBlock(); this.writeLine("if (*str == '\\0')"); this.writeLine("\treturn false;"); this.writeLine("char *end;"); this.writeLine("errno = 0;"); - this.write("*result = strto"); - this.write(call); - this.writeLine(");"); - this.writeLine("return *end == '\\0' && errno == 0;"); - this.closeBlock(); } #writeIntLibrary(klassName, type, methods) @@ -13685,13 +13687,7 @@ export class GenC extends GenCCpp if (methods.has(FuId.MATH_MAX)) this.#writeIntMaxMin(klassName, "Max", type, 62); if (methods.has(FuId.MATH_CLAMP)) { - this.writeNewLine(); - this.write("static "); - this.write(type); - this.write(" Fu"); - this.write(klassName); - this.write("_Clamp("); - this.write(type); + this.#startLibraryMethod(type, klassName, "Clamp", type); this.write(" x, "); this.write(type); this.write(" minValue, "); @@ -13702,10 +13698,19 @@ export class GenC extends GenCCpp this.closeBlock(); } if (methods.has(FuId.INT_TRY_PARSE)) { - if (klassName == "Long") - this.#writeTryParseLibrary("Long_TryParse(int64_t *result, const char *str, int base)", "ll(str, &end, base"); - else - this.#writeTryParseLibrary("Int_TryParse(int *result, const char *str, int base)", "l(str, &end, base"); + this.#startTryParseLibrary(klassName, type, ", int base"); + if (klassName == "Int") { + this.writeLine("long l = strtol(str, &end, base);"); + this.writeLine("if (l < INT_MIN || l > INT_MAX || *end != '\\0' || errno != 0)"); + this.writeLine("\treturn false;"); + this.writeLine("*result = (int) l;"); + this.writeLine("return true;"); + } + else { + this.writeLine("*result = strtoll(str, &end, base);"); + this.writeLine("return *end == '\\0' && errno == 0;"); + } + this.closeBlock(); } } @@ -13714,8 +13719,12 @@ export class GenC extends GenCCpp this.#writeIntLibrary("Int", "int", this.#intFunctions); this.#writeIntLibrary("NInt", "ptrdiff_t", this.#nIntFunctions); this.#writeIntLibrary("Long", "int64_t", this.#longFunctions); - if (this.#doubleTryParse) - this.#writeTryParseLibrary("Double_TryParse(double *result, const char *str)", "d(str, &end"); + if (this.#doubleTryParse) { + this.#startTryParseLibrary("Double", "double", ""); + this.writeLine("*result = strtod(str, &end);"); + this.writeLine("return *end == '\\0' && errno == 0;"); + this.closeBlock(); + } if (this.#stringAssign) { this.writeNewLine(); this.writeLine("static void FuString_Assign(char **str, char *value)");