LordGolias/sqf

Crash when using results of if statement

Closed this issue · 2 comments

if (true) then {["a",1]} else {["b",2]} params ["_l", "_n"];
(if (true) then {["a",1]} else {["b",2]}) params ["_l", "_n"];

First line causes error, second passes.

Traceback (most recent call last):
  File "V:\sqf\sqflint.py", line 92, in <module>
    _main()
  File "V:\sqf\sqflint.py", line 88, in _main
    main(sys.argv[1:])
  File "V:\sqf\sqflint.py", line 82, in main
    return analyze(code, writer)
  File "V:\sqf\sqflint.py", line 25, in analyze
    exceptions = sqf.analyzer.analyze(result).exceptions
  File "V:\sqf\sqf\analyzer.py", line 399, in analyze
    analyzer.execute_code(file, extra_scope={'_this': arg})
  File "V:\sqf\sqf\analyzer.py", line 139, in execute_code
    outcome = super().execute_code(code, params, extra_scope, namespace_name)
  File "V:\sqf\sqf\base_interpreter.py", line 131, in execute_code
    outcome = self.value(self.execute_single(statement))
  File "V:\sqf\sqf\analyzer.py", line 267, in execute_single
    t = self.execute_token(token)
  File "V:\sqf\sqf\analyzer.py", line 100, in execute_token
    result = self.execute_single(statement=token)
  File "V:\sqf\sqf\analyzer.py", line 287, in execute_single
    outcome = return_type()
TypeError: __init__() missing 2 required positional arguments: 'then' and 'else_'

I'm honestly a little surprised the above code works in arma, as the following code throws an error in arma:

x = if (true) then {2} else {3} * 5;

Mathematical binary commands have a higher priority than other binary commands. (Also else has a higher priority than other binary commands for the if-then-else construct to work, but still lower than mathematical binary commands).

This is why:

["a", "b", "c", "d", "e"] select 2 + 1
["a", "b", "c", "d", "e"] select 3
"d"

params is just another binary command here.

The precedence of the operators is defined in the code here. The numbers I am using are from this blog post from foxhound.

The issue here is that params is both a unary and binary operator, and, during parsing, it currently does not know which one is to be used. I favored using unary strength instead of the binary (elif n_token in UNARY_OPERATORS: is before elif n_token in BINARY_OPERATORS:), which is a problem in this case because it makes it stronger than else. The crash is caused by the parser parsing

if (true) then {["a",1]} else {["b",2]} params ["_l", "_n"];

as

if (true) then {["a",1]} else ({["b",2]} params ["_l", "_n"];)

instead of

(if (true) then {["a",1]} else {["b",2]}) params ["_l", "_n"];

The easy fix for this is failing gracefully for bad code with if-then constructs like the above; the complete fix is to use binary or unary binding strength correctly for both unary and binary operators.