C4Script: Add ParseInt function

ParseInt() will take a string parameter and try to convert it into an
integer. If the conversion fails, it returns nil.
alut-include-path
Nicolas Hake 2017-04-11 14:21:25 +02:00
parent 1ee3081de2
commit b87f8e3f47
4 changed files with 68 additions and 1 deletions

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE funcs
SYSTEM '../../../clonk.dtd'>
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
<funcs>
<func>
<title>ParseInt</title>
<category>Arithmetics</category>
<version>8.0 OC</version>
<syntax>
<rtype>int</rtype>
<params>
<param>
<type>string</type>
<name>value</name>
<desc>Absolute coordinate you want to convert to a relative coordinate.</desc>
</param>
</params>
</syntax>
<desc>Parses a string representing a base 10 number into an integer value. If the string does not entirely consist of a base 10 number, optionally signed, <code>nil</code> is returned.</desc>
<examples>
<example>
<code>ParseInt("14")</code>
<text>Returns the integer <code>14</code>.</text>
<code>ParseInt("fourteen")</code>
<text>Returns <code>nil</code>.</text>
</example>
</examples>
</func>
</funcs>

View File

@ -94,8 +94,9 @@ static int ToNumber(char c)
//------------------------------- Strings ------------------------------------------------
int32_t StrToI32(const char *s, int base, const char **scan_end)
int32_t StrToI32(const char *str, int base, const char **scan_end)
{
const char *s = str;
int sign = 1;
int32_t result = 0;
if (*s == '-')
@ -107,6 +108,12 @@ int32_t StrToI32(const char *s, int base, const char **scan_end)
{
s++;
}
if (!*s)
{
// Abort if there are no digits to parse
if (scan_end) *scan_end = str;
return 0;
}
while (IsNumber(*s,base))
{
int value = ToNumber(*s++);

View File

@ -617,6 +617,16 @@ static C4Value FnFormat(C4PropList * _this, C4Value * Pars)
return C4VString(FnStringFormat(_this, Pars[0].getStr(), &Pars[1], 9));
}
// Parse a string into an integer. Returns nil if the conversion fails.
static Nillable<int32_t> FnParseInt(C4PropList *_this, C4String *str)
{
const char *cstr = str->GetCStr();
const char *end = nullptr;
int32_t result = StrToI32(cstr, 10, &end);
if (end == cstr || *end != '\0') return C4Void();
return result;
}
static long FnAbs(C4PropList * _this, long iVal)
{
return Abs(iVal);
@ -1142,6 +1152,7 @@ void InitCoreFunctionMap(C4AulScriptEngine *pEngine)
for (C4ScriptFnDef *pDef = &C4ScriptFnMap[0]; pDef->Identifier; pDef++)
new C4AulDefFunc(p, pDef);
#define F(f) ::AddFunc(p, #f, Fn##f)
F(ParseInt);
F(Abs);
F(Min);
F(Max);

View File

@ -147,6 +147,25 @@ TEST_F(AulPredefFunctionTest, CreateEffect)
EXPECT_EQ(C4VInt(3), RunScript("local A = { Construction=func() { this.Magicnumber = 3; } }; func Main() { return CreateEffect(A, 1).Magicnumber; }"));
}
TEST_F(AulPredefFunctionTest, ParseInt)
{
auto ParseInt = [this](const std::string &value) { return RunExpr("ParseInt(\"" + value + "\")"); };
EXPECT_EQ(C4VInt(0), ParseInt("0"));
EXPECT_EQ(C4VInt(0), ParseInt("-0"));
EXPECT_EQ(C4VInt(0), ParseInt("+0"));
EXPECT_EQ(C4VINT_MIN, ParseInt("-2147483648"));
EXPECT_EQ(C4VINT_MAX, ParseInt("2147483647"));
EXPECT_EQ(C4VNull, ParseInt(""));
EXPECT_EQ(C4VNull, ParseInt("-"));
EXPECT_EQ(C4VNull, ParseInt("+"));
EXPECT_EQ(C4VNull, ParseInt("--23"));
EXPECT_EQ(C4VNull, ParseInt("-+1234"));
EXPECT_EQ(C4VNull, ParseInt("a"));
EXPECT_EQ(C4VNull, ParseInt("0a"));
EXPECT_EQ(C4VNull, ParseInt("2147483647a"));
}
TEST_F(AulPredefFunctionTest, Trivial)
{
EXPECT_EQ(C4VInt(100), RunExpr("Sin(900,100,10)"));