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 |