dibyendumajumdar / ravi

Ravi is a dialect of Lua, featuring limited optional static typing, JIT and AOT compilers
http://ravilang.github.io/
Other
1.16k stars 60 forks source link

Lua parsing error #241

Closed mustime closed 2 years ago

mustime commented 2 years ago

Compiling the following code into bytecode:

local t = {}

function t:GetNumFromStr(strData, Substr: string)
    local iSubLen = #Substr
    local iCount = 0
    local temp1 = strData
    for i = 1, #strData, 1 do
        local temp2 = string.sub(temp1, i, i + iSubLen - 1)
        if temp2 == Substr then
            i = i + iSubLen
            iCount = iCount + 1
        end
    end

    return iCount
end

and will end up with an error:

test.lua:11: Invalid assignment: integer expected near 'iCount'

However, if I change line: 4 to local iSubLen: integer = #Substr, it will get passed.

So I wonder doesn't # operation make iSubLen an integer already? Why : integer is needed.

dibyendumajumdar commented 2 years ago

hi the # operator is not guaranteed to return an integer value as you can have meta method to override the behavior.

Although I suppose if operand is a string, unlikely to have a metamethod on it. Maybe in this case we could assert its an integer

XmiliaH commented 2 years ago

Although I suppose if operand is a string, unlikely to have a metamethod on it. Maybe in this case we could assert its an integer

The # operator is guaranteed to return integers for ravi-arrays and strings. There is already a case for that when parsing the length operator https://github.com/dibyendumajumdar/ravi/blob/a6eeb86c4135255344ca138231a4c2c81961230e/src/lcode.c#L1315-L1319 but Substr: string allows Substr to be a string or nil and nil can have a metamethod for the length operator.

Also, there is a bug in lcode.c:

--- a/src/lcode.c
+++ b/src/lcode.c
@@ -1391,7 +1391,7 @@ static void codebinexpval (FuncState *fs, OpCode op,
     }                                                                      \
     e1->u.info = luaK_codeABC(fs, OP_##op, 0, rk1, rk2);                   \
     if ((e1->ravi_type_map & (~(RAVI_TM_FLOAT | RAVI_TM_INTEGER))) == 0 && \
-        (e1->ravi_type_map & (~(RAVI_TM_FLOAT | RAVI_TM_INTEGER))) == 0) { \
+        (e2->ravi_type_map & (~(RAVI_TM_FLOAT | RAVI_TM_INTEGER))) == 0) { \
       if (e1->ravi_type_map & e2->ravi_type_map & RAVI_TM_INTEGER) {       \
         e1->ravi_type_map = RAVI_TM_FLOAT | ii;                            \
       }                                                                    \
XmiliaH commented 2 years ago

@mustime I do not know what you do with i = i + iSubLen as

for i = 1, 10 do
    print(i)
    i = i + 2
end

might not give the result you expected.

mustime commented 2 years ago

@mustime I do not know what you do with i = i + iSubLen as

for i = 1, 10 do
    print(i)
    i = i + 2
end

might not give the result you expected.

Well, the logic I list above had been stripped down and somehow pointless. Just try to explain the case. And it seems only happened within the for-statement.

To make this simpler, try the following code:

function foo(a, b)
    local x = #b
    for i = 1, #a, 1 do
        i = i + x
    end
end

And will get test.lua: 5: Invalid assignment: integer expected near 'end'