A Basic Pyth-like Syntax Checker Pyth is a golfing language based on Python. It uses prefix notation, with each command having a different arity (number of arguments it accepts).

Your task is to write a syntax checker for a (non-existent) Pyth-like language, Pith.

Pith's syntax

Pith only has 8 single-char commands:

01234()"


01234 each have arity of the corresponding number, and hence expect that many arguments after it. For example,

400010


is a correct Pith program because 4 is followed by four arguments 0 0 0 and 10, the last of which is a 1 followed by the single argument 0. To visualise this, we can look at the following tree:

      R
      |
      4
      |
-------------
|   |   |   |
0   0   0   1
            |
            0


where R is the root node. An alternative way to think about this is that each number refers to the number of children the corresponding node has in the tree above.

Here's another valid Pith program, with more than one base command:

210010


corresponding to

           R
           |
     -------------
     |           |
     2           1
     |           |
 ---------       0
 |       |
 1       0
 |
 0


On the other hand,

3120102100


is not a correct Pith program because the initial 3 only has two arguments, which we can see by looking at the tree below:

                R
                |
                3
                |
     ------------------------ ??
     |          |
     1          2
     |          |
     2        ------
     |        |    |
   ------     1    0
   |    |     |
   0    1     0
        |
        0


Next ( starts an unbounded, and ) ends an unbounded. An unbounded takes any number of arguments (greedily), and counts as a single argument to any parent command. Any unboundeds still open by the end of the program are automatically closed. A ) command is not an error if no unboundeds are open — it just does nothing.*

For instance, the Pith program

)31(0)0(201000100


corresponds to the tree

            R
            |
            3
            |
    ------------------------------
    |       |                    |
    1       0                    (
    |                            |
    (              -----------------------------
    |              |      |      |      |      |
    0              2      0      0      1      0
                   |                    |
                -------                 0
                |     |
                0     1
                      |
                      0


Empty unboundeds are okay, so () is a valid Pith program.

An invalid Pith program with an unbounded is

12(010


since the 2 only receives one argument (the unbounded).

Finally, " starts and ends a string, which is always 0 arity and counts as a single argument, e.g.

2"010""44)()4"


which is just a 2 being passed two string arguments "010" and "44)()4". Like unboundeds, strings may also be empty, and any unclosed strings by the end of the program are automatically closed.

*This part is different from the original Pyth which actually does do something in a case like 1), ending the 1-arity and raising an error.

Input/output

Input will be a single non-empty string consisting of only the characters 01234()". You may optionally assume that an additional trailing newline is always present. You may write a function or a full program for this challenge.

You should output a truthy value if the input is syntactically valid Pith, or a falsy value otherwise. The truthy and falsy values must be fixed, so you can't output 1 for one valid program and 2 for another.

Scoring

This is code-golf, so the code in the fewest bytes wins.

Test cases

Truthy:

0
)
(
"
()
""
10
400010
210010
("")00
3"""""
(0)))0)1)0
2(2(2(0)0)0)0
2"010""44)()4"
)31(0)0(201000100
())2)1))0"3())"))
3("4321("301(0)21100"4")"123"00)40"121"31000""01010


Falsy:

1
1(310
(1)0)
12(010
4"00010"
3120102100
20(2((0)(0)))
2(2(2(0)0)0)01)
4(0102)00)00000
2"00"("00"2(""))
CJam, 65 bytes

q'"/La+2%{0s*}:Z~_,:L')*+{L{4{)_Z+s/Z}/L{'(\Z')++/Z}/}*')-}2*0s-!


Gosh, I wish CJam had Regex, this could have been completed in less than 50 bytes then

The main idea is to keep reducing stuff to 0 i.e. 10 to 0, 200 to 0 and so on. Once that is done, we reduce all matched brackets to 0, i.e. () to 0, (0) to 0, (00) to 0 and so on. The we repeat the cycle L times, where L is the input length.

The input string initially goes through extra processing where we adjust for unmatched " and add lots of ) to compensate for unmatched (

This ensures that after all the iterations, we should only have 0 (and no-op )) left in the string.

Update - fixed a bug where top level ) no-op are considered harmful

Code expansion

q'"/La+2%{0s*}:Z~_,:L')*      "Part 1 - Preprocessing";
q'"/                          "Read the input and split it on quote";
    La+                       "Add an extra empty array to the split array to compensate";
                              "for unmatched ending quote";
        2%                    "Take every other splitted part, ignoring the contents";
                              "of the strings in the code";
          {0s*}:Z~            "Join the parts by string 0. Also create a function Z";
                              "that does that for future use. We are now done with";
                              "reducing "XYZ" to 0 ";
                  _,:L        "Store the length of the remaining code in L";
                      ')*     "Append L ) to the string to compensate for unmatched (";

{L{4{)_Z+s/Z}/L{'(\Z')++/Z}/}*')-}2*   "Part 2 - the reducing loop";
 L{                         }*         "Run the reduction logic L times";
   4{)_Z+s/Z}/                         "Part 2a - reducing arities";
   4{       }/                         "Run the iteration for 0, 1, 2 and 3";
     )_                                "Increment the iteration number and make a copy";
       Z+s                             "Get that many 0 and append it to the number";
          /Z                           "Split the code onto this number and convert it";
                                       "to 0. This successfully reduces 10, 200, ";
                                       "3000 and 4000 to 0";
              L{'(\Z')++/Z}/           "Part 2b - reducing groups";
              L{          }/           "Run the iteration for 0 through L - 1";
                '(\Z')++               "Get the string '(&lt;iteration number of 0&gt;)'";
                        /Z             "split on it and join by 0. This successfully";
                                       "reduces (), (0), (00) and so on .. to 0";
                              ')-      "After running the part 2 loop L times, all";
                                       "reducible arities and brackets should be reduced";
                                       "except for cases like '30)00' where the no-op )";
                                       "breaks the flow. So we remove ) from the code";
                                       "and run Part 2 L times again";

0s-!                          "Now, if the code was valid, we should only have 0 in the";
                              "remaining code. If not, the code was invalid";


Try it online here or run the whole suite