Class: Rattler::Parsers::DispatchAction

Inherits:
Parser show all
Includes:
Combining
Defined in:
lib/rattler/parsers/dispatch_action.rb

Overview

DispatchAction decorates a parser to peform a symantic action on success by dispatching to a method.

Author:

  • Jason Arhart

Constant Summary collapse

@@node_defaults =
{
  :target => 'Rattler::Runtime::ParseNode',
  :method => 'parsed'
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Combining

#capturing?, #with_ws

Methods inherited from Parser

#&, #capturing?, #labeled?, #one_or_more, #optional, #skip, #variable_capture_count?, #with_ws, #zero_or_more, #|

Methods inherited from Util::Node

#==, #[], [], #attrs, #can_equal?, #child, #children, #each, #empty?, #eql?, #inspect, #method_missing, #name, #respond_to?, #same_contents?, #to_graphviz, #with_attrs, #with_attrs!, #with_children

Constructor Details

#initialize(parser, opts = {}) ⇒ DispatchAction #initialize(method_spec) ⇒ DispatchAction

Create a new parser that decorates a parser to peform a symantic on success.

Overloads:

  • #initialize(parser, opts = {}) ⇒ DispatchAction

    Parameters:

    Options Hash (opts):

    • target (String) — default: 'Rattler::Runtime::ParseNode'

      the object on which to invoke a method as the symantic action

    • method (String) — default: 'parsed'

      the name of the method to invoke as the symantic action

  • #initialize(method_spec) ⇒ DispatchAction

    Parameters:

    • method_spec (String)

      a specification of the target and optional method name separated by “.”



64
65
66
67
68
69
# File 'lib/rattler/parsers/dispatch_action.rb', line 64

def initialize(children, attrs_arg={})
  super(children, self.class.parse_attrs_arg(attrs_arg))
  @@node_defaults.each {|k, v| attrs[k] ||= v } unless attrs[:code]
  @method_name = attrs[:method]
  @target_attrs = attrs[:target_attrs] || {}
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Rattler::Util::Node

Instance Attribute Details

#method_nameObject (readonly)

the name of the method used as the symantic action



72
73
74
# File 'lib/rattler/parsers/dispatch_action.rb', line 72

def method_name
  @method_name
end

#target_attrsObject (readonly)

the name of the method used as the symantic action



72
73
74
# File 'lib/rattler/parsers/dispatch_action.rb', line 72

def target_attrs
  @target_attrs
end

Class Method Details

.parse_attrs_arg(arg) ⇒ Object



39
40
41
42
43
44
45
46
47
48
# File 'lib/rattler/parsers/dispatch_action.rb', line 39

def self.parse_attrs_arg(arg) #:nodoc:
  case arg
  when Hash
    arg
  when /^\s*(.+?)\s*\.\s*(.+?)\s*$/
    { :target => $1, :method => $2 }
  else
    { :target => arg.to_s.strip }
  end
end

.parsed(results, *_) ⇒ Object



27
28
29
30
31
32
33
34
35
36
# File 'lib/rattler/parsers/dispatch_action.rb', line 27

def self.parsed(results, *_) #:nodoc:
  optional_expr, optional_attribute, optional_name = results
  expr = optional_expr.first || ESymbol[]
  a = self[expr, optional_attribute.first || @@node_defaults[:target]]
  unless optional_name.empty?
    a.with_attrs(:target_attrs => {:name => eval(optional_name.first, TOPLEVEL_BINDING)})
  else
    a
  end
end

Instance Method Details

#bind(scope, bind_args) ⇒ Object



97
98
99
# File 'lib/rattler/parsers/dispatch_action.rb', line 97

def bind(scope, bind_args)
  bindable_code.bind(scope, bind_args)
end

#bindable_codeObject



93
94
95
# File 'lib/rattler/parsers/dispatch_action.rb', line 93

def bindable_code
  @bindable_code ||= NodeCode.new(target, method_name, target_attrs)
end

#parse(scanner, rules, scope = {}) ⇒ Object

If the wrapped parser matches at the parse position, return the result of applying the symantic action, otherwise return a false value.

Returns:

  • the result of applying the symantic action, or a false value if the parse failed.



81
82
83
84
85
86
87
88
89
90
91
# File 'lib/rattler/parsers/dispatch_action.rb', line 81

def parse(scanner, rules, scope = {})
  if result = parse_child(child, scanner, rules, scope) {|_| scope = _ }
    if not capturing?
      apply([])
    elsif result.respond_to?(:to_ary)
      apply(result, scope)
    else
      apply([result], scope)
    end
  end
end