gen-text 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.yardopts +2 -0
 - data/LICENSE +21 -0
 - data/README.md +170 -0
 - data/bin/gen-text +73 -0
 - data/lib/gen_text/compile.rb +547 -0
 - data/lib/gen_text/vm.rb +269 -0
 - data/lib/io/with_dummy_pos.rb +20 -0
 - data/yardopts_extra.rb +4 -0
 - metadata +75 -0
 
    
        data/.yardopts
    ADDED
    
    
    
        data/LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            The MIT License (MIT)
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Copyright (c) 2016-9999 Humanity
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         
     | 
| 
      
 6 
     | 
    
         
            +
            of this software and associated documentation files (the "Software"), to deal
         
     | 
| 
      
 7 
     | 
    
         
            +
            in the Software without restriction, including without limitation the rights
         
     | 
| 
      
 8 
     | 
    
         
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         
     | 
| 
      
 9 
     | 
    
         
            +
            copies of the Software, and to permit persons to whom the Software is
         
     | 
| 
      
 10 
     | 
    
         
            +
            furnished to do so, subject to the following conditions:
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be included in all
         
     | 
| 
      
 13 
     | 
    
         
            +
            copies or substantial portions of the Software.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         
     | 
| 
      
 16 
     | 
    
         
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         
     | 
| 
      
 17 
     | 
    
         
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         
     | 
| 
      
 18 
     | 
    
         
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         
     | 
| 
      
 19 
     | 
    
         
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         
     | 
| 
      
 20 
     | 
    
         
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
         
     | 
| 
      
 21 
     | 
    
         
            +
            SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,170 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Description
         
     | 
| 
      
 2 
     | 
    
         
            +
            -----------
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            A generator of texts from EBNF-like grammars.
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            Install
         
     | 
| 
      
 7 
     | 
    
         
            +
            -------
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            - Install [Ruby](http://ruby-lang.org) 1.9.3 or higher.
         
     | 
| 
      
 10 
     | 
    
         
            +
            - `gem install gen-text`
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            Usage
         
     | 
| 
      
 13 
     | 
    
         
            +
            -----
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            Run it with the command:
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                gen-text file.g
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            Here `file.g` is a file containing the grammar description which consists of the rule definitions:
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                nonterminal1 = expr1 ;
         
     | 
| 
      
 22 
     | 
    
         
            +
                
         
     | 
| 
      
 23 
     | 
    
         
            +
                nonterminal2 = expr2 ;
         
     | 
| 
      
 24 
     | 
    
         
            +
                
         
     | 
| 
      
 25 
     | 
    
         
            +
                nonterminal3 = expr3 ;
         
     | 
| 
      
 26 
     | 
    
         
            +
                
         
     | 
| 
      
 27 
     | 
    
         
            +
            Nonterminals start from a letter or "\_" and may contain alphanumeric characters, "\_", "-" or ":".
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            You may also use backquoted nonterminals:
         
     | 
| 
      
 30 
     | 
    
         
            +
                
         
     | 
| 
      
 31 
     | 
    
         
            +
                `nonterminal1` = expr1 ;
         
     | 
| 
      
 32 
     | 
    
         
            +
                
         
     | 
| 
      
 33 
     | 
    
         
            +
                `Nonterminal with arbitrary characters: [:|:]\/!` = expr2 ;
         
     | 
| 
      
 34 
     | 
    
         
            +
                
         
     | 
| 
      
 35 
     | 
    
         
            +
            You may use the following expressions in the right part:
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            <table>
         
     | 
| 
      
 38 
     | 
    
         
            +
              <thead>
         
     | 
| 
      
 39 
     | 
    
         
            +
                <tr> <td><strong>Expression</strong></td> <td><strong>Meaning</strong></td> </tr>
         
     | 
| 
      
 40 
     | 
    
         
            +
              </thead>
         
     | 
| 
      
 41 
     | 
    
         
            +
              <tbody>
         
     | 
| 
      
 42 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 43 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 44 
     | 
    
         
            +
                    <tt>"str"</tt><br/>
         
     | 
| 
      
 45 
     | 
    
         
            +
                    <tt>'str'</tt>
         
     | 
| 
      
 46 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 47 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 48 
     | 
    
         
            +
                    <p>Generate a string.</p>
         
     | 
| 
      
 49 
     | 
    
         
            +
                    <p>Following escape sequences are allowed: "\n", "\t", "\e" and "\." where "." is an arbitrary character.</p>
         
     | 
| 
      
 50 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 51 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 52 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 53 
     | 
    
         
            +
                  <td><tt>U+HHHH</tt></td>
         
     | 
| 
      
 54 
     | 
    
         
            +
                  <td>Generate an UTF-8 character sequence corresponding to the Unicode code. E. g.: <tt>U+000A</tt> is equivalent to <tt>"\n"</tt>.</td>
         
     | 
| 
      
 55 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 56 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 57 
     | 
    
         
            +
                  <td><tt>n</tt> (a number)</td>
         
     | 
| 
      
 58 
     | 
    
         
            +
                  <td>Generate a number</td>
         
     | 
| 
      
 59 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 60 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 61 
     | 
    
         
            +
                  <td><tt>m...n</tt></td>
         
     | 
| 
      
 62 
     | 
    
         
            +
                  <td>Generate a random number between <tt>m</tt> and <tt>n</tt> (inclusive).</td>
         
     | 
| 
      
 63 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 64 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 65 
     | 
    
         
            +
                  <td><tt>nonterm</tt></td>
         
     | 
| 
      
 66 
     | 
    
         
            +
                  <td>–</td>
         
     | 
| 
      
 67 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 68 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 69 
     | 
    
         
            +
                  <td colspan="2"><center><strong>Combinators</strong></center></td>
         
     | 
| 
      
 70 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 71 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 72 
     | 
    
         
            +
                  <td> <tt>expr expr</tt> </td>
         
     | 
| 
      
 73 
     | 
    
         
            +
                  <td>Sequence.</td>
         
     | 
| 
      
 74 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 75 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 76 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 77 
     | 
    
         
            +
                    <tt>expr | expr</tt>
         
     | 
| 
      
 78 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 79 
     | 
    
         
            +
                  <td>Random choice.</td>
         
     | 
| 
      
 80 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 81 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 82 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 83 
     | 
    
         
            +
                    <tt>
         
     | 
| 
      
 84 
     | 
    
         
            +
                      | expr <br/>
         
     | 
| 
      
 85 
     | 
    
         
            +
                      | expr
         
     | 
| 
      
 86 
     | 
    
         
            +
                    </tt>
         
     | 
| 
      
 87 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 88 
     | 
    
         
            +
                  <td>Random choice (another form).</td>
         
     | 
| 
      
 89 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 90 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 91 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 92 
     | 
    
         
            +
                    <tt>
         
     | 
| 
      
 93 
     | 
    
         
            +
                      | [m%] expr <br/>
         
     | 
| 
      
 94 
     | 
    
         
            +
                      | [n%] expr <br/>
         
     | 
| 
      
 95 
     | 
    
         
            +
                      | expr
         
     | 
| 
      
 96 
     | 
    
         
            +
                    </tt>
         
     | 
| 
      
 97 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 98 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 99 
     | 
    
         
            +
                    <p>Random choice with specific probabilities.</p>
         
     | 
| 
      
 100 
     | 
    
         
            +
                    <p>If probability is unspecified then it is calculated automatically.</p>
         
     | 
| 
      
 101 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 102 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 103 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 104 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 105 
     | 
    
         
            +
                    <tt>
         
     | 
| 
      
 106 
     | 
    
         
            +
                      | [0.1] expr <br/>
         
     | 
| 
      
 107 
     | 
    
         
            +
                      | [0.3] expr <br/>
         
     | 
| 
      
 108 
     | 
    
         
            +
                      | expr
         
     | 
| 
      
 109 
     | 
    
         
            +
                    </tt>
         
     | 
| 
      
 110 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 111 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 112 
     | 
    
         
            +
                    The same as above. Probabilities may be specified as floating point numbers between 0.0 and 1.0.
         
     | 
| 
      
 113 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 114 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 115 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 116 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 117 
     | 
    
         
            +
                    <tt>expr*</tt> <br/>
         
     | 
| 
      
 118 
     | 
    
         
            +
                    <tt>expr+</tt> <br/>
         
     | 
| 
      
 119 
     | 
    
         
            +
                    <tt>expr?</tt> <br/>
         
     | 
| 
      
 120 
     | 
    
         
            +
                    <tt>expr*[n]</tt> <br/>
         
     | 
| 
      
 121 
     | 
    
         
            +
                    <tt>expr*[m...n]</tt> <br/>
         
     | 
| 
      
 122 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 123 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 124 
     | 
    
         
            +
                    <p>Repeat <tt>expr</tt> many times:</p>
         
     | 
| 
      
 125 
     | 
    
         
            +
                    <ul>
         
     | 
| 
      
 126 
     | 
    
         
            +
                      <li>0 or more times</li>
         
     | 
| 
      
 127 
     | 
    
         
            +
                      <li>1 or more times</li>
         
     | 
| 
      
 128 
     | 
    
         
            +
                      <li>0 or 1 time</li>
         
     | 
| 
      
 129 
     | 
    
         
            +
                      <li>exactly <tt>n</tt> times</li>
         
     | 
| 
      
 130 
     | 
    
         
            +
                      <li>between <tt>m</tt> and <tt>n</tt> times</li>
         
     | 
| 
      
 131 
     | 
    
         
            +
                    </ul>
         
     | 
| 
      
 132 
     | 
    
         
            +
                    <p><strong>Note:</strong> you may use <tt>inf</tt> ("infinity") instead of <tt>m</tt> or <tt>n</tt>.</p>
         
     | 
| 
      
 133 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 134 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 135 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 136 
     | 
    
         
            +
                  <td colspan="2"><center><strong>Ruby code insertions</strong></center></td>
         
     | 
| 
      
 137 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 138 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 139 
     | 
    
         
            +
                  <td><tt>{ code }</tt></td>
         
     | 
| 
      
 140 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 141 
     | 
    
         
            +
                    <p>Execute the code. Generate nothing.</p>
         
     | 
| 
      
 142 
     | 
    
         
            +
                    <p><strong>Note</strong>: all code insertions inside a rule share the same scope.</p>
         
     | 
| 
      
 143 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 144 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 145 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 146 
     | 
    
         
            +
                  <td><tt>{= code }</tt></td>
         
     | 
| 
      
 147 
     | 
    
         
            +
                  <td>Generate a string returned by the code.</td>
         
     | 
| 
      
 148 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 149 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 150 
     | 
    
         
            +
                  <td><tt>{? code }</tt></td>
         
     | 
| 
      
 151 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 152 
     | 
    
         
            +
                    <p>Condition. A code which must evaluate to true.</p>
         
     | 
| 
      
 153 
     | 
    
         
            +
                    <p><strong>Note</strong>: presence of this expression turns on backtracking and output buffering and may result in enormous memory usage.</p>
         
     | 
| 
      
 154 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 155 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 156 
     | 
    
         
            +
              </tbody>
         
     | 
| 
      
 157 
     | 
    
         
            +
            </table>
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
            TODO: Capture the generated output.
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
            Examples
         
     | 
| 
      
 162 
     | 
    
         
            +
            --------
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
            See them in "sample" directory.
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
            Links
         
     | 
| 
      
 167 
     | 
    
         
            +
            -----
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
            - [Documentation](http://www.rubydoc.info/gems/gen-text/0.0.1)
         
     | 
| 
      
 170 
     | 
    
         
            +
            - [Source code](https://github.com/LavirtheWhiolet/gen-text)
         
     | 
    
        data/bin/gen-text
    ADDED
    
    | 
         @@ -0,0 +1,73 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'gen_text/vm'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'gen_text/compile'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'io/with_dummy_pos'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'stringio'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            def usage
         
     | 
| 
      
 8 
     | 
    
         
            +
              puts <<-TEXT
         
     | 
| 
      
 9 
     | 
    
         
            +
            Usage: #{File.basename __FILE__} [options] [grammar]
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            Reads grammar and generates random text from it.
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            If the grammar file is not specified the the grammar is read from standard
         
     | 
| 
      
 14 
     | 
    
         
            +
            input.
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            Options:
         
     | 
| 
      
 17 
     | 
    
         
            +
                 -h, --help             Show this message and exit.
         
     | 
| 
      
 18 
     | 
    
         
            +
                 -d, --debug            Turn on debug mode.
         
     | 
| 
      
 19 
     | 
    
         
            +
                 -c, --compile          Compile the grammar. Do not generate text.
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            TEXT
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            grammar_file = :'-'
         
     | 
| 
      
 25 
     | 
    
         
            +
            compile_only = false
         
     | 
| 
      
 26 
     | 
    
         
            +
            until ARGV.empty?
         
     | 
| 
      
 27 
     | 
    
         
            +
              case x = ARGV.shift
         
     | 
| 
      
 28 
     | 
    
         
            +
              when "-h", "--help"
         
     | 
| 
      
 29 
     | 
    
         
            +
                usage
         
     | 
| 
      
 30 
     | 
    
         
            +
                exit
         
     | 
| 
      
 31 
     | 
    
         
            +
              when "-d", "--debug"
         
     | 
| 
      
 32 
     | 
    
         
            +
                $DEBUG = true
         
     | 
| 
      
 33 
     | 
    
         
            +
              when "-c", "--compile"
         
     | 
| 
      
 34 
     | 
    
         
            +
                compile_only = true
         
     | 
| 
      
 35 
     | 
    
         
            +
              else
         
     | 
| 
      
 36 
     | 
    
         
            +
                grammar_file = x
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
| 
      
 39 
     | 
    
         
            +
            grammar =
         
     | 
| 
      
 40 
     | 
    
         
            +
              begin
         
     | 
| 
      
 41 
     | 
    
         
            +
                case grammar_file
         
     | 
| 
      
 42 
     | 
    
         
            +
                when :'-' then STDIN.read
         
     | 
| 
      
 43 
     | 
    
         
            +
                else File.read(grammar_file)
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
              rescue IOError => e
         
     | 
| 
      
 46 
     | 
    
         
            +
                abort e.message
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
            program =
         
     | 
| 
      
 49 
     | 
    
         
            +
              begin
         
     | 
| 
      
 50 
     | 
    
         
            +
                GenText::Compile.new.(grammar, grammar_file.to_s)
         
     | 
| 
      
 51 
     | 
    
         
            +
              rescue Parse::Error => e
         
     | 
| 
      
 52 
     | 
    
         
            +
                abort "error: #{e.pos.file}:#{e.pos.line+1}:#{e.pos.column+1}: #{e.message}"
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
            # Optimization: If the program does not cause calling out.pos=(...) then
         
     | 
| 
      
 55 
     | 
    
         
            +
            #   there is no way for GenText::VM to put the garbage after the pos.
         
     | 
| 
      
 56 
     | 
    
         
            +
            buffered, out =
         
     | 
| 
      
 57 
     | 
    
         
            +
              if GenText::VM.may_set_out_pos?(program) then
         
     | 
| 
      
 58 
     | 
    
         
            +
                [true, StringIO.new]
         
     | 
| 
      
 59 
     | 
    
         
            +
              else
         
     | 
| 
      
 60 
     | 
    
         
            +
                [false, IO::WithDummyPos.new(STDOUT)]
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
            begin
         
     | 
| 
      
 63 
     | 
    
         
            +
              srand(Time.now.to_i)
         
     | 
| 
      
 64 
     | 
    
         
            +
              GenText::VM.new.run(program, out, compile_only)
         
     | 
| 
      
 65 
     | 
    
         
            +
            rescue GenText::CheckFailed => e
         
     | 
| 
      
 66 
     | 
    
         
            +
              abort "error: #{e.pos.file}:#{e.pos.line+1}:#{e.pos.column+1}: #{e.message}"
         
     | 
| 
      
 67 
     | 
    
         
            +
            ensure
         
     | 
| 
      
 68 
     | 
    
         
            +
              if buffered then
         
     | 
| 
      
 69 
     | 
    
         
            +
                n = out.pos
         
     | 
| 
      
 70 
     | 
    
         
            +
                out.pos = 0
         
     | 
| 
      
 71 
     | 
    
         
            +
                IO.copy_stream(out, STDOUT, n)
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,547 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'parse'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'gen_text/vm'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module GenText
         
     | 
| 
      
 5 
     | 
    
         
            +
              
         
     | 
| 
      
 6 
     | 
    
         
            +
              class Compile < Parse
         
     | 
| 
      
 7 
     | 
    
         
            +
                
         
     | 
| 
      
 8 
     | 
    
         
            +
                # @param (see Parse#call)
         
     | 
| 
      
 9 
     | 
    
         
            +
                # @return the program as an Array of <code>[:method_id, *args]</code> where
         
     | 
| 
      
 10 
     | 
    
         
            +
                #   <code>method_id</code> is ID of {VM}'s method. The program may raise
         
     | 
| 
      
 11 
     | 
    
         
            +
                #   {CheckFailed}.
         
     | 
| 
      
 12 
     | 
    
         
            +
                def call(*args)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  super(*args).to_vm_code
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
                
         
     | 
| 
      
 16 
     | 
    
         
            +
                private
         
     | 
| 
      
 17 
     | 
    
         
            +
                
         
     | 
| 
      
 18 
     | 
    
         
            +
                # ---- Utils ----
         
     | 
| 
      
 19 
     | 
    
         
            +
                
         
     | 
| 
      
 20 
     | 
    
         
            +
                INF = Float::INFINITY
         
     | 
| 
      
 21 
     | 
    
         
            +
                
         
     | 
| 
      
 22 
     | 
    
         
            +
                # @!visibility private
         
     | 
| 
      
 23 
     | 
    
         
            +
                module ::ASTNode
         
     | 
| 
      
 24 
     | 
    
         
            +
                  
         
     | 
| 
      
 25 
     | 
    
         
            +
                  module_function
         
     | 
| 
      
 26 
     | 
    
         
            +
                  
         
     | 
| 
      
 27 
     | 
    
         
            +
                  # @return [Array<Array<(:generated_from, String)>>]
         
     | 
| 
      
 28 
     | 
    
         
            +
                  def generated_from(pos)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    if $DEBUG then
         
     | 
| 
      
 30 
     | 
    
         
            +
                      [[:generated_from, "#{pos.file}:#{pos.line+1}:#{pos.column+1}"]]
         
     | 
| 
      
 31 
     | 
    
         
            +
                    else
         
     | 
| 
      
 32 
     | 
    
         
            +
                      []
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
                
         
     | 
| 
      
 38 
     | 
    
         
            +
                # ---- AST & Code Generation ----
         
     | 
| 
      
 39 
     | 
    
         
            +
                
         
     | 
| 
      
 40 
     | 
    
         
            +
                # @!visibility private
         
     | 
| 
      
 41 
     | 
    
         
            +
                Context = Struct.new :rule_scope, :rule_labels
         
     | 
| 
      
 42 
     | 
    
         
            +
                
         
     | 
| 
      
 43 
     | 
    
         
            +
                # @!visibility private
         
     | 
| 
      
 44 
     | 
    
         
            +
                class Label
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
      
 47 
     | 
    
         
            +
                Program = ASTNode.new :rules do
         
     | 
| 
      
 48 
     | 
    
         
            +
                  
         
     | 
| 
      
 49 
     | 
    
         
            +
                  def to_vm_code
         
     | 
| 
      
 50 
     | 
    
         
            +
                    rule_labels = {}; begin
         
     | 
| 
      
 51 
     | 
    
         
            +
                      rules.each do |rule|
         
     | 
| 
      
 52 
     | 
    
         
            +
                        raise Parse::Error.new(rule.pos, "rule `#{rule.name}' is defined twice") if rule_labels.has_key? rule.name
         
     | 
| 
      
 53 
     | 
    
         
            +
                        rule_labels[rule.name] = Label.new
         
     | 
| 
      
 54 
     | 
    
         
            +
                      end
         
     | 
| 
      
 55 
     | 
    
         
            +
                    end
         
     | 
| 
      
 56 
     | 
    
         
            +
                    code =
         
     | 
| 
      
 57 
     | 
    
         
            +
                      [
         
     | 
| 
      
 58 
     | 
    
         
            +
                        [:call, rule_labels[rules.first.name]],
         
     | 
| 
      
 59 
     | 
    
         
            +
                        [:halt],
         
     | 
| 
      
 60 
     | 
    
         
            +
                        *rules.map do |rule|
         
     | 
| 
      
 61 
     | 
    
         
            +
                          [
         
     | 
| 
      
 62 
     | 
    
         
            +
                            *generated_from(rule.pos),
         
     | 
| 
      
 63 
     | 
    
         
            +
                            rule_labels[rule.name],
         
     | 
| 
      
 64 
     | 
    
         
            +
                            *rule.body.to_vm_code(Context.new(new_binding, rule_labels)),
         
     | 
| 
      
 65 
     | 
    
         
            +
                            [:ret]
         
     | 
| 
      
 66 
     | 
    
         
            +
                          ]
         
     | 
| 
      
 67 
     | 
    
         
            +
                        end.reduce(:concat)
         
     | 
| 
      
 68 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 69 
     | 
    
         
            +
                    return replace_labels_with_addresses(code)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
                  
         
     | 
| 
      
 72 
     | 
    
         
            +
                  private
         
     | 
| 
      
 73 
     | 
    
         
            +
                  
         
     | 
| 
      
 74 
     | 
    
         
            +
                  # @return [Binding]
         
     | 
| 
      
 75 
     | 
    
         
            +
                  def new_binding
         
     | 
| 
      
 76 
     | 
    
         
            +
                    binding
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
                  
         
     | 
| 
      
 79 
     | 
    
         
            +
                  def replace_labels_with_addresses(code)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    # Remove labels and remember their addresses.
         
     | 
| 
      
 81 
     | 
    
         
            +
                    addresses = {}
         
     | 
| 
      
 82 
     | 
    
         
            +
                    new_code = []
         
     | 
| 
      
 83 
     | 
    
         
            +
                    code.each do |instruction|
         
     | 
| 
      
 84 
     | 
    
         
            +
                      case instruction
         
     | 
| 
      
 85 
     | 
    
         
            +
                      when Label
         
     | 
| 
      
 86 
     | 
    
         
            +
                        addresses[instruction] = new_code.size
         
     | 
| 
      
 87 
     | 
    
         
            +
                      else
         
     | 
| 
      
 88 
     | 
    
         
            +
                        new_code.push instruction
         
     | 
| 
      
 89 
     | 
    
         
            +
                      end
         
     | 
| 
      
 90 
     | 
    
         
            +
                    end
         
     | 
| 
      
 91 
     | 
    
         
            +
                    # Replace labels in instructions' arguments.
         
     | 
| 
      
 92 
     | 
    
         
            +
                    this = lambda do |x|
         
     | 
| 
      
 93 
     | 
    
         
            +
                      case x
         
     | 
| 
      
 94 
     | 
    
         
            +
                      when Array
         
     | 
| 
      
 95 
     | 
    
         
            +
                        x.map(&this)
         
     | 
| 
      
 96 
     | 
    
         
            +
                      when Label
         
     | 
| 
      
 97 
     | 
    
         
            +
                        addresses[x]
         
     | 
| 
      
 98 
     | 
    
         
            +
                      else
         
     | 
| 
      
 99 
     | 
    
         
            +
                        x
         
     | 
| 
      
 100 
     | 
    
         
            +
                      end
         
     | 
| 
      
 101 
     | 
    
         
            +
                    end
         
     | 
| 
      
 102 
     | 
    
         
            +
                    return this.(new_code)
         
     | 
| 
      
 103 
     | 
    
         
            +
                  end
         
     | 
| 
      
 104 
     | 
    
         
            +
                  
         
     | 
| 
      
 105 
     | 
    
         
            +
                end
         
     | 
| 
      
 106 
     | 
    
         
            +
                
         
     | 
| 
      
 107 
     | 
    
         
            +
                GenString = ASTNode.new :string do
         
     | 
| 
      
 108 
     | 
    
         
            +
                  
         
     | 
| 
      
 109 
     | 
    
         
            +
                  def to_vm_code(context)
         
     | 
| 
      
 110 
     | 
    
         
            +
                    [
         
     | 
| 
      
 111 
     | 
    
         
            +
                      *generated_from(pos),
         
     | 
| 
      
 112 
     | 
    
         
            +
                      [:push, string],
         
     | 
| 
      
 113 
     | 
    
         
            +
                      [:gen]
         
     | 
| 
      
 114 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 115 
     | 
    
         
            +
                  end
         
     | 
| 
      
 116 
     | 
    
         
            +
                  
         
     | 
| 
      
 117 
     | 
    
         
            +
                end
         
     | 
| 
      
 118 
     | 
    
         
            +
                
         
     | 
| 
      
 119 
     | 
    
         
            +
                GenNumber = ASTNode.new :from, :to do
         
     | 
| 
      
 120 
     | 
    
         
            +
                  
         
     | 
| 
      
 121 
     | 
    
         
            +
                  def to_vm_code(context)
         
     | 
| 
      
 122 
     | 
    
         
            +
                    [
         
     | 
| 
      
 123 
     | 
    
         
            +
                      *generated_from(pos),
         
     | 
| 
      
 124 
     | 
    
         
            +
                      [:push_rand, from..to],
         
     | 
| 
      
 125 
     | 
    
         
            +
                      [:gen]
         
     | 
| 
      
 126 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 127 
     | 
    
         
            +
                  end
         
     | 
| 
      
 128 
     | 
    
         
            +
                  
         
     | 
| 
      
 129 
     | 
    
         
            +
                end
         
     | 
| 
      
 130 
     | 
    
         
            +
                
         
     | 
| 
      
 131 
     | 
    
         
            +
                Repeat = ASTNode.new :subexpr, :from_times, :to_times do
         
     | 
| 
      
 132 
     | 
    
         
            +
                  
         
     | 
| 
      
 133 
     | 
    
         
            +
                  def to_vm_code(context)
         
     | 
| 
      
 134 
     | 
    
         
            +
                    raise Parse::Error.new(pos, "`from' can not be greater than `to'") if from_times > to_times
         
     | 
| 
      
 135 
     | 
    
         
            +
                    # 
         
     | 
| 
      
 136 
     | 
    
         
            +
                    subexpr_code = subexpr.to_vm_code(context)
         
     | 
| 
      
 137 
     | 
    
         
            +
                    # Code.
         
     | 
| 
      
 138 
     | 
    
         
            +
                    subexpr_label = Label.new
         
     | 
| 
      
 139 
     | 
    
         
            +
                    generated_from(pos) +
         
     | 
| 
      
 140 
     | 
    
         
            +
                    # Mandatory part (0...from_times).
         
     | 
| 
      
 141 
     | 
    
         
            +
                    if from_times > 0
         
     | 
| 
      
 142 
     | 
    
         
            +
                      loop1 = Label.new
         
     | 
| 
      
 143 
     | 
    
         
            +
                      loop1_end = Label.new
         
     | 
| 
      
 144 
     | 
    
         
            +
                      [
         
     | 
| 
      
 145 
     | 
    
         
            +
                        [:push, from_times], # counter
         
     | 
| 
      
 146 
     | 
    
         
            +
                        loop1,
         
     | 
| 
      
 147 
     | 
    
         
            +
                        [:goto_if_not_0, loop1_end], # if counter == 0 then goto loop1_end
         
     | 
| 
      
 148 
     | 
    
         
            +
                        [:call, subexpr_label],
         
     | 
| 
      
 149 
     | 
    
         
            +
                        [:dec], # counter
         
     | 
| 
      
 150 
     | 
    
         
            +
                        [:goto, loop1],
         
     | 
| 
      
 151 
     | 
    
         
            +
                        loop1_end,
         
     | 
| 
      
 152 
     | 
    
         
            +
                        [:pop] # counter
         
     | 
| 
      
 153 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 154 
     | 
    
         
            +
                    else
         
     | 
| 
      
 155 
     | 
    
         
            +
                      []
         
     | 
| 
      
 156 
     | 
    
         
            +
                    end +
         
     | 
| 
      
 157 
     | 
    
         
            +
                    # Optional part (from_times...to_times)
         
     | 
| 
      
 158 
     | 
    
         
            +
                    if (to_times - from_times) == 0
         
     | 
| 
      
 159 
     | 
    
         
            +
                      []
         
     | 
| 
      
 160 
     | 
    
         
            +
                    elsif (to_times - from_times) < INF
         
     | 
| 
      
 161 
     | 
    
         
            +
                      loop2 = Label.new
         
     | 
| 
      
 162 
     | 
    
         
            +
                      loop2_end = Label.new
         
     | 
| 
      
 163 
     | 
    
         
            +
                      [
         
     | 
| 
      
 164 
     | 
    
         
            +
                        [:push_rand, (to_times - from_times + 1)], # counter
         
     | 
| 
      
 165 
     | 
    
         
            +
                        loop2,
         
     | 
| 
      
 166 
     | 
    
         
            +
                        [:goto_if_not_0, loop2_end], # if counter == 0 then goto loop2_end
         
     | 
| 
      
 167 
     | 
    
         
            +
                        [:push_rescue_point, loop2_end],
         
     | 
| 
      
 168 
     | 
    
         
            +
                        [:call, subexpr_label],
         
     | 
| 
      
 169 
     | 
    
         
            +
                        [:pop], # rescue point
         
     | 
| 
      
 170 
     | 
    
         
            +
                        [:dec], # counter
         
     | 
| 
      
 171 
     | 
    
         
            +
                        [:goto, loop2],
         
     | 
| 
      
 172 
     | 
    
         
            +
                        loop2_end,
         
     | 
| 
      
 173 
     | 
    
         
            +
                        [:pop], # counter
         
     | 
| 
      
 174 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 175 
     | 
    
         
            +
                    else # if (to_times - from_times) is infinite
         
     | 
| 
      
 176 
     | 
    
         
            +
                      loop2 = Label.new
         
     | 
| 
      
 177 
     | 
    
         
            +
                      loop2_end = Label.new
         
     | 
| 
      
 178 
     | 
    
         
            +
                      [
         
     | 
| 
      
 179 
     | 
    
         
            +
                        loop2,
         
     | 
| 
      
 180 
     | 
    
         
            +
                        [:goto_if_rand_gt, 0.5, loop2_end],
         
     | 
| 
      
 181 
     | 
    
         
            +
                        [:push_rescue_point],
         
     | 
| 
      
 182 
     | 
    
         
            +
                        [:call, subexpr_label],
         
     | 
| 
      
 183 
     | 
    
         
            +
                        [:pop], # rescue point
         
     | 
| 
      
 184 
     | 
    
         
            +
                        [:goto, loop2],
         
     | 
| 
      
 185 
     | 
    
         
            +
                        loop2_end
         
     | 
| 
      
 186 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 187 
     | 
    
         
            +
                    end +
         
     | 
| 
      
 188 
     | 
    
         
            +
                    # Subexpr as subroutine.
         
     | 
| 
      
 189 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 190 
     | 
    
         
            +
                      after_subexpr = Label.new
         
     | 
| 
      
 191 
     | 
    
         
            +
                      [
         
     | 
| 
      
 192 
     | 
    
         
            +
                        [:goto, after_subexpr],
         
     | 
| 
      
 193 
     | 
    
         
            +
                        subexpr_label,
         
     | 
| 
      
 194 
     | 
    
         
            +
                        *subexpr.to_vm_code(context),
         
     | 
| 
      
 195 
     | 
    
         
            +
                        [:ret],
         
     | 
| 
      
 196 
     | 
    
         
            +
                        after_subexpr
         
     | 
| 
      
 197 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 198 
     | 
    
         
            +
                    end
         
     | 
| 
      
 199 
     | 
    
         
            +
                  end
         
     | 
| 
      
 200 
     | 
    
         
            +
                  
         
     | 
| 
      
 201 
     | 
    
         
            +
                end
         
     | 
| 
      
 202 
     | 
    
         
            +
                
         
     | 
| 
      
 203 
     | 
    
         
            +
                GenCode = ASTNode.new :to_s do
         
     | 
| 
      
 204 
     | 
    
         
            +
                  
         
     | 
| 
      
 205 
     | 
    
         
            +
                  def to_vm_code(context)
         
     | 
| 
      
 206 
     | 
    
         
            +
                    [
         
     | 
| 
      
 207 
     | 
    
         
            +
                      *generated_from(pos),
         
     | 
| 
      
 208 
     | 
    
         
            +
                      [:eval_ruby_code, context.rule_scope, self.to_s, pos.file, pos.line+1],
         
     | 
| 
      
 209 
     | 
    
         
            +
                      [:gen]
         
     | 
| 
      
 210 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 211 
     | 
    
         
            +
                  end
         
     | 
| 
      
 212 
     | 
    
         
            +
                  
         
     | 
| 
      
 213 
     | 
    
         
            +
                end
         
     | 
| 
      
 214 
     | 
    
         
            +
                
         
     | 
| 
      
 215 
     | 
    
         
            +
                CheckCode = ASTNode.new :to_s do
         
     | 
| 
      
 216 
     | 
    
         
            +
                  
         
     | 
| 
      
 217 
     | 
    
         
            +
                  def to_vm_code(context)
         
     | 
| 
      
 218 
     | 
    
         
            +
                    passed = Label.new
         
     | 
| 
      
 219 
     | 
    
         
            +
                    [
         
     | 
| 
      
 220 
     | 
    
         
            +
                      *generated_from(pos),
         
     | 
| 
      
 221 
     | 
    
         
            +
                      [:eval_ruby_code, context.rule_scope, self.to_s, pos.file, pos.line+1],
         
     | 
| 
      
 222 
     | 
    
         
            +
                      [:goto_if, passed],
         
     | 
| 
      
 223 
     | 
    
         
            +
                      [:rescue_, lambda { raise CheckFailed.new(pos) }],
         
     | 
| 
      
 224 
     | 
    
         
            +
                      passed
         
     | 
| 
      
 225 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 226 
     | 
    
         
            +
                  end
         
     | 
| 
      
 227 
     | 
    
         
            +
                  
         
     | 
| 
      
 228 
     | 
    
         
            +
                end
         
     | 
| 
      
 229 
     | 
    
         
            +
                
         
     | 
| 
      
 230 
     | 
    
         
            +
                ActionCode = ASTNode.new :to_s do
         
     | 
| 
      
 231 
     | 
    
         
            +
                  
         
     | 
| 
      
 232 
     | 
    
         
            +
                  def to_vm_code(context)
         
     | 
| 
      
 233 
     | 
    
         
            +
                    [
         
     | 
| 
      
 234 
     | 
    
         
            +
                      *generated_from(pos),
         
     | 
| 
      
 235 
     | 
    
         
            +
                      [:eval_ruby_code, context.rule_scope, self.to_s, pos.file, pos.line+1],
         
     | 
| 
      
 236 
     | 
    
         
            +
                      [:pop]
         
     | 
| 
      
 237 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 238 
     | 
    
         
            +
                  end
         
     | 
| 
      
 239 
     | 
    
         
            +
                  
         
     | 
| 
      
 240 
     | 
    
         
            +
                end
         
     | 
| 
      
 241 
     | 
    
         
            +
                
         
     | 
| 
      
 242 
     | 
    
         
            +
                RuleCall = ASTNode.new :name do
         
     | 
| 
      
 243 
     | 
    
         
            +
                  
         
     | 
| 
      
 244 
     | 
    
         
            +
                  def to_vm_code(context)
         
     | 
| 
      
 245 
     | 
    
         
            +
                    [
         
     | 
| 
      
 246 
     | 
    
         
            +
                      *generated_from(pos),
         
     | 
| 
      
 247 
     | 
    
         
            +
                      [:call, (context.rule_labels[name] or raise Parse::Error.new(pos, "rule `#{name}' not defined"))]
         
     | 
| 
      
 248 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 249 
     | 
    
         
            +
                  end
         
     | 
| 
      
 250 
     | 
    
         
            +
                  
         
     | 
| 
      
 251 
     | 
    
         
            +
                end
         
     | 
| 
      
 252 
     | 
    
         
            +
                
         
     | 
| 
      
 253 
     | 
    
         
            +
                Choice = ASTNode.new :alternatives do
         
     | 
| 
      
 254 
     | 
    
         
            +
                  
         
     | 
| 
      
 255 
     | 
    
         
            +
                  def to_vm_code(context)
         
     | 
| 
      
 256 
     | 
    
         
            +
                    # Populate alternatives' weights.
         
     | 
| 
      
 257 
     | 
    
         
            +
                    if alternatives.map(&:probability).all? { |x| x == :auto } then
         
     | 
| 
      
 258 
     | 
    
         
            +
                      alternatives.each { |a| a.weight = 1 }
         
     | 
| 
      
 259 
     | 
    
         
            +
                    else
         
     | 
| 
      
 260 
     | 
    
         
            +
                      known_probabilities_sum =
         
     | 
| 
      
 261 
     | 
    
         
            +
                        alternatives.map(&:probability).reject { |x| x == :auto }.reduce(:+)
         
     | 
| 
      
 262 
     | 
    
         
            +
                      raise Parse::Error.new(pos, "probabilities sum exceed 100%") if known_probabilities_sum > 1.00 + 0.0001
         
     | 
| 
      
 263 
     | 
    
         
            +
                      auto_probability =
         
     | 
| 
      
 264 
     | 
    
         
            +
                        (1.00 - known_probabilities_sum) / alternatives.map(&:probability).select { |x| x == :auto }.size
         
     | 
| 
      
 265 
     | 
    
         
            +
                      alternatives.each do |alternative|
         
     | 
| 
      
 266 
     | 
    
         
            +
                        alternative.weight =
         
     | 
| 
      
 267 
     | 
    
         
            +
                          if alternative.probability == :auto then
         
     | 
| 
      
 268 
     | 
    
         
            +
                            auto_probability
         
     | 
| 
      
 269 
     | 
    
         
            +
                          else
         
     | 
| 
      
 270 
     | 
    
         
            +
                            alternative.probability
         
     | 
| 
      
 271 
     | 
    
         
            +
                          end
         
     | 
| 
      
 272 
     | 
    
         
            +
                      end
         
     | 
| 
      
 273 
     | 
    
         
            +
                    end
         
     | 
| 
      
 274 
     | 
    
         
            +
                    # Populate alternatives' labels.
         
     | 
| 
      
 275 
     | 
    
         
            +
                    alternatives.each { |a| a.label = Label.new }
         
     | 
| 
      
 276 
     | 
    
         
            +
                    # Generate the code.
         
     | 
| 
      
 277 
     | 
    
         
            +
                    initial_weights_and_labels = alternatives.map { |a| [a.weight, a.label] }
         
     | 
| 
      
 278 
     | 
    
         
            +
                    end_label = Label.new
         
     | 
| 
      
 279 
     | 
    
         
            +
                    [
         
     | 
| 
      
 280 
     | 
    
         
            +
                      *generated_from(pos),
         
     | 
| 
      
 281 
     | 
    
         
            +
                      [:push_dup, initial_weights_and_labels],
         
     | 
| 
      
 282 
     | 
    
         
            +
                      [:weighed_choice],
         
     | 
| 
      
 283 
     | 
    
         
            +
                      *alternatives.map do |alternative|
         
     | 
| 
      
 284 
     | 
    
         
            +
                        [
         
     | 
| 
      
 285 
     | 
    
         
            +
                          alternative.label,
         
     | 
| 
      
 286 
     | 
    
         
            +
                          *alternative.subexpr.to_vm_code(context),
         
     | 
| 
      
 287 
     | 
    
         
            +
                          [:goto, end_label],
         
     | 
| 
      
 288 
     | 
    
         
            +
                        ]
         
     | 
| 
      
 289 
     | 
    
         
            +
                      end.reduce(:concat),
         
     | 
| 
      
 290 
     | 
    
         
            +
                      end_label,
         
     | 
| 
      
 291 
     | 
    
         
            +
                      [:pop], # rescue_point
         
     | 
| 
      
 292 
     | 
    
         
            +
                      [:pop], # weights_and_labels
         
     | 
| 
      
 293 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 294 
     | 
    
         
            +
                  end
         
     | 
| 
      
 295 
     | 
    
         
            +
                  
         
     | 
| 
      
 296 
     | 
    
         
            +
                end
         
     | 
| 
      
 297 
     | 
    
         
            +
                
         
     | 
| 
      
 298 
     | 
    
         
            +
                ChoiceAlternative = ASTNode.new :probability, :subexpr do
         
     | 
| 
      
 299 
     | 
    
         
            +
                  
         
     | 
| 
      
 300 
     | 
    
         
            +
                  # Used by {Choice#to_vm_code} only.
         
     | 
| 
      
 301 
     | 
    
         
            +
                  # @return [Numeric]
         
     | 
| 
      
 302 
     | 
    
         
            +
                  attr_accessor :weight
         
     | 
| 
      
 303 
     | 
    
         
            +
                  
         
     | 
| 
      
 304 
     | 
    
         
            +
                  # Used by {Choice#to_vm_code} only.
         
     | 
| 
      
 305 
     | 
    
         
            +
                  # @return [Label]
         
     | 
| 
      
 306 
     | 
    
         
            +
                  attr_accessor :label
         
     | 
| 
      
 307 
     | 
    
         
            +
                  
         
     | 
| 
      
 308 
     | 
    
         
            +
                end
         
     | 
| 
      
 309 
     | 
    
         
            +
                
         
     | 
| 
      
 310 
     | 
    
         
            +
                Seq = ASTNode.new :subexprs do
         
     | 
| 
      
 311 
     | 
    
         
            +
                  
         
     | 
| 
      
 312 
     | 
    
         
            +
                  def to_vm_code(context)
         
     | 
| 
      
 313 
     | 
    
         
            +
                    generated_from(pos) +
         
     | 
| 
      
 314 
     | 
    
         
            +
                      subexprs.map { |subexpr| subexpr.to_vm_code(context) }.reduce(:concat)
         
     | 
| 
      
 315 
     | 
    
         
            +
                  end
         
     | 
| 
      
 316 
     | 
    
         
            +
                  
         
     | 
| 
      
 317 
     | 
    
         
            +
                end
         
     | 
| 
      
 318 
     | 
    
         
            +
                
         
     | 
| 
      
 319 
     | 
    
         
            +
                RuleDefinition = ASTNode.new :name, :body
         
     | 
| 
      
 320 
     | 
    
         
            +
                
         
     | 
| 
      
 321 
     | 
    
         
            +
                # ---- Syntax ----
         
     | 
| 
      
 322 
     | 
    
         
            +
                
         
     | 
| 
      
 323 
     | 
    
         
            +
                rule :start do
         
     | 
| 
      
 324 
     | 
    
         
            +
                  whitespace_and_comments and
         
     | 
| 
      
 325 
     | 
    
         
            +
                  rules = many { rule_definition } and
         
     | 
| 
      
 326 
     | 
    
         
            +
                  _(Program[rules])
         
     | 
| 
      
 327 
     | 
    
         
            +
                end
         
     | 
| 
      
 328 
     | 
    
         
            +
                
         
     | 
| 
      
 329 
     | 
    
         
            +
                rule :expr do
         
     | 
| 
      
 330 
     | 
    
         
            +
                  choice
         
     | 
| 
      
 331 
     | 
    
         
            +
                end
         
     | 
| 
      
 332 
     | 
    
         
            +
                
         
     | 
| 
      
 333 
     | 
    
         
            +
                rule :choice do
         
     | 
| 
      
 334 
     | 
    
         
            +
                  first = true
         
     | 
| 
      
 335 
     | 
    
         
            +
                  as = one_or_more {
         
     | 
| 
      
 336 
     | 
    
         
            +
                    p = choice_alternative_start(first) and s = seq and
         
     | 
| 
      
 337 
     | 
    
         
            +
                    act { first = false } and
         
     | 
| 
      
 338 
     | 
    
         
            +
                    _(ChoiceAlternative[p, s])
         
     | 
| 
      
 339 
     | 
    
         
            +
                  } and
         
     | 
| 
      
 340 
     | 
    
         
            +
                  if as.size == 1 then
         
     | 
| 
      
 341 
     | 
    
         
            +
                    as.first.subexpr
         
     | 
| 
      
 342 
     | 
    
         
            +
                  else
         
     | 
| 
      
 343 
     | 
    
         
            +
                    _(Choice[as])
         
     | 
| 
      
 344 
     | 
    
         
            +
                  end
         
     | 
| 
      
 345 
     | 
    
         
            +
                end
         
     | 
| 
      
 346 
     | 
    
         
            +
                
         
     | 
| 
      
 347 
     | 
    
         
            +
                # Returns probability or :auto.
         
     | 
| 
      
 348 
     | 
    
         
            +
                def choice_alternative_start(first)
         
     | 
| 
      
 349 
     | 
    
         
            +
                  _{
         
     | 
| 
      
 350 
     | 
    
         
            +
                    (_{ slash } or _{ pipe }) and
         
     | 
| 
      
 351 
     | 
    
         
            +
                    probability = (
         
     | 
| 
      
 352 
     | 
    
         
            +
                      _{
         
     | 
| 
      
 353 
     | 
    
         
            +
                        lbracket and
         
     | 
| 
      
 354 
     | 
    
         
            +
                        x = ufloat and opt { percent and act { x /= 100.0 } } and
         
     | 
| 
      
 355 
     | 
    
         
            +
                        rbracket and
         
     | 
| 
      
 356 
     | 
    
         
            +
                        x
         
     | 
| 
      
 357 
     | 
    
         
            +
                      } or
         
     | 
| 
      
 358 
     | 
    
         
            +
                      :auto
         
     | 
| 
      
 359 
     | 
    
         
            +
                    )
         
     | 
| 
      
 360 
     | 
    
         
            +
                  } or
         
     | 
| 
      
 361 
     | 
    
         
            +
                  (if first then :auto else nil end)
         
     | 
| 
      
 362 
     | 
    
         
            +
                end
         
     | 
| 
      
 363 
     | 
    
         
            +
                
         
     | 
| 
      
 364 
     | 
    
         
            +
                rule :seq do
         
     | 
| 
      
 365 
     | 
    
         
            +
                  e = repeat and many {
         
     | 
| 
      
 366 
     | 
    
         
            +
                    e2 = repeat and e = _(Seq[to_seq_subexprs(e) + to_seq_subexprs(e2)])
         
     | 
| 
      
 367 
     | 
    
         
            +
                  } and
         
     | 
| 
      
 368 
     | 
    
         
            +
                  e
         
     | 
| 
      
 369 
     | 
    
         
            +
                end
         
     | 
| 
      
 370 
     | 
    
         
            +
                
         
     | 
| 
      
 371 
     | 
    
         
            +
                def to_seq_subexprs(e)
         
     | 
| 
      
 372 
     | 
    
         
            +
                  case e
         
     | 
| 
      
 373 
     | 
    
         
            +
                  when Seq then e.subexprs
         
     | 
| 
      
 374 
     | 
    
         
            +
                  else [e]
         
     | 
| 
      
 375 
     | 
    
         
            +
                  end
         
     | 
| 
      
 376 
     | 
    
         
            +
                end
         
     | 
| 
      
 377 
     | 
    
         
            +
                
         
     | 
| 
      
 378 
     | 
    
         
            +
                rule :repeat do
         
     | 
| 
      
 379 
     | 
    
         
            +
                  e = primary and many {
         
     | 
| 
      
 380 
     | 
    
         
            +
                    _{
         
     | 
| 
      
 381 
     | 
    
         
            +
                      asterisk and
         
     | 
| 
      
 382 
     | 
    
         
            +
                      from = 0 and to = INF and
         
     | 
| 
      
 383 
     | 
    
         
            +
                      opt {
         
     | 
| 
      
 384 
     | 
    
         
            +
                        lbracket and
         
     | 
| 
      
 385 
     | 
    
         
            +
                        n = times and act { from = n and to = n } and
         
     | 
| 
      
 386 
     | 
    
         
            +
                        opt {
         
     | 
| 
      
 387 
     | 
    
         
            +
                          ellipsis and
         
     | 
| 
      
 388 
     | 
    
         
            +
                          n = times and act { to = n }
         
     | 
| 
      
 389 
     | 
    
         
            +
                        } and
         
     | 
| 
      
 390 
     | 
    
         
            +
                        rbracket
         
     | 
| 
      
 391 
     | 
    
         
            +
                      } and
         
     | 
| 
      
 392 
     | 
    
         
            +
                      e = _(Repeat[e, from, to]) } or
         
     | 
| 
      
 393 
     | 
    
         
            +
                    _{ question and e = _(Repeat[e, 0, 1]) } or
         
     | 
| 
      
 394 
     | 
    
         
            +
                    _{ plus and e = _(Repeat[e, 1, INF]) }
         
     | 
| 
      
 395 
     | 
    
         
            +
                  } and
         
     | 
| 
      
 396 
     | 
    
         
            +
                  e
         
     | 
| 
      
 397 
     | 
    
         
            +
                end
         
     | 
| 
      
 398 
     | 
    
         
            +
                
         
     | 
| 
      
 399 
     | 
    
         
            +
                def times
         
     | 
| 
      
 400 
     | 
    
         
            +
                  _{ uint } or
         
     | 
| 
      
 401 
     | 
    
         
            +
                  _{ inf and INF }
         
     | 
| 
      
 402 
     | 
    
         
            +
                end
         
     | 
| 
      
 403 
     | 
    
         
            +
                
         
     | 
| 
      
 404 
     | 
    
         
            +
                rule :primary do
         
     | 
| 
      
 405 
     | 
    
         
            +
                  _{ s = string and _(GenString[s]) } or
         
     | 
| 
      
 406 
     | 
    
         
            +
                  _{ c = code("{=") and _(GenCode[c]) } or
         
     | 
| 
      
 407 
     | 
    
         
            +
                  _{ c = code("{?") and _(CheckCode[c]) } or
         
     | 
| 
      
 408 
     | 
    
         
            +
                  _{ action_code } or
         
     | 
| 
      
 409 
     | 
    
         
            +
                  _{ n = nonterm and not_follows(:eq) and _(RuleCall[n]) } or
         
     | 
| 
      
 410 
     | 
    
         
            +
                  _{ gen_number } or
         
     | 
| 
      
 411 
     | 
    
         
            +
                  _{ lparen and e = expr and rparen and e }
         
     | 
| 
      
 412 
     | 
    
         
            +
                end
         
     | 
| 
      
 413 
     | 
    
         
            +
                
         
     | 
| 
      
 414 
     | 
    
         
            +
                def gen_number
         
     | 
| 
      
 415 
     | 
    
         
            +
                  n1 = number and n2 = opt { ellipsis and number } and
         
     | 
| 
      
 416 
     | 
    
         
            +
                  act { n2 = (n2.first or n1) } and
         
     | 
| 
      
 417 
     | 
    
         
            +
                  _(GenNumber[n1, n2])
         
     | 
| 
      
 418 
     | 
    
         
            +
                end
         
     | 
| 
      
 419 
     | 
    
         
            +
                
         
     | 
| 
      
 420 
     | 
    
         
            +
                rule :action_code do
         
     | 
| 
      
 421 
     | 
    
         
            +
                  c = code("{") and _(ActionCode[c])
         
     | 
| 
      
 422 
     | 
    
         
            +
                end
         
     | 
| 
      
 423 
     | 
    
         
            +
                
         
     | 
| 
      
 424 
     | 
    
         
            +
                rule :rule_definition do
         
     | 
| 
      
 425 
     | 
    
         
            +
                  n = nonterm and (_{eq} or _{larrow}) and e = choice and semicolon and
         
     | 
| 
      
 426 
     | 
    
         
            +
                  _(RuleDefinition[n, e])
         
     | 
| 
      
 427 
     | 
    
         
            +
                end
         
     | 
| 
      
 428 
     | 
    
         
            +
                
         
     | 
| 
      
 429 
     | 
    
         
            +
                # ---- Tokens ----
         
     | 
| 
      
 430 
     | 
    
         
            +
                
         
     | 
| 
      
 431 
     | 
    
         
            +
                token :inf, "inf"
         
     | 
| 
      
 432 
     | 
    
         
            +
                token :asterisk, "*"
         
     | 
| 
      
 433 
     | 
    
         
            +
                token :question, "?"
         
     | 
| 
      
 434 
     | 
    
         
            +
                token :plus, "+"
         
     | 
| 
      
 435 
     | 
    
         
            +
                token :pipe, "|"
         
     | 
| 
      
 436 
     | 
    
         
            +
                token :slash, "/"
         
     | 
| 
      
 437 
     | 
    
         
            +
                token :eq, "="
         
     | 
| 
      
 438 
     | 
    
         
            +
                token :semicolon, ";"
         
     | 
| 
      
 439 
     | 
    
         
            +
                token :percent, "%"
         
     | 
| 
      
 440 
     | 
    
         
            +
                token :ellipsis, "..."
         
     | 
| 
      
 441 
     | 
    
         
            +
                token :lbrace, "{"
         
     | 
| 
      
 442 
     | 
    
         
            +
                token :rbrace, "}"
         
     | 
| 
      
 443 
     | 
    
         
            +
                token :lparen, "("
         
     | 
| 
      
 444 
     | 
    
         
            +
                token :rparen, ")"
         
     | 
| 
      
 445 
     | 
    
         
            +
                token :lbracket, "["
         
     | 
| 
      
 446 
     | 
    
         
            +
                token :rbracket, "]"
         
     | 
| 
      
 447 
     | 
    
         
            +
                token :dot, "."
         
     | 
| 
      
 448 
     | 
    
         
            +
                token :larrow, "<-"
         
     | 
| 
      
 449 
     | 
    
         
            +
                
         
     | 
| 
      
 450 
     | 
    
         
            +
                # Parses "#{start} #{code_part} } #{whitespace_and_comments}".
         
     | 
| 
      
 451 
     | 
    
         
            +
                # Returns the code_part.
         
     | 
| 
      
 452 
     | 
    
         
            +
                def code(start)
         
     | 
| 
      
 453 
     | 
    
         
            +
                  p = pos and
         
     | 
| 
      
 454 
     | 
    
         
            +
                  scan(start) and c = code_part and
         
     | 
| 
      
 455 
     | 
    
         
            +
                  (rbrace or raise Expected.new(p, "`}' at the end")) and
         
     | 
| 
      
 456 
     | 
    
         
            +
                  c
         
     | 
| 
      
 457 
     | 
    
         
            +
                end
         
     | 
| 
      
 458 
     | 
    
         
            +
                
         
     | 
| 
      
 459 
     | 
    
         
            +
                rule :code_part do
         
     | 
| 
      
 460 
     | 
    
         
            +
                  many {
         
     | 
| 
      
 461 
     | 
    
         
            +
                    _{ scan(/\\./) } or
         
     | 
| 
      
 462 
     | 
    
         
            +
                    _{ scan(/[^{}]+/) } or
         
     | 
| 
      
 463 
     | 
    
         
            +
                    _{
         
     | 
| 
      
 464 
     | 
    
         
            +
                      pp = pos and
         
     | 
| 
      
 465 
     | 
    
         
            +
                      p1 = scan("{") and p2 = code_part and
         
     | 
| 
      
 466 
     | 
    
         
            +
                      (p3 = scan("}") or raise Expected.new(pp, "`}' at the end")) and
         
     | 
| 
      
 467 
     | 
    
         
            +
                      p1 + p2 + p3
         
     | 
| 
      
 468 
     | 
    
         
            +
                    }
         
     | 
| 
      
 469 
     | 
    
         
            +
                  }.join
         
     | 
| 
      
 470 
     | 
    
         
            +
                end
         
     | 
| 
      
 471 
     | 
    
         
            +
                
         
     | 
| 
      
 472 
     | 
    
         
            +
                token :string do
         
     | 
| 
      
 473 
     | 
    
         
            +
                  _{ string0('"') } or
         
     | 
| 
      
 474 
     | 
    
         
            +
                  _{ string0("'") } or
         
     | 
| 
      
 475 
     | 
    
         
            +
                  _{ scan("U+") and c = scan(/\h+/) and [c.hex].pack("U") }
         
     | 
| 
      
 476 
     | 
    
         
            +
                end
         
     | 
| 
      
 477 
     | 
    
         
            +
                
         
     | 
| 
      
 478 
     | 
    
         
            +
                def string0(quote)
         
     | 
| 
      
 479 
     | 
    
         
            +
                  p = pos and scan(quote) and
         
     | 
| 
      
 480 
     | 
    
         
            +
                  s = many {
         
     | 
| 
      
 481 
     | 
    
         
            +
                    _{ scan(/\\n/) and "\n" } or
         
     | 
| 
      
 482 
     | 
    
         
            +
                    _{ scan(/\\t/) and "\t" } or
         
     | 
| 
      
 483 
     | 
    
         
            +
                    _{ scan(/\\e/) and "\e" } or
         
     | 
| 
      
 484 
     | 
    
         
            +
                    _{ scan(/\\./) } or
         
     | 
| 
      
 485 
     | 
    
         
            +
                    scan(/[^#{quote}]/)
         
     | 
| 
      
 486 
     | 
    
         
            +
                  }.join and
         
     | 
| 
      
 487 
     | 
    
         
            +
                  (scan(quote) or raise Expected.new(p, "`#{quote}' at the end")) and s
         
     | 
| 
      
 488 
     | 
    
         
            +
                end
         
     | 
| 
      
 489 
     | 
    
         
            +
                
         
     | 
| 
      
 490 
     | 
    
         
            +
                token :nonterm do
         
     | 
| 
      
 491 
     | 
    
         
            +
                  _{ scan(/`.*?`/) } or
         
     | 
| 
      
 492 
     | 
    
         
            +
                  _{ scan(/[[:alpha:]_:][[:alnum:]\-_:]*/) }
         
     | 
| 
      
 493 
     | 
    
         
            +
                end
         
     | 
| 
      
 494 
     | 
    
         
            +
                
         
     | 
| 
      
 495 
     | 
    
         
            +
                token :int, "integer number" do
         
     | 
| 
      
 496 
     | 
    
         
            +
                  n = number and n.is_a? Integer and n
         
     | 
| 
      
 497 
     | 
    
         
            +
                end
         
     | 
| 
      
 498 
     | 
    
         
            +
                
         
     | 
| 
      
 499 
     | 
    
         
            +
                token :uint, "non-negative integer number" do
         
     | 
| 
      
 500 
     | 
    
         
            +
                  n = int and n >= 0 and n
         
     | 
| 
      
 501 
     | 
    
         
            +
                end
         
     | 
| 
      
 502 
     | 
    
         
            +
                
         
     | 
| 
      
 503 
     | 
    
         
            +
                token :number do
         
     | 
| 
      
 504 
     | 
    
         
            +
                  s = scan(/[\-\+]?\d+(\.\d+)?([eE][\-\+]?\d+)?/) and
         
     | 
| 
      
 505 
     | 
    
         
            +
                  if /[\.eE]/ === s then
         
     | 
| 
      
 506 
     | 
    
         
            +
                    Float(s)
         
     | 
| 
      
 507 
     | 
    
         
            +
                  else
         
     | 
| 
      
 508 
     | 
    
         
            +
                    Integer(s)
         
     | 
| 
      
 509 
     | 
    
         
            +
                  end
         
     | 
| 
      
 510 
     | 
    
         
            +
                end
         
     | 
| 
      
 511 
     | 
    
         
            +
                
         
     | 
| 
      
 512 
     | 
    
         
            +
                token :float, "floating point number" do
         
     | 
| 
      
 513 
     | 
    
         
            +
                  number
         
     | 
| 
      
 514 
     | 
    
         
            +
                end
         
     | 
| 
      
 515 
     | 
    
         
            +
                
         
     | 
| 
      
 516 
     | 
    
         
            +
                token :ufloat, "non-negative floating point number" do
         
     | 
| 
      
 517 
     | 
    
         
            +
                  n = number and n >= 0 and n
         
     | 
| 
      
 518 
     | 
    
         
            +
                end
         
     | 
| 
      
 519 
     | 
    
         
            +
                
         
     | 
| 
      
 520 
     | 
    
         
            +
                def whitespace_and_comments
         
     | 
| 
      
 521 
     | 
    
         
            +
                  many {
         
     | 
| 
      
 522 
     | 
    
         
            +
                    _{ scan(/\s+/) } or
         
     | 
| 
      
 523 
     | 
    
         
            +
                    _{ scan("//") and scan(/[^\n]*\n/m) } or
         
     | 
| 
      
 524 
     | 
    
         
            +
                    _{
         
     | 
| 
      
 525 
     | 
    
         
            +
                      p = pos and scan("/*") and
         
     | 
| 
      
 526 
     | 
    
         
            +
                      many { not_follows { scan("*/") } and scan(/./m) } and
         
     | 
| 
      
 527 
     | 
    
         
            +
                      (scan("*/") or raise Expected.new(p, "`*/' at the end"))
         
     | 
| 
      
 528 
     | 
    
         
            +
                    }
         
     | 
| 
      
 529 
     | 
    
         
            +
                  }
         
     | 
| 
      
 530 
     | 
    
         
            +
                end
         
     | 
| 
      
 531 
     | 
    
         
            +
                
         
     | 
| 
      
 532 
     | 
    
         
            +
              end
         
     | 
| 
      
 533 
     | 
    
         
            +
              
         
     | 
| 
      
 534 
     | 
    
         
            +
              class CheckFailed < Exception
         
     | 
| 
      
 535 
     | 
    
         
            +
                
         
     | 
| 
      
 536 
     | 
    
         
            +
                # @param [Parse::Position] pos
         
     | 
| 
      
 537 
     | 
    
         
            +
                def initialize(pos)
         
     | 
| 
      
 538 
     | 
    
         
            +
                  super("check failed")
         
     | 
| 
      
 539 
     | 
    
         
            +
                  @pos = pos
         
     | 
| 
      
 540 
     | 
    
         
            +
                end
         
     | 
| 
      
 541 
     | 
    
         
            +
                
         
     | 
| 
      
 542 
     | 
    
         
            +
                # @return [Parse::Position] pos
         
     | 
| 
      
 543 
     | 
    
         
            +
                attr_reader :pos
         
     | 
| 
      
 544 
     | 
    
         
            +
                
         
     | 
| 
      
 545 
     | 
    
         
            +
              end
         
     | 
| 
      
 546 
     | 
    
         
            +
              
         
     | 
| 
      
 547 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/gen_text/vm.rb
    ADDED
    
    | 
         @@ -0,0 +1,269 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            module GenText
         
     | 
| 
      
 3 
     | 
    
         
            +
              
         
     | 
| 
      
 4 
     | 
    
         
            +
              class VM
         
     | 
| 
      
 5 
     | 
    
         
            +
                
         
     | 
| 
      
 6 
     | 
    
         
            +
                # @param program Array of <code>[:method_id, *args]</code>.
         
     | 
| 
      
 7 
     | 
    
         
            +
                # @return [Boolean] true if +program+ may result in calling
         
     | 
| 
      
 8 
     | 
    
         
            +
                #   {IO#pos=} and false otherwise.
         
     | 
| 
      
 9 
     | 
    
         
            +
                def self.may_set_out_pos?(program)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  program.any? { |instruction| instruction.first == :rescue_ }
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
                
         
     | 
| 
      
 13 
     | 
    
         
            +
                # Executes +program+.
         
     | 
| 
      
 14 
     | 
    
         
            +
                # 
         
     | 
| 
      
 15 
     | 
    
         
            +
                # After the execution the +out+ may contain garbage after its {IO#pos}.
         
     | 
| 
      
 16 
     | 
    
         
            +
                # It is up to the caller to truncate the garbage or to copy the useful data.
         
     | 
| 
      
 17 
     | 
    
         
            +
                # 
         
     | 
| 
      
 18 
     | 
    
         
            +
                # @param program Array of <code>[:method_id, *args]</code>.
         
     | 
| 
      
 19 
     | 
    
         
            +
                # @param [IO] out
         
     | 
| 
      
 20 
     | 
    
         
            +
                # @param [Boolean] do_not_run if true then +program+ will not be run
         
     | 
| 
      
 21 
     | 
    
         
            +
                #   (some checks and initializations will be performed only).
         
     | 
| 
      
 22 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 23 
     | 
    
         
            +
                def run(program, out, do_not_run = false)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  # 
         
     | 
| 
      
 25 
     | 
    
         
            +
                  if $DEBUG
         
     | 
| 
      
 26 
     | 
    
         
            +
                    STDERR.puts "PROGRAM:"
         
     | 
| 
      
 27 
     | 
    
         
            +
                    program.each_with_index do |instruction, addr|
         
     | 
| 
      
 28 
     | 
    
         
            +
                      STDERR.puts "  #{addr}: #{inspect_instruction(instruction)}"
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                  #
         
     | 
| 
      
 32 
     | 
    
         
            +
                  return if do_not_run
         
     | 
| 
      
 33 
     | 
    
         
            +
                  # Init.
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @stack = []
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @out = out
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @pc = 0
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @halted = false
         
     | 
| 
      
 38 
     | 
    
         
            +
                  # Run.
         
     | 
| 
      
 39 
     | 
    
         
            +
                  STDERR.puts "RUN TRACE:" if $DEBUG
         
     | 
| 
      
 40 
     | 
    
         
            +
                  until halted?
         
     | 
| 
      
 41 
     | 
    
         
            +
                    instruction = program[@pc]
         
     | 
| 
      
 42 
     | 
    
         
            +
                    method_id, *args = *instruction
         
     | 
| 
      
 43 
     | 
    
         
            +
                    STDERR.puts "  #{@pc}: #{inspect_instruction(instruction)}" if $DEBUG
         
     | 
| 
      
 44 
     | 
    
         
            +
                    self.__send__(method_id, *args)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    if $DEBUG then
         
     | 
| 
      
 46 
     | 
    
         
            +
                      STDERR.puts "    PC: #{@pc}"
         
     | 
| 
      
 47 
     | 
    
         
            +
                      STDERR.puts "    STACK: #{@stack.inspect}"
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
                
         
     | 
| 
      
 52 
     | 
    
         
            +
                # @return [Integer]
         
     | 
| 
      
 53 
     | 
    
         
            +
                attr_reader :pc
         
     | 
| 
      
 54 
     | 
    
         
            +
                
         
     | 
| 
      
 55 
     | 
    
         
            +
                # @return [IO]
         
     | 
| 
      
 56 
     | 
    
         
            +
                attr_reader :out
         
     | 
| 
      
 57 
     | 
    
         
            +
                
         
     | 
| 
      
 58 
     | 
    
         
            +
                # @return [Boolean]
         
     | 
| 
      
 59 
     | 
    
         
            +
                def halted?
         
     | 
| 
      
 60 
     | 
    
         
            +
                  @halted
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
                
         
     | 
| 
      
 63 
     | 
    
         
            +
                # Sets {#halted?} to true.
         
     | 
| 
      
 64 
     | 
    
         
            +
                # 
         
     | 
| 
      
 65 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 66 
     | 
    
         
            +
                def halt
         
     | 
| 
      
 67 
     | 
    
         
            +
                  @halted = true
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
                
         
     | 
| 
      
 70 
     | 
    
         
            +
                # NOP
         
     | 
| 
      
 71 
     | 
    
         
            +
                # 
         
     | 
| 
      
 72 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 73 
     | 
    
         
            +
                def generated_from(*args)
         
     | 
| 
      
 74 
     | 
    
         
            +
                  @pc += 1
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
                
         
     | 
| 
      
 77 
     | 
    
         
            +
                # Pushes +o+ to the stack.
         
     | 
| 
      
 78 
     | 
    
         
            +
                # 
         
     | 
| 
      
 79 
     | 
    
         
            +
                # @param [Object] o
         
     | 
| 
      
 80 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 81 
     | 
    
         
            +
                def push(o)
         
     | 
| 
      
 82 
     | 
    
         
            +
                  @stack.push o
         
     | 
| 
      
 83 
     | 
    
         
            +
                  @pc += 1
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
                
         
     | 
| 
      
 86 
     | 
    
         
            +
                # {#push}(o.dup)
         
     | 
| 
      
 87 
     | 
    
         
            +
                # 
         
     | 
| 
      
 88 
     | 
    
         
            +
                # @param [Object] o
         
     | 
| 
      
 89 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 90 
     | 
    
         
            +
                def push_dup(o)
         
     | 
| 
      
 91 
     | 
    
         
            +
                  push(o.dup)
         
     | 
| 
      
 92 
     | 
    
         
            +
                end
         
     | 
| 
      
 93 
     | 
    
         
            +
                
         
     | 
| 
      
 94 
     | 
    
         
            +
                # {#push}(rand(+r+) if +r+ is specified; rand() otherwise)
         
     | 
| 
      
 95 
     | 
    
         
            +
                # 
         
     | 
| 
      
 96 
     | 
    
         
            +
                # @param [Object, nil] r
         
     | 
| 
      
 97 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 98 
     | 
    
         
            +
                def push_rand(r = nil)
         
     | 
| 
      
 99 
     | 
    
         
            +
                  push(if r then rand(r) else rand end)
         
     | 
| 
      
 100 
     | 
    
         
            +
                end
         
     | 
| 
      
 101 
     | 
    
         
            +
                
         
     | 
| 
      
 102 
     | 
    
         
            +
                # Pops the value from the stack.
         
     | 
| 
      
 103 
     | 
    
         
            +
                # 
         
     | 
| 
      
 104 
     | 
    
         
            +
                # @return [Object] the popped value.
         
     | 
| 
      
 105 
     | 
    
         
            +
                def pop
         
     | 
| 
      
 106 
     | 
    
         
            +
                  @stack.pop
         
     | 
| 
      
 107 
     | 
    
         
            +
                  @pc += 1
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
                
         
     | 
| 
      
 110 
     | 
    
         
            +
                # If {#pop} is true then {#pc} := +addr+.
         
     | 
| 
      
 111 
     | 
    
         
            +
                # 
         
     | 
| 
      
 112 
     | 
    
         
            +
                # @param [Integer] addr
         
     | 
| 
      
 113 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 114 
     | 
    
         
            +
                def goto_if(addr)
         
     | 
| 
      
 115 
     | 
    
         
            +
                  if @stack.pop then
         
     | 
| 
      
 116 
     | 
    
         
            +
                    @pc = addr
         
     | 
| 
      
 117 
     | 
    
         
            +
                  else
         
     | 
| 
      
 118 
     | 
    
         
            +
                    @pc += 1
         
     | 
| 
      
 119 
     | 
    
         
            +
                  end
         
     | 
| 
      
 120 
     | 
    
         
            +
                end
         
     | 
| 
      
 121 
     | 
    
         
            +
                
         
     | 
| 
      
 122 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 123 
     | 
    
         
            +
                def dec
         
     | 
| 
      
 124 
     | 
    
         
            +
                  @stack[-1] -= 1
         
     | 
| 
      
 125 
     | 
    
         
            +
                  @pc += 1
         
     | 
| 
      
 126 
     | 
    
         
            +
                end
         
     | 
| 
      
 127 
     | 
    
         
            +
                
         
     | 
| 
      
 128 
     | 
    
         
            +
                # If the value on the stack != 0 then {#goto}(+addr).
         
     | 
| 
      
 129 
     | 
    
         
            +
                # 
         
     | 
| 
      
 130 
     | 
    
         
            +
                # @param [Integer] addr
         
     | 
| 
      
 131 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 132 
     | 
    
         
            +
                def goto_if_not_0(addr)
         
     | 
| 
      
 133 
     | 
    
         
            +
                  if @stack.last != 0 then
         
     | 
| 
      
 134 
     | 
    
         
            +
                    @pc += 1
         
     | 
| 
      
 135 
     | 
    
         
            +
                  else
         
     | 
| 
      
 136 
     | 
    
         
            +
                    @pc = addr
         
     | 
| 
      
 137 
     | 
    
         
            +
                  end
         
     | 
| 
      
 138 
     | 
    
         
            +
                end
         
     | 
| 
      
 139 
     | 
    
         
            +
                
         
     | 
| 
      
 140 
     | 
    
         
            +
                # If rand > +v+ then {#goto}(addr)
         
     | 
| 
      
 141 
     | 
    
         
            +
                # 
         
     | 
| 
      
 142 
     | 
    
         
            +
                # @param [Numeric] v
         
     | 
| 
      
 143 
     | 
    
         
            +
                # @param [Integer] addr
         
     | 
| 
      
 144 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 145 
     | 
    
         
            +
                # 
         
     | 
| 
      
 146 
     | 
    
         
            +
                def goto_if_rand_gt(v, addr)
         
     | 
| 
      
 147 
     | 
    
         
            +
                  if rand > v then
         
     | 
| 
      
 148 
     | 
    
         
            +
                    @pc = addr
         
     | 
| 
      
 149 
     | 
    
         
            +
                  else
         
     | 
| 
      
 150 
     | 
    
         
            +
                    @pc += 1
         
     | 
| 
      
 151 
     | 
    
         
            +
                  end
         
     | 
| 
      
 152 
     | 
    
         
            +
                end
         
     | 
| 
      
 153 
     | 
    
         
            +
                
         
     | 
| 
      
 154 
     | 
    
         
            +
                # @param [Integer] addr
         
     | 
| 
      
 155 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 156 
     | 
    
         
            +
                def goto(addr)
         
     | 
| 
      
 157 
     | 
    
         
            +
                  @pc = addr
         
     | 
| 
      
 158 
     | 
    
         
            +
                end
         
     | 
| 
      
 159 
     | 
    
         
            +
                
         
     | 
| 
      
 160 
     | 
    
         
            +
                # Writes {#pop} to {#out}.
         
     | 
| 
      
 161 
     | 
    
         
            +
                # 
         
     | 
| 
      
 162 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 163 
     | 
    
         
            +
                def gen
         
     | 
| 
      
 164 
     | 
    
         
            +
                  @out.write @stack.pop
         
     | 
| 
      
 165 
     | 
    
         
            +
                  @pc += 1
         
     | 
| 
      
 166 
     | 
    
         
            +
                end
         
     | 
| 
      
 167 
     | 
    
         
            +
                
         
     | 
| 
      
 168 
     | 
    
         
            +
                # {#push}(eval(+ruby_code+, +file+, +line+))
         
     | 
| 
      
 169 
     | 
    
         
            +
                # 
         
     | 
| 
      
 170 
     | 
    
         
            +
                # @param [Binding] binding_
         
     | 
| 
      
 171 
     | 
    
         
            +
                # @param [String] ruby_code
         
     | 
| 
      
 172 
     | 
    
         
            +
                # @param [String] file original file of +ruby_code+.
         
     | 
| 
      
 173 
     | 
    
         
            +
                # @param [Integer] line original line of +ruby_code+.
         
     | 
| 
      
 174 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 175 
     | 
    
         
            +
                def eval_ruby_code(binding_, ruby_code, file, line)
         
     | 
| 
      
 176 
     | 
    
         
            +
                  @stack.push binding_.eval(ruby_code, file, line)
         
     | 
| 
      
 177 
     | 
    
         
            +
                  @pc += 1
         
     | 
| 
      
 178 
     | 
    
         
            +
                end
         
     | 
| 
      
 179 
     | 
    
         
            +
                
         
     | 
| 
      
 180 
     | 
    
         
            +
                # {#push}({#out}'s {IO#pos} and {#pc} as {RescuePoint})
         
     | 
| 
      
 181 
     | 
    
         
            +
                # 
         
     | 
| 
      
 182 
     | 
    
         
            +
                # @param [Integer, nil] pc if specified then it is pushed instead of {#pc}.
         
     | 
| 
      
 183 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 184 
     | 
    
         
            +
                def push_rescue_point(pc = nil)
         
     | 
| 
      
 185 
     | 
    
         
            +
                  @stack.push RescuePoint[(pc or @pc), @out.pos]
         
     | 
| 
      
 186 
     | 
    
         
            +
                  @pc += 1
         
     | 
| 
      
 187 
     | 
    
         
            +
                end
         
     | 
| 
      
 188 
     | 
    
         
            +
                
         
     | 
| 
      
 189 
     | 
    
         
            +
                # {#pop}s until a {RescuePoint} is found then restore {#out} and {#pc} from
         
     | 
| 
      
 190 
     | 
    
         
            +
                # the {RescuePoint}.
         
     | 
| 
      
 191 
     | 
    
         
            +
                # 
         
     | 
| 
      
 192 
     | 
    
         
            +
                # @param [Proc] on_failure is called if no {RescuePoint} is found
         
     | 
| 
      
 193 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 194 
     | 
    
         
            +
                def rescue_(on_failure)
         
     | 
| 
      
 195 
     | 
    
         
            +
                  @stack.pop until @stack.empty? or @stack.last.is_a? RescuePoint
         
     | 
| 
      
 196 
     | 
    
         
            +
                  if @stack.empty? then
         
     | 
| 
      
 197 
     | 
    
         
            +
                    on_failure.()
         
     | 
| 
      
 198 
     | 
    
         
            +
                  else
         
     | 
| 
      
 199 
     | 
    
         
            +
                    rescue_point = @stack.pop
         
     | 
| 
      
 200 
     | 
    
         
            +
                    @pc = rescue_point.pc
         
     | 
| 
      
 201 
     | 
    
         
            +
                    @out.pos = rescue_point.out_pos
         
     | 
| 
      
 202 
     | 
    
         
            +
                  end
         
     | 
| 
      
 203 
     | 
    
         
            +
                end
         
     | 
| 
      
 204 
     | 
    
         
            +
                
         
     | 
| 
      
 205 
     | 
    
         
            +
                # @param [Integer] addr
         
     | 
| 
      
 206 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 207 
     | 
    
         
            +
                def call(addr)
         
     | 
| 
      
 208 
     | 
    
         
            +
                  @stack.push(@pc + 1)
         
     | 
| 
      
 209 
     | 
    
         
            +
                  @pc = addr
         
     | 
| 
      
 210 
     | 
    
         
            +
                end
         
     | 
| 
      
 211 
     | 
    
         
            +
                
         
     | 
| 
      
 212 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 213 
     | 
    
         
            +
                def ret
         
     | 
| 
      
 214 
     | 
    
         
            +
                  @pc = @stack.pop
         
     | 
| 
      
 215 
     | 
    
         
            +
                end
         
     | 
| 
      
 216 
     | 
    
         
            +
                
         
     | 
| 
      
 217 
     | 
    
         
            +
                # Let stack contains +wa+ = [[weight1, address1], [weight2, address2], ...].
         
     | 
| 
      
 218 
     | 
    
         
            +
                # This function:
         
     | 
| 
      
 219 
     | 
    
         
            +
                # 
         
     | 
| 
      
 220 
     | 
    
         
            +
                # 1. Picks a random address from +wa+ (the more weight the
         
     | 
| 
      
 221 
     | 
    
         
            +
                #    address has, the more often it is picked);
         
     | 
| 
      
 222 
     | 
    
         
            +
                # 2. Deletes the chosen address from +wa+;
         
     | 
| 
      
 223 
     | 
    
         
            +
                # 3. If there was the only address in +wa+ then it does {#push}(nil);
         
     | 
| 
      
 224 
     | 
    
         
            +
                #    otherwise it does {#push_rescue_point};
         
     | 
| 
      
 225 
     | 
    
         
            +
                # 4. {#goto}(the chosen address).
         
     | 
| 
      
 226 
     | 
    
         
            +
                # 
         
     | 
| 
      
 227 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 228 
     | 
    
         
            +
                def weighed_choice
         
     | 
| 
      
 229 
     | 
    
         
            +
                  weights_and_addresses = @stack.last
         
     | 
| 
      
 230 
     | 
    
         
            +
                  # If no alternatives left...
         
     | 
| 
      
 231 
     | 
    
         
            +
                  if weights_and_addresses.size == 1 then
         
     | 
| 
      
 232 
     | 
    
         
            +
                    _, address = *weights_and_addresses.first
         
     | 
| 
      
 233 
     | 
    
         
            +
                    @stack.push nil
         
     | 
| 
      
 234 
     | 
    
         
            +
                    @pc = address
         
     | 
| 
      
 235 
     | 
    
         
            +
                  # If there are alternatives...
         
     | 
| 
      
 236 
     | 
    
         
            +
                  else
         
     | 
| 
      
 237 
     | 
    
         
            +
                    chosen_weight_and_address = sample_weighed(weights_and_addresses)
         
     | 
| 
      
 238 
     | 
    
         
            +
                    weights_and_addresses.delete chosen_weight_and_address
         
     | 
| 
      
 239 
     | 
    
         
            +
                    _, chosen_address = *chosen_weight_and_address
         
     | 
| 
      
 240 
     | 
    
         
            +
                    push_rescue_point
         
     | 
| 
      
 241 
     | 
    
         
            +
                    @pc = chosen_address
         
     | 
| 
      
 242 
     | 
    
         
            +
                  end
         
     | 
| 
      
 243 
     | 
    
         
            +
                end
         
     | 
| 
      
 244 
     | 
    
         
            +
                
         
     | 
| 
      
 245 
     | 
    
         
            +
                RescuePoint = Struct.new :pc, :out_pos
         
     | 
| 
      
 246 
     | 
    
         
            +
                
         
     | 
| 
      
 247 
     | 
    
         
            +
                private
         
     | 
| 
      
 248 
     | 
    
         
            +
                
         
     | 
| 
      
 249 
     | 
    
         
            +
                # @param [Array<Array<(Numeric, Object)>>] weights_and_items
         
     | 
| 
      
 250 
     | 
    
         
            +
                # @return [Array<(Numeric, Object)>]
         
     | 
| 
      
 251 
     | 
    
         
            +
                def sample_weighed(weights_and_items)
         
     | 
| 
      
 252 
     | 
    
         
            +
                  weight_sum = weights_and_items.map(&:first).reduce(:+)
         
     | 
| 
      
 253 
     | 
    
         
            +
                  chosen_partial_weight_sum = rand(0...weight_sum)
         
     | 
| 
      
 254 
     | 
    
         
            +
                  current_partial_weight_sum = 0
         
     | 
| 
      
 255 
     | 
    
         
            +
                  weights_and_items.find do |weight, item|
         
     | 
| 
      
 256 
     | 
    
         
            +
                    current_partial_weight_sum += weight
         
     | 
| 
      
 257 
     | 
    
         
            +
                    current_partial_weight_sum > chosen_partial_weight_sum
         
     | 
| 
      
 258 
     | 
    
         
            +
                  end or
         
     | 
| 
      
 259 
     | 
    
         
            +
                  weights_and_items.last
         
     | 
| 
      
 260 
     | 
    
         
            +
                end
         
     | 
| 
      
 261 
     | 
    
         
            +
                
         
     | 
| 
      
 262 
     | 
    
         
            +
                def inspect_instruction(instruction)
         
     | 
| 
      
 263 
     | 
    
         
            +
                  method_id, *args = *instruction
         
     | 
| 
      
 264 
     | 
    
         
            +
                  "#{method_id} #{args.map(&:inspect).join(", ")}"
         
     | 
| 
      
 265 
     | 
    
         
            +
                end
         
     | 
| 
      
 266 
     | 
    
         
            +
                
         
     | 
| 
      
 267 
     | 
    
         
            +
              end
         
     | 
| 
      
 268 
     | 
    
         
            +
              
         
     | 
| 
      
 269 
     | 
    
         
            +
            end
         
     | 
    
        data/yardopts_extra.rb
    ADDED
    
    
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,75 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: gen-text
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.0.2
         
     | 
| 
      
 5 
     | 
    
         
            +
              prerelease: 
         
     | 
| 
      
 6 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 7 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 8 
     | 
    
         
            +
            - Lavir the Whiolet
         
     | 
| 
      
 9 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 10 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 11 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2016-06-24 00:00:00.000000000 Z
         
     | 
| 
      
 13 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 14 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 15 
     | 
    
         
            +
              name: parse-framework
         
     | 
| 
      
 16 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 17 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 18 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 19 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 20 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 21 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 22 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 23 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 24 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 25 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 26 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 27 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 28 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 29 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 30 
     | 
    
         
            +
            description: ! 'A generator of texts from EBNF-like grammars. It features probability
         
     | 
| 
      
 31 
     | 
    
         
            +
              management, code insertions and conditional generation with conditions written in
         
     | 
| 
      
 32 
     | 
    
         
            +
              Ruby.
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            '
         
     | 
| 
      
 35 
     | 
    
         
            +
            email: Lavir.th.Whiolet@gmail.com
         
     | 
| 
      
 36 
     | 
    
         
            +
            executables:
         
     | 
| 
      
 37 
     | 
    
         
            +
            - gen-text
         
     | 
| 
      
 38 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 39 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 40 
     | 
    
         
            +
            files:
         
     | 
| 
      
 41 
     | 
    
         
            +
            - lib/gen_text/vm.rb
         
     | 
| 
      
 42 
     | 
    
         
            +
            - lib/gen_text/compile.rb
         
     | 
| 
      
 43 
     | 
    
         
            +
            - lib/io/with_dummy_pos.rb
         
     | 
| 
      
 44 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 45 
     | 
    
         
            +
            - LICENSE
         
     | 
| 
      
 46 
     | 
    
         
            +
            - .yardopts
         
     | 
| 
      
 47 
     | 
    
         
            +
            - yardopts_extra.rb
         
     | 
| 
      
 48 
     | 
    
         
            +
            - bin/gen-text
         
     | 
| 
      
 49 
     | 
    
         
            +
            homepage: http://lavirthewhiolet.github.io/gen-text
         
     | 
| 
      
 50 
     | 
    
         
            +
            licenses:
         
     | 
| 
      
 51 
     | 
    
         
            +
            - MIT
         
     | 
| 
      
 52 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 53 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 54 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 55 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 56 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 57 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 58 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 59 
     | 
    
         
            +
              - - ! '>='
         
     | 
| 
      
 60 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 61 
     | 
    
         
            +
                  version: 1.9.3
         
     | 
| 
      
 62 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 63 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 64 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 65 
     | 
    
         
            +
              - - ! '>='
         
     | 
| 
      
 66 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 67 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 68 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 69 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 70 
     | 
    
         
            +
            rubygems_version: 1.8.23
         
     | 
| 
      
 71 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 72 
     | 
    
         
            +
            specification_version: 3
         
     | 
| 
      
 73 
     | 
    
         
            +
            summary: A generator of texts from EBNF-like grammars.
         
     | 
| 
      
 74 
     | 
    
         
            +
            test_files: []
         
     | 
| 
      
 75 
     | 
    
         
            +
            has_rdoc: 
         
     |