Module: Antelope::Ace::Scanner::Second

Included in:
Antelope::Ace::Scanner
Defined in:
lib/antelope/ace/scanner/second.rb

Overview

Scans the second part of the file. The second part of the file only contains productions (or rules). Rules have a label and a body; the label may be any lowercase alphabetical identifier followed by a colon; the body consists of "parts", an "or", a "prec", and/or a "block". The part may consist of any alphabetical characters. An or is just a vertical bar (|). A prec is a precedence declaraction, which is %prec followed by any alphabetical characters. A block is a {, followed by code, followed by a terminating }. Rules may be terminated by a semicolon, but this is optional.

Instance Method Summary collapse

Instance Method Details

#_scan_blockString (private)

Scans the block; it scans until it encounters enough closing brackets to match the opening brackets. If it encounters an opening brackets, it increments the bracket counter by one; if it encounters a closing bracket, it decrements by one. It will error if it reaches the end before the brackets are fully closed.

Returns:

  • (String)

    the block's body.

Raises:

  • (SyntaxError)

    if it reaches the end before the final bracket is closed.



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/antelope/ace/scanner/second.rb', line 140

def _scan_block
  brack = 1
  body = "{"
  scan_for = %r{
    (
      (?: " ( \\\\ | \\" | [^"] )* "? )
    | (?: ' ( \\\\ | \\' | [^'] )* '? )
    | (?: // .*? \n )
    | (?: \# .*? \n )
    | (?: /\* [\s\S]+? \*/ )
    | (?: \} )
    | (?: \{ )
    )
  }x

  until brack.zero?
    if part = @scanner.scan_until(scan_for)
      body << part


      if @scanner[1] == "}"
        brack -= 1
      elsif @scanner[1] == "{"
        brack += 1
      end
    else
      if @scanner.scan(/(.+)/m)
        @line += @scanner[1].count("\n")
      end
      error!
    end
  end

  body
end

#scan_second_partvoid

This method returns an undefined value.

Scans the second part of the file. This should be from just before the first content boundry; if the scanner doesn't find a content boundry, it will error. It will then check for a rule.

Raises:

  • (SyntaxError)

    if no content boundry was found, or if the scanner encounters anything but a rule or whitespace.

See Also:



30
31
32
33
34
35
36
37
38
# File 'lib/antelope/ace/scanner/second.rb', line 30

def scan_second_part
  scanner.scan(CONTENT_BOUNDRY) or error!
  tokens << [:second]

  until @scanner.check(CONTENT_BOUNDRY)
    scan_second_rule || scan_whitespace || scan_comment ||
    error!
  end
end

#scan_second_ruleBoolean

Scans a rule. A rule consists of a label (the nonterminal the production is for), a body, and a block; and then, an optional semicolon.

Returns:

  • (Boolean)

    if it matched

See Also:



48
49
50
51
52
53
54
# File 'lib/antelope/ace/scanner/second.rb', line 48

def scan_second_rule
  if @scanner.check(/(#{IDENTIFIER})(\[#{IDENTIFIER}\])?:/)
    scan_second_rule_label or error!
    scan_second_rule_body
    true
  end
end

#scan_second_rule_blockBoolean

Attempts to scan a block. This correctly balances brackets; however, if a bracket is opened/closed within a string, it still counts that as a bracket that needs to be balanced. So, having extensive code within a block is not a good idea.

Returns:

  • (Boolean)

    if it matched.



122
123
124
125
126
# File 'lib/antelope/ace/scanner/second.rb', line 122

def scan_second_rule_block
  if @scanner.scan(/\{/)
    tokens << [:block, _scan_block]
  end
end

#scan_second_rule_bodyvoid

This method returns an undefined value.

The body can contain parts, ors, precs, or blocks (or whitespaces). Scans all of them, and then attempts to scan a semicolon.



76
77
78
79
80
81
82
83
84
# File 'lib/antelope/ace/scanner/second.rb', line 76

def scan_second_rule_body
  body = true
  while body
    scan_second_rule_prec || scan_second_rule_part ||
    scan_second_rule_or ||  scan_second_rule_block ||
    scan_whitespace || scan_comment || (body = false)
  end
  @scanner.scan(/;/)
end

#scan_second_rule_labelBoolean

Scans the label for a rule. It should contain only lower case letters and a colon.

Returns:

  • (Boolean)

    if it matched.



60
61
62
63
64
# File 'lib/antelope/ace/scanner/second.rb', line 60

def scan_second_rule_label
  if @scanner.scan(/(#{IDENTIFIER})(?:\[(#{IDENTIFIER})\])?: ?/)
    tokens << [:label, @scanner[1], @scanner[2]]
  end
end

#scan_second_rule_orBoolean

Attempts to scan an "or". It's just a vertical bar.

Returns:

  • (Boolean)

    if it matched.



100
101
102
103
104
# File 'lib/antelope/ace/scanner/second.rb', line 100

def scan_second_rule_or
  if @scanner.scan(/\|/)
    tokens << [:or]
  end
end

#scan_second_rule_partBoolean

Attempts to scan a "part". A part is any series of alphabetical characters that are not followed by a colon.

Returns:

  • (Boolean)

    if it matched.



91
92
93
94
95
# File 'lib/antelope/ace/scanner/second.rb', line 91

def scan_second_rule_part
  if @scanner.scan(/(%?#{IDENTIFIER})(?:\[(#{IDENTIFIER})\])?(?!\:|[A-Za-z._])/)
    tokens << [:part, @scanner[1], @scanner[2]]
  end
end

#scan_second_rule_precBoolean

Attempts to scan a precedence definition. A precedence definition is "%prec " followed by a terminal or nonterminal.

Returns:

  • (Boolean)

    if it matched.



110
111
112
113
114
# File 'lib/antelope/ace/scanner/second.rb', line 110

def scan_second_rule_prec
  if @scanner.scan(/%prec (#{IDENTIFIER})/)
    tokens << [:prec, @scanner[1]]
  end
end