Class: Heist::Runtime::Macro::Matches
- Inherits:
-
Object
- Object
- Heist::Runtime::Macro::Matches
- Defined in:
- lib/heist/runtime/callable/macro/matches.rb
Overview
Matches instances, with help from the Tree class, are data structures that represent the way in which syntactic expressions match patterns found in Macro rules. They provide an API for storing and retrieving such data, with the aim of removing some clutter from the macro parsing and expansion routines.
At a pure Ruby level, a Matches is a wrapper around a hash that maps pattern variables to Tree objects, which themselves are wrappers around nested arrays that represent how repeated pattern matches are grouped together. For example, given the pattern
(do ([variable init step ...] ...)
(test expression ...)
command ...)
and the expression
(do ([x 6 (- x 1)]
[acc 1])
((zero? x) acc)
(display x) (newline)
(set! acc (* acc x)))
the Matches object would contain the following:
@data = {
"variable" => [ x,
acc
],
"init" => [ 6,
1
],
"step" => [ [ (- x 1)
],
[]
],
"test" => (zero? x),
"expression" => [ acc
],
"command" => [ (display x),
(newline),
(set! acc (* acc x))
]
}
Breaking this down, we see test is not followed by an ellipsis in the pattern, and can thus only consume one item from the input expression. So, its match data is a single Expression. variable, init, command and expression are all followed by a single ellipsis (variable and init appear in a list that is followed by an ellipsis), so can consume several values each; their match data are arrays of expressions.
step, on the other hand, is followed by two ellipses: it itself is followed by an ellipsis, and step ... appears inside a list that is also followed by an ellipsis. If a pattern is followed by more than one ellipsis, the match data it generates is a tree of nested arrays that describe how the expressions are grouped. Here, we see that the expression [variable init step ...] appears twice in the input, so step‘s root match element is an array of two elements. But, step does not match any data in the second appearance ([acc 1]), so the second element of this array is empty. The first element is an array containing the single match from the first appearance ((- x 1) in the expression [x 6 (- x 1)]).
Matches tries to hide many of these details so the macro routines can read and write to this data structure in the simplest possible terms.
Instance Method Summary collapse
-
#descend!(names, depth) ⇒ Object
Tells the
Matchesobject that the given pattern variables (the arraynames) have encountered a trailing ellipsis at the given repetition depth. -
#expand!(template, depth) ⇒ Object
Takes a
templateExpression, a repetitiondepthand a block, and calls the blockntimes, wherenis the number of matches for the pattern variables in the template at the given depth and the current iteration point in the tree. -
#get(name) ⇒ Object
Retrieves an expression from the
Matchesunder the givenname. -
#has?(name) ⇒ Boolean
Returns
trueiff the receiver has a pattern variable namedname. -
#initialize(pattern, formals) ⇒ Matches
constructor
A
Matchesis initialized using aConsrepresenting a macro pattern, and an array of formal keywords supplied by theMacro. -
#put(name, value) ⇒ Object
Writes an expression to the
Matchesobject under the variablename.
Constructor Details
#initialize(pattern, formals) ⇒ Matches
A Matches is initialized using a Cons representing a macro pattern, and an array of formal keywords supplied by the Macro. Keywords do not need to store matches so they are ignored here.
82 83 84 85 86 |
# File 'lib/heist/runtime/callable/macro/matches.rb', line 82 def initialize(pattern, formals) @data = {} names = Macro.pattern_vars(pattern, formals) names.each { |name| @data[name] = Tree.new(name) } end |
Instance Method Details
#descend!(names, depth) ⇒ Object
Tells the Matches object that the given pattern variables (the array names) have encountered a trailing ellipsis at the given repetition depth. This allows Matches to group repeated patterns correctly.
91 92 93 94 95 |
# File 'lib/heist/runtime/callable/macro/matches.rb', line 91 def descend!(names, depth) @data.each do |name, set| set.descend!(depth) if names.include?(name) end end |
#expand!(template, depth) ⇒ Object
Takes a template Expression, a repetition depth and a block, and calls the block n times, where n is the number of matches for the pattern variables in the template at the given depth and the current iteration point in the tree. After each block call, the Matches object moves the pointer for all the applicable pattern variables along one place at the given depth – see iterate! and Tree#shift!.
123 124 125 126 |
# File 'lib/heist/runtime/callable/macro/matches.rb', line 123 def (template, depth) names = Macro.pattern_vars(template) size(names, depth).times { yield() and iterate!(names, depth) } end |
#get(name) ⇒ Object
Retrieves an expression from the Matches under the given name. The receiver deals with pulling the expression from the right point in the tree; see the expand!, iterate! and Tree#read and Tree#shift! methods.
113 114 115 |
# File 'lib/heist/runtime/callable/macro/matches.rb', line 113 def get(name) @data[name.to_s].read end |
#has?(name) ⇒ Boolean
Returns true iff the receiver has a pattern variable named name.
105 106 107 |
# File 'lib/heist/runtime/callable/macro/matches.rb', line 105 def has?(name) @data.has_key?(name.to_s) end |
#put(name, value) ⇒ Object
Writes an expression to the Matches object under the variable name. The receiver deals with storing it in the correct repetition group.
99 100 101 102 |
# File 'lib/heist/runtime/callable/macro/matches.rb', line 99 def put(name, value) name = name.to_s @data[name] << value if has?(name) end |