aniero-treehouse 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/Manifest.txt +43 -0
- data/README.txt +102 -0
- data/Rakefile +25 -0
- data/examples/simple_assignment.rb +54 -0
- data/lib/treehouse.rb +52 -0
- data/lib/treehouse/metaid.rb +16 -0
- data/lib/treehouse/node.rb +79 -0
- data/lib/treehouse/node_creator.rb +28 -0
- data/lib/treehouse/node_definition.rb +106 -0
- data/lib/treehouse/visitor.rb +49 -0
- data/lib/treehouse/visitor_definition.rb +49 -0
- data/spec/fixtures/assignments.txt +7 -0
- data/spec/fixtures/ey00-s00348.xen +14 -0
- data/spec/grammars/assignments.rb +38 -0
- data/spec/grammars/assignments.treetop +42 -0
- data/spec/grammars/dot_xen.rb +122 -0
- data/spec/grammars/dot_xen.treetop +100 -0
- data/spec/grammars/magic.rb +63 -0
- data/spec/integration/assignments_spec.rb +45 -0
- data/spec/integration/dot_xen_spec.rb +86 -0
- data/spec/integration/magic_spec.rb +40 -0
- data/spec/node_creator_spec.rb +47 -0
- data/spec/node_definition_spec.rb +60 -0
- data/spec/node_spec.rb +131 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/treehouse_spec.rb +17 -0
- data/spec/visitor_definition_spec.rb +44 -0
- data/spec/visitor_spec.rb +48 -0
- data/tasks/ann.rake +81 -0
- data/tasks/bones.rake +21 -0
- data/tasks/gem.rake +126 -0
- data/tasks/git.rake +41 -0
- data/tasks/manifest.rake +49 -0
- data/tasks/notes.rake +28 -0
- data/tasks/post_load.rake +39 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +57 -0
- data/tasks/setup.rb +268 -0
- data/tasks/spec.rake +55 -0
- data/tasks/svn.rake +48 -0
- data/tasks/test.rake +38 -0
- data/treehouse.gemspec +38 -0
- metadata +124 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
examples/simple_assignment.rb
|
6
|
+
lib/treehouse.rb
|
7
|
+
lib/treehouse/metaid.rb
|
8
|
+
lib/treehouse/node.rb
|
9
|
+
lib/treehouse/node_creator.rb
|
10
|
+
lib/treehouse/node_definition.rb
|
11
|
+
lib/treehouse/visitor.rb
|
12
|
+
lib/treehouse/visitor_definition.rb
|
13
|
+
spec/fixtures/assignments.txt
|
14
|
+
spec/fixtures/ey00-s00348.xen
|
15
|
+
spec/grammars/assignments.rb
|
16
|
+
spec/grammars/assignments.treetop
|
17
|
+
spec/grammars/dot_xen.rb
|
18
|
+
spec/grammars/dot_xen.treetop
|
19
|
+
spec/grammars/magic.rb
|
20
|
+
spec/integration/assignments_spec.rb
|
21
|
+
spec/integration/dot_xen_spec.rb
|
22
|
+
spec/integration/magic_spec.rb
|
23
|
+
spec/node_creator_spec.rb
|
24
|
+
spec/node_definition_spec.rb
|
25
|
+
spec/node_spec.rb
|
26
|
+
spec/spec_helper.rb
|
27
|
+
spec/treehouse_spec.rb
|
28
|
+
spec/visitor_definition_spec.rb
|
29
|
+
spec/visitor_spec.rb
|
30
|
+
tasks/ann.rake
|
31
|
+
tasks/bones.rake
|
32
|
+
tasks/gem.rake
|
33
|
+
tasks/git.rake
|
34
|
+
tasks/manifest.rake
|
35
|
+
tasks/notes.rake
|
36
|
+
tasks/post_load.rake
|
37
|
+
tasks/rdoc.rake
|
38
|
+
tasks/rubyforge.rake
|
39
|
+
tasks/setup.rb
|
40
|
+
tasks/spec.rake
|
41
|
+
tasks/svn.rake
|
42
|
+
tasks/test.rake
|
43
|
+
treehouse.gemspec
|
data/README.txt
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
Treehouse
|
2
|
+
by Nathan Witmer
|
3
|
+
http://github.com/aniero/treehouse
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Simple node and visitor definitions for Treetop grammars.
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* Simple node definition syntax for defining an AST
|
12
|
+
* Simple visitor definition to walk an AST
|
13
|
+
|
14
|
+
== SYNOPSIS:
|
15
|
+
|
16
|
+
Given a treetop grammar:
|
17
|
+
|
18
|
+
grammar SimpleAssignment
|
19
|
+
rule assignment
|
20
|
+
lhs:variable space* "=" space* rhs:variable <create_node(:assignment)>
|
21
|
+
end
|
22
|
+
rule variable
|
23
|
+
[a-z]+ <create_node(:variable)>
|
24
|
+
end
|
25
|
+
rule space
|
26
|
+
[ ]+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
You can use Treehouse to define nodes for the grammar:
|
31
|
+
|
32
|
+
module SimpleAssignment
|
33
|
+
include Treehouse::NodeDefinition
|
34
|
+
|
35
|
+
node :assignment, :lhs, :rhs
|
36
|
+
node :variable, :value => :text_value
|
37
|
+
end
|
38
|
+
|
39
|
+
When you parse the grammar and call .build, it will return an AST using the nodes you defined, auto-building everything
|
40
|
+
for you:
|
41
|
+
|
42
|
+
ast = Parser.parse("foo = bar").build
|
43
|
+
|
44
|
+
ast.class #=> SimpleAssignment::Assignment
|
45
|
+
ast.lhs.class #=> SimpleAssignment::Variable
|
46
|
+
ast.lhs.value #=> "foo"
|
47
|
+
|
48
|
+
You can also define visitors for an AST:
|
49
|
+
|
50
|
+
module SimpleAssignment
|
51
|
+
include Treehouse::VisitorDefinition
|
52
|
+
|
53
|
+
visitor :hash_visitor do
|
54
|
+
visits Assignment do |a|
|
55
|
+
hash = {}
|
56
|
+
hash[ visit(lhs) ] = visit(rhs)
|
57
|
+
hash
|
58
|
+
end
|
59
|
+
visits Variable do |v|
|
60
|
+
v.value
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
SimpleAssignment::HashVisitor.visit(ast) #=> {"foo" => "bar"}
|
66
|
+
|
67
|
+
See examples/simple_assignment.rb for the full code.
|
68
|
+
|
69
|
+
== REQUIREMENTS:
|
70
|
+
|
71
|
+
* treetop
|
72
|
+
* attributes
|
73
|
+
* active_support
|
74
|
+
|
75
|
+
== INSTALL:
|
76
|
+
|
77
|
+
* sudo gem install aniero-treehouse -s http://gems.github.com
|
78
|
+
|
79
|
+
== LICENSE:
|
80
|
+
|
81
|
+
(The MIT License)
|
82
|
+
|
83
|
+
Copyright (c) 2008 Nathan Witmer
|
84
|
+
|
85
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
86
|
+
a copy of this software and associated documentation files (the
|
87
|
+
'Software'), to deal in the Software without restriction, including
|
88
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
89
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
90
|
+
permit persons to whom the Software is furnished to do so, subject to
|
91
|
+
the following conditions:
|
92
|
+
|
93
|
+
The above copyright notice and this permission notice shall be
|
94
|
+
included in all copies or substantial portions of the Software.
|
95
|
+
|
96
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
97
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
98
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
99
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
100
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
101
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
102
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Look in the tasks/setup.rb file for the various options that can be
|
2
|
+
# configured in this Rakefile. The .rake files in the tasks directory
|
3
|
+
# are where the options are used.
|
4
|
+
|
5
|
+
load 'tasks/setup.rb'
|
6
|
+
|
7
|
+
ensure_in_path 'lib'
|
8
|
+
require 'treehouse'
|
9
|
+
|
10
|
+
task :default => 'spec:run'
|
11
|
+
|
12
|
+
PROJ.name = 'treehouse'
|
13
|
+
PROJ.authors = 'Nathan Witmer'
|
14
|
+
PROJ.email = 'nwitmer at gmail dot com'
|
15
|
+
PROJ.url = 'http://github.com/aniero/treehouse'
|
16
|
+
PROJ.rubyforge.name = ''
|
17
|
+
PROJ.version = Treehouse.version
|
18
|
+
|
19
|
+
PROJ.spec.opts << '--color --format specdoc'
|
20
|
+
|
21
|
+
# EOF
|
22
|
+
|
23
|
+
depend_on "treetop"
|
24
|
+
depend_on "attributes"
|
25
|
+
depend_on "activesupport", ">= 2.0.2"
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", "lib", "treehouse")
|
2
|
+
|
3
|
+
Treetop.load_from_string <<-GRAMMAR
|
4
|
+
module SimpleAssignment
|
5
|
+
grammar Grammar
|
6
|
+
rule assignment
|
7
|
+
lhs:variable space* "=" space* rhs:variable <AST.create_node(:assignment)>
|
8
|
+
end
|
9
|
+
rule variable
|
10
|
+
[a-z]+ <AST.create_node(:variable)>
|
11
|
+
end
|
12
|
+
rule space
|
13
|
+
[ ]+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
GRAMMAR
|
18
|
+
|
19
|
+
module SimpleAssignment
|
20
|
+
|
21
|
+
# Define nodes for the AST
|
22
|
+
module AST
|
23
|
+
include Treehouse::NodeDefinition
|
24
|
+
node :assignment, :lhs, :rhs
|
25
|
+
node :variable, :value => :text_value
|
26
|
+
end
|
27
|
+
|
28
|
+
include Treehouse::VisitorDefinition
|
29
|
+
|
30
|
+
# Define a simple visitor to walk the AST and build a hash
|
31
|
+
visitor :hash_visitor do
|
32
|
+
visits AST::Assignment do |assignment|
|
33
|
+
{ visit(assignment.lhs) => visit(assignment.rhs) }
|
34
|
+
end
|
35
|
+
visits AST::Variable do |var|
|
36
|
+
var.value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Parser < ::Treetop::Runtime::CompiledParser
|
41
|
+
include Grammar
|
42
|
+
def self.parse(io)
|
43
|
+
new.parse(io).build
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
require "pp"
|
50
|
+
ast = SimpleAssignment::Parser.parse("foo=bar")
|
51
|
+
puts "----- AST -----"
|
52
|
+
pp ast
|
53
|
+
puts "\n----- visitor output -----"
|
54
|
+
pp SimpleAssignment::HashVisitor.visit(ast)
|
data/lib/treehouse.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Treehouse
|
2
|
+
|
3
|
+
# :stopdoc:
|
4
|
+
VERSION = '0.0.2'
|
5
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
6
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
7
|
+
# :startdoc:
|
8
|
+
|
9
|
+
# Returns the version string for the library.
|
10
|
+
#
|
11
|
+
def self.version
|
12
|
+
VERSION
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the library path for the module. If any arguments are given,
|
16
|
+
# they will be joined to the end of the libray path using
|
17
|
+
# <tt>File.join</tt>.
|
18
|
+
#
|
19
|
+
def self.libpath( *args )
|
20
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, *args)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the lpath for the module. If any arguments are given,
|
24
|
+
# they will be joined to the end of the path using
|
25
|
+
# <tt>File.join</tt>.
|
26
|
+
#
|
27
|
+
def self.path( *args )
|
28
|
+
args.empty? ? PATH : ::File.join(PATH, *args)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Utility method used to rquire all files ending in .rb that lie in the
|
32
|
+
# directory below this file that has the same name as the filename passed
|
33
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
34
|
+
# the _filename_ does not have to be equivalent to the directory.
|
35
|
+
#
|
36
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
37
|
+
dir ||= ::File.basename(fname, '.*')
|
38
|
+
search_me = ::File.expand_path(
|
39
|
+
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
40
|
+
|
41
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
42
|
+
end
|
43
|
+
|
44
|
+
end # module Treehouse
|
45
|
+
|
46
|
+
require "rubygems"
|
47
|
+
gem "activesupport"
|
48
|
+
gem "attributes"
|
49
|
+
|
50
|
+
%w(active_support/core_ext/string attributes treetop).each { |lib| require lib }
|
51
|
+
|
52
|
+
Treehouse.require_all_libs_relative_to __FILE__
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# thanks, _why!
|
2
|
+
class Object
|
3
|
+
# The hidden singleton lurks behind everyone
|
4
|
+
def metaclass; class << self; self; end; end
|
5
|
+
def meta_eval &blk; metaclass.instance_eval &blk; end
|
6
|
+
|
7
|
+
# Adds methods to a metaclass
|
8
|
+
def meta_def name, &blk
|
9
|
+
meta_eval { define_method name, &blk }
|
10
|
+
end
|
11
|
+
|
12
|
+
# Defines an instance method within a class
|
13
|
+
# def class_def name, &blk
|
14
|
+
# class_eval { define_method name, &blk }
|
15
|
+
# end
|
16
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Treehouse
|
2
|
+
|
3
|
+
# Treehouse nodes are auto-generated by node definitions (see Treehouse::NodeDefinition).
|
4
|
+
# A node is meant to be a part of an AST external to the AST that Treetop generates at parse-time
|
5
|
+
# with Treetop::Runtime::SyntaxNodes.
|
6
|
+
#
|
7
|
+
class Node
|
8
|
+
|
9
|
+
# Create a subclass of Node with the given attributes, both simple and mapped.
|
10
|
+
#
|
11
|
+
# (see NodeDefinitions#node for more information)
|
12
|
+
#
|
13
|
+
def self.create(*attribs)
|
14
|
+
Class.new(self) do
|
15
|
+
attribs.each do |attrib|
|
16
|
+
case attrib
|
17
|
+
when Symbol, String
|
18
|
+
attribute(attrib.to_s) { raise "no value given for #{attrib}" }
|
19
|
+
when Hash
|
20
|
+
attrib.each do |name, symbol|
|
21
|
+
attribute(name.to_s) { raise "no value given for #{name}" }
|
22
|
+
attribute_mapping[name.to_s] = symbol
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# The mapping of attribute names to the auto-build values/methods/lambdas used by create_node
|
30
|
+
def self.attribute_mapping
|
31
|
+
@attribute_mapping ||= {}
|
32
|
+
end
|
33
|
+
|
34
|
+
# Instantiate a node.
|
35
|
+
#
|
36
|
+
# Values can either be a hash of values to set the values of this node's attributes, or a Treetop syntax node
|
37
|
+
# which is used to automatically build this node.
|
38
|
+
#
|
39
|
+
def initialize(values={})
|
40
|
+
if values.kind_of?(Treetop::Runtime::SyntaxNode)
|
41
|
+
build_from_parsed_node(values)
|
42
|
+
else
|
43
|
+
values.each do |name, value|
|
44
|
+
send("#{name}=", value)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
# Auto-builds this node using the provided parsed node and the defined attributes and mapped attributes.
|
52
|
+
def build_from_parsed_node(parsed_node)
|
53
|
+
attributes.each do |attrib|
|
54
|
+
if value = mapping(attrib)
|
55
|
+
if value.kind_of?(Proc)
|
56
|
+
value = value.call(parsed_node)
|
57
|
+
else
|
58
|
+
value = parsed_node.send(mapping(attrib))
|
59
|
+
end
|
60
|
+
else
|
61
|
+
value = parsed_node.send(attrib)
|
62
|
+
end
|
63
|
+
value = value.map { |val| val.respond_to?(:build) ? val.build : val } if value.kind_of?(Array)
|
64
|
+
value = value.build if value.respond_to?(:build)
|
65
|
+
send("#{attrib}=", value)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def attributes
|
70
|
+
self.class.attributes
|
71
|
+
end
|
72
|
+
|
73
|
+
def mapping(name)
|
74
|
+
self.class.attribute_mapping[name]
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Treehouse
|
2
|
+
class NodeCreator
|
3
|
+
|
4
|
+
# Creates a node creator for the given node class. This is meant to act as a stand-in for the treetop
|
5
|
+
# syntax node class.
|
6
|
+
#
|
7
|
+
def initialize(node_class)
|
8
|
+
@node_class = node_class
|
9
|
+
end
|
10
|
+
|
11
|
+
# Returns a new treetop syntax node to act as a standin for a normal syntax node. Before returning the node,
|
12
|
+
# this defines a build method on the syntax node that will instantiate the node class using the auto-build
|
13
|
+
# functionality. If this build method isn't enough, you'll have to define one yourself inline in the treetop
|
14
|
+
# gramamr.
|
15
|
+
#
|
16
|
+
def new(*args)
|
17
|
+
parsed_node = Treetop::Runtime::SyntaxNode.new(*args)
|
18
|
+
|
19
|
+
node_class = @node_class # local scope for the block below
|
20
|
+
parsed_node.meta_def :build do
|
21
|
+
node_class.new(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
parsed_node
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Treehouse::NodeDefinition
|
2
|
+
|
3
|
+
module ModuleMethods
|
4
|
+
|
5
|
+
# Returns a NodeCreator to act as a stand-in for a normal node class definition.
|
6
|
+
# According to the treetop metagrammar, node class definitions can have more than just a class in them.
|
7
|
+
# For example:
|
8
|
+
#
|
9
|
+
# rule variable
|
10
|
+
# [a-z]+ <Variable>
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# Instead, use this method to use AST node auto-build functionality. Given
|
14
|
+
#
|
15
|
+
# node :variable, :value => :text_value
|
16
|
+
#
|
17
|
+
# You can define the grammar as
|
18
|
+
#
|
19
|
+
# rule variable
|
20
|
+
# [a-z]+ <create_node(:variable)>
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
def create_node(name)
|
24
|
+
Treehouse::NodeCreator.new(const_get(name.to_s.camelize))
|
25
|
+
end
|
26
|
+
|
27
|
+
# Define a node.
|
28
|
+
#
|
29
|
+
# This creates a new class (a subclass of Treehouse::Node) with the given attribute names.
|
30
|
+
#
|
31
|
+
# Attribute names can be lists of symbols (simple attributes) and/or a hash of name-value pairs (mapped attributes).
|
32
|
+
# The new class will have attributes matching the names and hash keys given. More on the hash values in a minute.
|
33
|
+
#
|
34
|
+
# node :foo
|
35
|
+
#
|
36
|
+
# Creates a Foo class in the local scope.
|
37
|
+
#
|
38
|
+
# node :calculation, :left, :right, :operator => lambda { |node| node.elements[1] }
|
39
|
+
#
|
40
|
+
# Creates a Calculation class with left, right, and operator attributes.
|
41
|
+
#
|
42
|
+
# There are two ways to instantiate a class generated by this method.
|
43
|
+
#
|
44
|
+
# The first method is to provide a hash with name/value pairs for the attributes:
|
45
|
+
#
|
46
|
+
# c = Calculation.new(:left => "lhs", :right => "rhs", :operator => "=")
|
47
|
+
# c.left # => "lhs"
|
48
|
+
#
|
49
|
+
# If an attribute isn't initialized in this way, you will get an exception if you try to access it.
|
50
|
+
#
|
51
|
+
# This simple way of instantiating a node can be used in a grammar to build an AST with these nodes manually.
|
52
|
+
#
|
53
|
+
# The second method takes a treetop syntax node and auto-builds the node using the syntax node as a basis.
|
54
|
+
# The auto-build functionality uses the attribute names and mapped attributes in the following way:
|
55
|
+
#
|
56
|
+
# * Simple attributes: calls the method by that name on the syntax node
|
57
|
+
# * Mapped attributes: if the attribute value is a symbol or a string, it calls that method on the syntax node.
|
58
|
+
# If the attribute value is a lambda, it yields the syntax node to the lambda.
|
59
|
+
#
|
60
|
+
# If the value (or array of values) returned by one of these methods is another syntax node, the auto-build code
|
61
|
+
# will call the build method on each syntax node or array item (assuming each syntax node has a build method,
|
62
|
+
# usually auto-defined using create_node). Any value not responding to the build method is left alone.
|
63
|
+
#
|
64
|
+
# Simple example:
|
65
|
+
#
|
66
|
+
# rule assignment
|
67
|
+
# variable:lhs "=" variable:rhs <create_node(:assignment)>
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# node :assignment, :lhs, :rhs
|
71
|
+
#
|
72
|
+
# Assignment.new(syntax_node) will return an instance with an lhs and rhs set from that node.
|
73
|
+
#
|
74
|
+
# If a block is given, the block is evaluated in the context of the new class (for method definitions, etc.) e.g.
|
75
|
+
#
|
76
|
+
# node :foo do
|
77
|
+
# def name; "hello!"; end
|
78
|
+
# end
|
79
|
+
# Foo.new.name #=> "hello!"
|
80
|
+
#
|
81
|
+
def node(name, *attribute_names, &blk)
|
82
|
+
klass = Treehouse::Node.create *attribute_names
|
83
|
+
const_set name.to_s.camelize, klass
|
84
|
+
klass.class_eval &blk if block_given?
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
# Include this module to get access to the node and create_node methods.
|
90
|
+
# A good place to include this is in a separate AST module, e.g.
|
91
|
+
#
|
92
|
+
# module AST
|
93
|
+
# include NodeDefinition
|
94
|
+
# node :foo
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# And then in your grammar:
|
98
|
+
#
|
99
|
+
# rule foo
|
100
|
+
# "foo" <AST.create_node(:foo)>
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
def self.included(base)
|
104
|
+
base.extend ModuleMethods
|
105
|
+
end
|
106
|
+
end
|