laurentlb/shader-minifier

Declarator lists as operands of ternary operator parsed incorrectly

Opened this issue · 4 comments

Hi, it's me again (sorry ._.)

The following shader should be valid (validates using glslangValidator; also compare https://www.shadertoy.com/view/lfjcWt)

#version 450

out vec4 out_color;
uniform float t;

void main() {
    float a, b;

    t > .5
        ? a = .5, b = .5
        : a = .9, b = .1
        ;
    out_color = vec4(a, b, 1, 1);
}

But triggers a parsing error in shader_minifier:

System.AggregateException: One or more errors occurred. (Parse error: Error in minbug.frag: Ln: 10 Col: 17
        ? a = .5, b = .5
                ^
Expecting: infix operator, postfix operator, suffix or ':'
Other error messages:
  ':' is the right part of the ternary operator '?' ':'. The left part is on
  the same line at column 9.
) ---> System.Exception: Parse error: Error in minbug.frag: Ln: 10 Col: 17
        ? a = .5, b = .5
                ^
Expecting: infix operator, postfix operator, suffix or ':'
Other error messages:
  ':' is the right part of the ternary operator '?' ':'. The left part is on
  the same line at column 9.

  at Microsoft.FSharp.Core.PrintfModule+PrintFormatToStringThenFail@1439[TResult].Invoke (System.String message) [0x00000] in <665bb110c40096cda745038310b15b66>:0 
  at <StartupCode$shader_minifier_lib>.$Api+parseAndRewrite@23.Invoke (System.Tuple`2[T1,T2] tupledArg) [0x00019] in <665bb110c40096cda745038310b15b66>:0 
  at Microsoft.FSharp.Collections.ArrayModule+Parallel+Map@1401-2[T,TResult].Invoke (System.Int32 i) [0x00000] in <665bb110c40096cda745038310b15b66>:0 
  at System.Threading.Tasks.Parallel+<ForWorker>c__AnonStorey2`1[TLocal].<>m__1 (System.Threading.Tasks.RangeWorker& currentWorker, System.Int32 timeout, System.Boolean& replicationDelegateYieldedBeforeCompletion) [0x00103] in <12b418a7818c4ca0893feeaaf67f1e7f>:0 
--- End of stack trace from previous location where exception was thrown ---

  at System.Threading.Tasks.Parallel+<ForWorker>c__AnonStorey2`1[TLocal].<>m__1 (System.Threading.Tasks.RangeWorker& currentWorker, System.Int32 timeout, System.Boolean& replicationDelegateYieldedBeforeCompletion) [0x0024b] in <12b418a7818c4ca0893feeaaf67f1e7f>:0 
  at System.Threading.Tasks.TaskReplicator+Replica`1[TState].ExecuteAction (System.Boolean& yieldedBeforeCompletion) [0x00000] in <12b418a7818c4ca0893feeaaf67f1e7f>:0 
  at System.Threading.Tasks.TaskReplicator+Replica.Execute () [0x00029] in <12b418a7818c4ca0893feeaaf67f1e7f>:0 
   --- End of inner exception stack trace ---
  at System.Threading.Tasks.TaskReplicator.Run[TState] (System.Threading.Tasks.TaskReplicator+ReplicatableUserAction`1[TState] action, System.Threading.Tasks.ParallelOptions options, System.Boolean stopOnFirstFailure) [0x0006a] in <12b418a7818c4ca0893feeaaf67f1e7f>:0 
  at System.Threading.Tasks.Parallel.ForWorker[TLocal] (System.Int32 fromInclusive, System.Int32 toExclusive, System.Threading.Tasks.ParallelOptions parallelOptions, System.Action`1[T] body, System.Action`2[T1,T2] bodyWithState, System.Func`4[T1,T2,T3,TResult] bodyWithLocal, System.Func`1[TResult] localInit, System.Action`1[T] localFinally) [0x0015c] in <12b418a7818c4ca0893feeaaf67f1e7f>:0 
--- End of stack trace from previous location where exception was thrown ---

  at System.Threading.Tasks.Parallel.ThrowSingleCancellationExceptionOrOtherException (System.Collections.ICollection exceptions, System.Threading.CancellationToken cancelToken, System.Exception otherException) [0x00010] in <12b418a7818c4ca0893feeaaf67f1e7f>:0 
  at System.Threading.Tasks.Parallel.ForWorker[TLocal] (System.Int32 fromInclusive, System.Int32 toExclusive, System.Threading.Tasks.ParallelOptions parallelOptions, System.Action`1[T] body, System.Action`2[T1,T2] bodyWithState, System.Func`4[T1,T2,T3,TResult] bodyWithLocal, System.Func`1[TResult] localInit, System.Action`1[T] localFinally) [0x001c5] in <12b418a7818c4ca0893feeaaf67f1e7f>:0 
  at System.Threading.Tasks.Parallel.For (System.Int32 fromInclusive, System.Int32 toExclusive, System.Action`1[T] body) [0x00011] in <12b418a7818c4ca0893feeaaf67f1e7f>:0 
  at Microsoft.FSharp.Collections.ArrayModule+Parallel.Map[T,TResult] (Microsoft.FSharp.Core.FSharpFunc`2[T,TResult] mapping, T[] array) [0x00024] in <665bb110c40096cda745038310b15b66>:0 
  at ShaderMinifier.Minifier.minify (Options+Options options, System.Tuple`2[System.String,System.String][] files) [0x00150] in <665bb110c40096cda745038310b15b66>:0 
  at ShaderMinifier.Minifier..ctor (Options+Options options, System.Tuple`2[System.String,System.String][] files) [0x0000f] in <665bb110c40096cda745038310b15b66>:0 
  at Main.minifyFiles (Options+Options options, System.Collections.Generic.IEnumerable`1[T] filenames, System.IO.TextWriter out) [0x00073] in <665bb110c40096cda745038310b15b66>:0 
  at Main.run (Options+Options options, System.Collections.Generic.IEnumerable`1[T] filenames) [0x0003b] in <665bb110c40096cda745038310b15b66>:0 
---> (Inner Exception #0) System.Exception: Parse error: Error in minbug.frag: Ln: 10 Col: 17
        ? a = .5, b = .5
                ^
Expecting: infix operator, postfix operator, suffix or ':'
Other error messages:
  ':' is the right part of the ternary operator '?' ':'. The left part is on
  the same line at column 9.

  at Microsoft.FSharp.Core.PrintfModule+PrintFormatToStringThenFail@1439[TResult].Invoke (System.String message) [0x00000] in <665bb110c40096cda745038310b15b66>:0 
  at <StartupCode$shader_minifier_lib>.$Api+parseAndRewrite@23.Invoke (System.Tuple`2[T1,T2] tupledArg) [0x00019] in <665bb110c40096cda745038310b15b66>:0 
  at Microsoft.FSharp.Collections.ArrayModule+Parallel+Map@1401-2[T,TResult].Invoke (System.Int32 i) [0x00000] in <665bb110c40096cda745038310b15b66>:0 
  at System.Threading.Tasks.Parallel+<ForWorker>c__AnonStorey2`1[TLocal].<>m__1 (System.Threading.Tasks.RangeWorker& currentWorker, System.Int32 timeout, System.Boolean& replicationDelegateYieldedBeforeCompletion) [0x00103] in <12b418a7818c4ca0893feeaaf67f1e7f>:0 
--- End of stack trace from previous location where exception was thrown ---

  at System.Threading.Tasks.Parallel+<ForWorker>c__AnonStorey2`1[TLocal].<>m__1 (System.Threading.Tasks.RangeWorker& currentWorker, System.Int32 timeout, System.Boolean& replicationDelegateYieldedBeforeCompletion) [0x0024b] in <12b418a7818c4ca0893feeaaf67f1e7f>:0 
  at System.Threading.Tasks.TaskReplicator+Replica`1[TState].ExecuteAction (System.Boolean& yieldedBeforeCompletion) [0x00000] in <12b418a7818c4ca0893feeaaf67f1e7f>:0 
  at System.Threading.Tasks.TaskReplicator+Replica.Execute () [0x00029] in <12b418a7818c4ca0893feeaaf67f1e7f>:0 <---

I'm using Shader Minifier 1.4.0

It is possible to use the workaround

#version 450

out vec4 out_color;
uniform float t;

void main() {
    float a, b;

    t > .5
        ? (a = .5, b = .5)
        : (a = .9, b = .1)
        ;
    out_color = vec4(a, b, 1, 1);
}

which gets minified to

#version 450

out vec4 v;
uniform float f;
void main()
{
  float m,N;
  f>.5?
    m=.5,N=.5:
    (m=.9,N=.1);
  v=vec4(m,N,1,1);
}

(That's at the cost of one set of unneccessary (, ) , but enables using declarator lists anyways)

Thanks for the reports!

For the last point, that was the PR that removed the parentheses between ? and :: #396

The "workaround" shader is not the same as the original shader. Without the parentheses, the expression should parse as
(t>.5?a=.5,b=.5:a=.9) , b=.1;
, is lower precedence than ? : in GLSL spec.

N.B. It's easier to understand and discuss outputs if renaming is disabled, since this isn't related to a renamer bug.

The input line with : is red herring; these all parse correctly in the minifier:
t > .5 ? a = .5 : a = .9, b = .1 ;
float c = t > .5 ? a = .5 : a = .9, b = .1 ; (redefines b, see bug #437)
with different result:
t > .5 ? a = .5 : (a = .9, b = .1) ;
float c = t > .5 ? a = .5 : (a = .9, b = .1) ;

The actual bug may be reproduced more simply; these both fail to parse (with different error messages):
t > .5 ? a, b : a ;
float c = t > .5 ? a, b : a ;
While these parse (this is the relevant workaround):
t > .5 ? (a, b) : a ;
float c = t > .5 ? (a, b) : a ;