ID:2445083
 
Resolved
Certain complex do-while loop cases could behave incorrectly in the while() condition, as a result of the way they were compiled.
BYOND Version:512
Operating System:Windows 7 Ultimate 64-bit
Web Browser:Firefox 66.0
Applies to:Dream Maker
Status: Resolved (512.1467)

This issue has been resolved.
Descriptive Problem Summary:

The condition of a do-while loop loses track of what object methods are being called on, complaining that a /list/procname() does not exist when src is not a list and procname() exists on src.

See "COMMENT OUT THIS LINE TO BREAK IT" in the snippet below.

Code Snippet (if applicable) to Reproduce Problem:
/datum/SDQL_parser
var/list/query
var/error = 0

/datum/SDQL_parser/New(query_list)
query = query_list

/datum/SDQL_parser/proc/parse_error(error_message)
error = 1
usr << "SQDL2 Parsing Error: [error_message]</span>"
return query.len + 1

/datum/SDQL_parser/proc/token(i)
return query[i]

/datum/SDQL_parser/proc/expression(i, list/node)
node += "expression"
return i + 1

/datum/SDQL_parser/proc/array(var/i, var/list/node)
if(copytext(token(i), 1, 2) != "\[")
parse_error("Expected an array but found '[token(i)]'")
return i + 1

node += token(i) // Add the "["

var/list/expression_list = list()

i++
if(token(i) != "]")
var/list/temp_expression_list = list()
do
var/tok = token(i)
if (tok == ",")
if (temp_expression_list == null)
parse_error("Found ',' or ':' without expression in an array.")
return i + 1

expression_list[++expression_list.len] = temp_expression_list
temp_expression_list = null
i++
continue

temp_expression_list = list()
i = expression(i, temp_expression_list)

// COMMENT OUT THIS LINE TO BREAK IT
var/_ = src.type

while(token(i) && token(i) != "]")

if (temp_expression_list)
expression_list[++expression_list.len] = temp_expression_list

node[++node.len] = expression_list

return i + 1

/client/New()
..()

usr = src
var/tokens = json_decode(@{"["[","1",",","2",",","3","]"]"})
var/datum/SDQL_parser/D = new(tokens)
var/target = list()
var/result = D.array(1, target)
src << "[D.error ? "error" : "ok"]"
src << json_encode(result)
src << json_encode(target)


Expected Results:

ok
8
["[",[["expression"],["expression"],["expression"]]]

Actual Results:

runtime error: undefined proc or verb /list/token().

proc name: array (/datum/SDQL_parser/proc/array)
source file: sandbox.dm,50
usr: SpaceManiac (/client)
src: /datum/SDQL_parser (/datum/SDQL_parser)
call stack:
/datum/SDQL_parser (/datum/SDQL_parser): array(4, /list (/list))
SpaceManiac (/client): New()
ok
null
["["]

Does the problem occur:
Every time? Or how often? Every time.
In other games? Yes, in both prod and test project.
In other user accounts? Yes, originally discovered by another coder.
On other computers? Yes, see above.

When does the problem NOT occur?

When "src." is accessed prior to the do-while condition.

Changing the use of "continue" to an "else" instead also suppresses the issue.

Did the problem NOT occur in any earlier versions? If so, what was the last version that worked? (Visit http://www.byond.com/download/build to download old versions for testing.)

Occurs in both 1464 and 1465, earlier versions unknown.

Workarounds:

Write a no-op involving "src." before the do-while condition.
Ooh, this is a good find. Probably a simple fix in the compiler.
Lummox JR resolved issue with message:
Certain complex do-while loop cases could behave incorrectly in the while() condition, as a result of the way they were compiled.