lib/citrus/file.rb in citrus-2.2.2 vs lib/citrus/file.rb in citrus-2.3.0
- old
+ new
@@ -26,38 +26,40 @@
## Hierarchical syntax
rule :file do
all(:space, zero_or_more(any(:require, :grammar))) {
- find(:require).each {|r| require r.value }
- find(:grammar).map {|g| g.value }
+ if captures[:require]
+ captures[:require].each {|r| require r.value }
+ end
+
+ (captures[:grammar] || []).map {|g| g.value }
}
end
rule :grammar do
- all(:grammar_keyword, :module_name, :grammar_body, :end_keyword) {
+ mod all(:grammar_keyword, :module_name, :grammar_body, :end_keyword) do
include ModuleNameHelpers
def value
module_namespace.const_set(module_basename, grammar_body.value)
end
- }
+ end
end
rule :grammar_body do
zero_or_more(any(:include, :root, :rule)) {
grammar = Grammar.new
- find(:include).map do |inc|
- grammar.include(inc.value)
+ if captures[:include]
+ captures[:include].each {|inc| grammar.include(inc.value) }
end
- root = find(:root).last
grammar.root(root.value) if root
- find(:rule).each do |r|
- grammar.rule(r.rule_name.value, r.value)
+ if captures[:rule]
+ captures[:rule].each {|r| grammar.rule(r.rule_name.value, r.value) }
end
grammar
}
end
@@ -69,101 +71,110 @@
end
rule :rule_body do
zero_or_one(:choice) {
# An empty rule definition matches the empty string.
- matches.length > 0 ? choice.value : Rule.new('')
+ choice ? choice.value : Rule.for('')
}
end
rule :choice do
- all(:sequence, zero_or_more([ :bar, :sequence ])) {
+ mod all(:sequence, zero_or_more([ :bar, :sequence ])) do
def rules
- @rules ||= begin
- [ sequence.value ] + matches[1].matches.map do |m|
- m.matches[1].value
- end
- end
+ @rules ||= captures[:sequence].map {|s| s.value }
end
def value
rules.length > 1 ? Choice.new(rules) : rules.first
end
- }
+ end
end
rule :sequence do
- one_or_more(:expression) {
+ mod one_or_more(:label_expression) do
def rules
- @rules ||= matches.map {|m| m.value }
+ @rules ||= captures[:label_expression].map {|e| e.value }
end
def value
rules.length > 1 ? Sequence.new(rules) : rules.first
end
+ end
+ end
+
+ rule :label_expression do
+ all(zero_or_one(:label), :expression) {
+ rule = expression.value
+ rule.label = label.value if label
+ rule
}
end
rule :expression do
all(:prefix, zero_or_one(:extension)) {
rule = prefix.value
- extension = matches[1].first
rule.extension = extension.value if extension
rule
}
end
rule :prefix do
all(zero_or_one(:predicate), :suffix) {
rule = suffix.value
- predicate = matches[0].first
rule = predicate.value(rule) if predicate
rule
}
end
rule :suffix do
all(:primary, zero_or_one(:repeat)) {
rule = primary.value
- repeat = matches[1].first
rule = repeat.value(rule) if repeat
rule
}
end
rule :primary do
- any(:grouping, :proxy, :string_terminal, :terminal)
+ any(:grouping, :proxy, :terminal)
end
rule :grouping do
- all(:lparen, :rule_body, :rparen) { rule_body.value }
+ all(:lparen, :rule_body, :rparen) {
+ rule_body.value
+ }
end
## Lexical syntax
rule :require do
- all(:require_keyword, :quoted_string) { quoted_string.value }
+ all(:require_keyword, :quoted_string) {
+ quoted_string.value
+ }
end
rule :include do
- all(:include_keyword, :module_name) {
+ mod all(:include_keyword, :module_name) do
include ModuleNameHelpers
def value
module_namespace.const_get(module_basename)
end
- }
+ end
end
rule :root do
- all(:root_keyword, :rule_name) { rule_name.value }
+ all(:root_keyword, :rule_name) {
+ rule_name.value
+ }
end
# Rule names may contain letters, numbers, underscores, and dashes. They
# MUST start with a letter.
rule :rule_name do
- all(/[a-zA-Z][a-zA-Z0-9_-]*/, :space) { first.to_s }
+ all(/[a-zA-Z][a-zA-Z0-9_-]*/, :space) {
+ first.to_s
+ }
end
rule :proxy do
any(:super, :alias)
end
@@ -178,86 +189,98 @@
all(notp(:end_keyword), :rule_name) {
Alias.new(rule_name.value)
}
end
+ rule :terminal do
+ any(:string_terminal, :regular_expression, :character_class, :dot)
+ end
+
rule :string_terminal do
any(:quoted_string, :case_insensitive_string) {
StringTerminal.new(super(), flags)
}
end
rule :quoted_string do
- all(/(["'])(?:\\?.)*?\1/, :space) {
+ mod all(/(["'])(?:\\?.)*?\1/, :space) do
def value
- eval(first)
+ eval(first.to_s)
end
def flags
0
end
- }
+ end
end
rule :case_insensitive_string do
- all(/`(?:\\?.)*?`/, :space) {
+ mod all(/`(?:\\?.)*?`/, :space) do
def value
- eval(first.gsub(/^`|`$/, '"'))
+ eval(first.to_s.gsub(/^`|`$/, '"'))
end
def flags
Regexp::IGNORECASE
end
- }
+ end
end
- rule :terminal do
- any(:regular_expression, :character_class, :dot) {
- Terminal.new(super())
- }
- end
-
rule :regular_expression do
all(/\/(?:\\?.)*?\/[imxouesn]*/, :space) {
- eval(first)
+ Terminal.new(eval(first.to_s))
}
end
rule :character_class do
all(/\[(?:\\?.)*?\]/, :space) {
- Regexp.new('\A' + first, nil, 'n')
+ Terminal.new(Regexp.new(first.to_s, nil, 'n'))
}
end
rule :dot do
all('.', :space) {
- DOT
+ Terminal.new(DOT)
}
end
+ rule :label do
+ all(/[a-zA-Z0-9_]+/, :space, ':', :space) {
+ first.to_sym
+ }
+ end
+
rule :extension do
any(:tag, :block)
end
rule :tag do
- all(:lt, :module_name, :gt) {
+ mod all(:lt, :module_name, :gt) do
include ModuleNameHelpers
def value
module_namespace.const_get(module_basename)
end
- }
+ end
end
rule :block do
all(:lcurly, zero_or_more(any(:block, /[^{}]+/)), :rcurly) {
- eval('Proc.new ' + to_s, TOPLEVEL_BINDING)
+ proc = eval("Proc.new #{to_s}", TOPLEVEL_BINDING)
+
+ # Attempt to detect if this is a module block using some
+ # extremely simple heuristics.
+ if to_s =~ /\b(def|include) /
+ Module.new(&proc)
+ else
+ proc
+ end
}
end
rule :predicate do
- any(:and, :not, :but, :label)
+ any(:and, :not, :but)
end
rule :and do
all('&', :space) { |rule|
AndPredicate.new(rule)
@@ -274,44 +297,30 @@
all('~', :space) { |rule|
ButPredicate.new(rule)
}
end
- rule :label do
- all(/[a-zA-Z0-9_]+/, :space, ':', :space) { |rule|
- Label.new(rule, first.to_s)
- }
- end
-
rule :repeat do
- any(:question, :plus, :star) { |rule|
- Repeat.new(rule, min, max)
- }
+ any(:question, :plus, :star)
end
rule :question do
- all('?', :space) {
- def min; 0 end
- def max; 1 end
+ all('?', :space) { |rule|
+ Repeat.new(rule, 0, 1)
}
end
rule :plus do
- all('+', :space) {
- def min; 1 end
- def max; Infinity end
+ all('+', :space) { |rule|
+ Repeat.new(rule, 1, Infinity)
}
end
rule :star do
- all(/[0-9]*/, '*', /[0-9]*/, :space) {
- def min
- matches[0] == '' ? 0 : matches[0].to_i
- end
-
- def max
- matches[2] == '' ? Infinity : matches[2].to_i
- end
+ all(/[0-9]*/, '*', /[0-9]*/, :space) { |rule|
+ min = captures[0] == '' ? 0 : captures[0].to_i
+ max = captures[2] == '' ? Infinity : captures[2].to_i
+ Repeat.new(rule, min, max)
}
end
rule :module_name do
all(one_or_more([ zero_or_one('::'), :constant ]), :space) {