0

I have noticed that when I have multiple where clauses and multiple asserting clauses, that I get often get syntax errors when I combine them together. The error will say "unexpected token after where". How should I write it to avoid this error? Here is the latest example:

Attempt 1:

def(class game_state game) ->commands [
        set(attack, cost),
        set(life, cost),
        set(abilities, []),
    ] where cost=(card.cost + (card.loyalty_cost * size(card.school)))
      where card=crypt_spells[choices[0]]
//      asserting size(choices) = 1 //FIXME: syntax error uncommented
        asserting choices != null
      where crypt_spells=filter(game.crypt.cards_of(player), value.type='spell')
      where player=game.player_obj

I also tried rewriting it a different way, that also resulted in the "unexpected token after where" syntax error.

Attempt 2:

def(class game_state game) ->commands [
        set(attack, cost),
        set(life, cost),
        set(abilities, []),
    ] where cost=(card.cost + (card.loyalty_cost * size(card.school)))
      where card=crypt_spells[choices[0]]
      asserting choices != null, size(choices)=1 | choices //FIXME: syntax error
      where crypt_spells=filter(game.crypt.cards_of(player), value.type='spell')
      where player=game.player_obj

Example 3:

Here is another example that, I think, highlights the problem:

def(class game_state game, class message.play_card info) ->commands
  if(info.choices,
    ([ /* do stuff */ ]
      where entry=game.crypt.get_entry(info.choices[0])
      asserting size(info.targets)=1 | info.targets    /* PARSE ERROR! */
    ) asserting size(info.choices)=1 | info.choices,   /* WORKS */
    [ /* else */ ]
  )

As you can see from this example, asserting a=b works fine unless it is preceded by a where clause.

Patrick Parker
  • 4,863
  • 4
  • 19
  • 51

1 Answers1

1

Let me try to transform your code into generic debug console code:

f()
where f = def
        () -> commands [
                debug(['something']),
                debug(['more stuff']),
                debug(['yet more stuff']),
        ]
        where aaa = (0 + (1 * 2))
        where bbb = 4
//        asserting 2 + 2 = 4 // FIXME: syntax error uncommented
        asserting '000' != null
        where ccc = [0, 1, 2, 3]
        where ddd = {'0': 0, '1': 1, }

The debug console can execute that:

(debug console):0: ['something']
(debug console):0: ['more stuff']
(debug console):0: ['yet more stuff']
[(Command Object: N10game_logic12_GLOBAL__N_113debug_commandE),
 (Command Object: N10game_logic12_GLOBAL__N_113debug_commandE),
 (Command Object: N10game_logic12_GLOBAL__N_113debug_commandE)]

Let's check that your syntax error is still there, or at least some syntax error, when uncommenting the assertion:

f()
where f = def
        () -> commands [
                debug(['something']),
                debug(['more stuff']),
                debug(['yet more stuff']),
        ]
        where aaa = (0 + (1 * 2))
        where bbb = 4
        asserting 2 + 2 = 4 // FIXME: syntax error uncommented
        asserting '000' != null
        where ccc = [0, 1, 2, 3]
        where ddd = {'0': 0, '1': 1, }

The debug console can't execute:

error parsing formula: formula.cpp:3942 ASSERTION FAILED: Unexpected tokens after
where
At (debug console) 0:
... where bbb = 4       asserting 2 + 2 = 4 // FIXME syntax error uncommen...
                                        ^

The engine uses simple parsing, and currently where, asserting and = (and maybe even ,?) can be combined in ways intuitive but not well managed by the parser.

Here, I think it found a secondary = for where before reaching ,, but I don't know. Right now I don't know exactly what is the criteria for finishing parsing of where. You would know by just debugging the parser.

This is an important issue, but maybe not critical and must fix now, as can mostly be managed by including more parens exhaustiveness.

Let's place just one parens pair, let's start by the failing assertion:

f()
where f = def
        () -> commands [
                debug(['something']),
                debug(['more stuff']),
                debug(['yet more stuff']),
        ]
        where aaa = (0 + (1 * 2))
        where bbb = 4
        asserting (2 + 2 = 4) // FIXME: syntax error uncommented
        asserting '000' != null
        where ccc = [0, 1, 2, 3]
        where ddd = {'0': 0, '1': 1, }

The debug console can execute again:

(debug console):0: ['something']
(debug console):0: ['more stuff']
(debug console):0: ['yet more stuff']
[(Command Object: N10game_logic12_GLOBAL__N_113debug_commandE),
 (Command Object: N10game_logic12_GLOBAL__N_113debug_commandE),
 (Command Object: N10game_logic12_GLOBAL__N_113debug_commandE)]

2018 May 27 added the error pinpoint location.

1737973
  • 159
  • 18
  • 42
  • are you saying it's a bug in the parser? and what about Attempt 2... how would you fix that one? – Patrick Parker May 27 '18 at 07:23
  • The parser potentially can be improved in order to better treat attempt 1 without affecting actual games code the engine has to run. But I don't really know until several or at least one step by step running sessions using a debugger. – 1737973 May 27 '18 at 07:33
  • I don't understand `asserting choices != null, size(choices)=1 | choices`, an important difference in attempt 2 relative to attempt 1. So I see it and I can't see the debug console friendly version of that. Had to ignore it. – 1737973 May 27 '18 at 07:37
  • Why would you write `asserting choices != null, size(choices)=1 | choices` not being in list comprehension? Is it valid (have you ever used something like that)? Can we consider `asserting choices != null and size(choices)=1` instead? – 1737973 Jun 04 '18 at 16:41
  • Yes, it’s valid. I have seen that style of assert in other places in working code. – Patrick Parker Jun 05 '18 at 00:41
  • Alright, understood. I've been trying to get it running for some minutes, but I think Attempt 2 just ca not work at all. So it's maybe serious candidate to bug. I'm not going to report it though as issue, because `asserting choices != null, size(choices) = 1 | choices` is (or has to be) equivalent to the more clear `asserting choices != null and size(choices) = 1` or the even more clear `asserting size(choices) = 1 asserting choices != null`. Also the issue tracker is now under control of the evil empire (just joking (but nope)). – 1737973 Jun 05 '18 at 18:34
  • Right, so in summary your answer is: 1) Don't use the asserting comma syntax 2) Put an open paren after `asserting` keyword and close paren before `|` pipe. I guess I can accept that. It does seem a bit buggish though. See my Example 3 added above. – Patrick Parker Jun 06 '18 at 05:34
  • For the time being I would advice to refrain from using the `asserting` comma syntax whenever there is going to be more than one element in the `where` and `asserting` clauses chain. I tried parenthesis pairs opening after `asserting` and closing before `|`, but I've not seen that as enough more solid as to recommend it specifically. I can't get to run Example 3 unless I remove every `where` and `asserting`. But... I think I have perceived before difficulties embedding `where` and `assertion` inside `if(...)`. Maybe that is an additional problem there. – 1737973 Jun 06 '18 at 09:27
  • I would mind to see a revamping of the formulas parsing code. But I'm not considering it if there is no way to unit test all of the parsing code with full coverage. Then try to extract the grammar from the unit tests. Then somehow try to profit from knowing the actual grammar. – 1737973 Jun 06 '18 at 09:30
  • note: Example 3 will parse if you write `asserting (size(info.targets)=1) | info.targets`. My point is that you don't have to wrap the second assertion in parenthesis, which seems inconsistent. And the problem with the first assertion is surprising because I don't know why the parser would need us to wrap up such a simple expression like size(info.targets)=1. – Patrick Parker Jun 06 '18 at 10:10
  • Very right! Interesting. Well, if you are curious, you can dive in the parser, and just find the answer, it's not the [clarity of Linux](https://superuser.com/a/704914) (also obviously there is not the same amount of manpower in it), but [once you get familiar, you can adapt it as you wish](https://github.com/anura-engine/anura/issues/240). – 1737973 Jun 06 '18 at 14:01