lib/citrus/file.rb in citrus-2.3.2 vs lib/citrus/file.rb in citrus-2.3.3

- old
+ new

@@ -1,5 +1,7 @@ +# encoding: UTF-8 + require 'citrus' module Citrus # Some helper methods for rules that alias +module_name+ and don't want to # use +Kernel#eval+ to retrieve Module objects. @@ -7,11 +9,11 @@ def module_segments @module_segments ||= module_name.value.split('::') end def module_namespace - module_segments[0..-2].inject(Object) do |namespace, constant| + module_segments[0...-1].inject(Object) do |namespace, constant| constant.empty? ? namespace : namespace.const_get(constant) end end def module_basename @@ -26,92 +28,75 @@ ## Hierarchical syntax rule :file do all(:space, zero_or_more(any(:require, :grammar))) { - if captures[:require] - captures[:require].each {|r| require r.value } + captures[:require].each do |req| + file = req.value + begin + require file + rescue ::LoadError => e + begin + Citrus.require(file) + rescue LoadError + # Re-raise the original LoadError. + raise e + end + end end - (captures[:grammar] || []).map {|g| g.value } + captures[:grammar].map {|g| g.value } } end rule :grammar do - mod all(:grammar_keyword, :module_name, :grammar_body, :end_keyword) do + mod all(:grammar_keyword, :module_name, zero_or_more(any(:include, :root, :rule)), :end_keyword) do include ModuleNameHelpers def value - module_namespace.const_set(module_basename, grammar_body.value) - end - end - end + grammar = module_namespace.const_set(module_basename, Grammar.new) - rule :grammar_body do - zero_or_more(any(:include, :root, :rule)) { - grammar = Grammar.new - - if captures[:include] captures[:include].each {|inc| grammar.include(inc.value) } - end + captures[:rule].each {|r| grammar.rule(r.rule_name.value, r.value) } - grammar.root(root.value) if root + grammar.root(root.value) if root - if captures[:rule] - captures[:rule].each {|r| grammar.rule(r.rule_name.value, r.value) } + grammar end - - grammar - } + end end rule :rule do - all(:rule_keyword, :rule_name, :rule_body, :end_keyword) { - rule_body.value + all(:rule_keyword, :rule_name, zero_or_one(:expression), :end_keyword) { + # An empty rule definition matches the empty string. + expression ? expression.value : Rule.for('') } end - rule :rule_body do - zero_or_one(:choice) { - # An empty rule definition matches the empty string. - choice ? choice.value : Rule.for('') + rule :expression do + all(:sequence, zero_or_more([ :bar, :sequence ])) { + rules = captures[:sequence].map {|s| s.value } + rules.length > 1 ? Choice.new(rules) : rules.first } end - rule :choice do - mod all(:sequence, zero_or_more([ :bar, :sequence ])) do - def rules - @rules ||= captures[:sequence].map {|s| s.value } - end - - def value - rules.length > 1 ? Choice.new(rules) : rules.first - end - end - end - rule :sequence do - mod one_or_more(:label_expression) do - def rules - @rules ||= captures[:label_expression].map {|e| e.value } - end - - def value - rules.length > 1 ? Sequence.new(rules) : rules.first - end - end + one_or_more(:labelled) { + rules = captures[:labelled].map {|l| l.value } + rules.length > 1 ? Sequence.new(rules) : rules.first + } end - rule :label_expression do - all(zero_or_one(:label), :expression) { - rule = expression.value + rule :labelled do + all(zero_or_one(:label), :extended) { + rule = extended.value rule.label = label.value if label rule } end - rule :expression do + rule :extended do all(:prefix, zero_or_one(:extension)) { rule = prefix.value rule.extension = extension.value if extension rule } @@ -136,12 +121,12 @@ rule :primary do any(:grouping, :proxy, :terminal) end rule :grouping do - all(:lparen, :rule_body, :rparen) { - rule_body.value + all(:lparen, :expression, :rparen) { + expression.value } end ## Lexical syntax @@ -190,16 +175,18 @@ Alias.new(rule_name.value) } end rule :terminal do - any(:string_terminal, :regular_expression, :character_class, :dot) - end + any(:quoted_string, :case_insensitive_string, :regular_expression, :character_class, :dot) { + primitive = super() - rule :string_terminal do - any(:quoted_string, :case_insensitive_string) { - StringTerminal.new(super(), flags) + if String === primitive + StringTerminal.new(primitive, flags) + else + Terminal.new(primitive) + end } end rule :quoted_string do mod all(/(["'])(?:\\?.)*?\1/, :space) do @@ -225,23 +212,23 @@ end end rule :regular_expression do all(/\/(?:\\?.)*?\/[imxouesn]*/, :space) { - Terminal.new(eval(first.to_s)) + eval(first.to_s) } end rule :character_class do all(/\[(?:\\?.)*?\]/, :space) { - Terminal.new(Regexp.new(first.to_s, nil, 'n')) + eval("/#{first.to_s}/") } end rule :dot do all('.', :space) { - Terminal.new(DOT) + DOT } end rule :label do all(/[a-zA-Z0-9_]+/, :space, ':', :space) { @@ -315,12 +302,12 @@ } end rule :star do all(/[0-9]*/, '*', /[0-9]*/, :space) { |rule| - min = captures[0] == '' ? 0 : captures[0].to_i - max = captures[2] == '' ? Infinity : captures[2].to_i + min = captures[1] == '' ? 0 : captures[1].to_i + max = captures[3] == '' ? Infinity : captures[3].to_i Repeat.new(rule, min, max) } end rule :module_name do @@ -345,7 +332,14 @@ rule :constant, /[A-Z][a-zA-Z0-9_]*/ rule :white, /[ \t\n\r]/ rule :comment, /#.*/ rule :space, zero_or_more(any(:white, :comment)) + end + + def File.parse(*args) # :nodoc: + super + rescue ParseError => e + # Raise SyntaxError when a parse fails. + raise SyntaxError, e end end