Class: Aspen::Parser
- Inherits:
-
AbstractParser
- Object
- AbstractParser
- Aspen::Parser
- Defined in:
- lib/aspen/parser.rb
Instance Attribute Summary
Attributes inherited from AbstractParser
Instance Method Summary collapse
-
#parse ⇒ Object
(also: #parse_narrative)
narrative = statements; statements = { statement } statement = COMMENT | CUSTOM_STATEMENT | list_statement | vanilla_statement.
- #parse_comment ⇒ Object
- #parse_custom_statement ⇒ Object
- #parse_edge ⇒ Object
- #parse_list_item ⇒ Object
- #parse_list_item_label ⇒ Object
- #parse_list_items ⇒ Object
- #parse_list_label ⇒ Object
- #parse_list_statement ⇒ Object
- #parse_literal ⇒ Object
- #parse_node ⇒ Object
-
#parse_node_cypher_form ⇒ Object
This complicates things greatly.
- #parse_node_grouped_form ⇒ Object
- #parse_node_labeled_form ⇒ Object
- #parse_node_short_form ⇒ Object
- #parse_statement ⇒ Object
- #parse_statements ⇒ Object
- #parse_vanilla_statement ⇒ Object
Methods inherited from AbstractParser
#expect, #first, #initialize, #last, #need, #next_token, parse, parse_code, #peek
Constructor Details
This class inherits a constructor from Aspen::AbstractParser
Instance Method Details
#parse ⇒ Object Also known as: parse_narrative
narrative = statements;
statements = { statement }
statement = COMMENT | CUSTOM_STATEMENT | list_statement | vanilla_statement
# Variant 1. TODO: Variant 2
list_statement = node, edge, [ list_label ], START_LIST, list_items, END_LIST
list_label = OPEN_PARENS, LABEL, CLOSE_PARENS
list_items = { list_item }
list_item = BULLET, CONTENT, [ list_item_label ]
list_item_label = OPEN_PARENS, LABEL, CLOSE_PARENS
vanilla_statement = node | node, edge, node, { END_STATEMENT }
node = node_short_form | node_grouped_form | node_cypher_form
node_short_form = OPEN_PARENS, CONTENT, CLOSE_PARENS
node_grouped_form = OPEN_PARENS, { CONTENT, [ COMMA ] }, CLOSE_PARENS
node_cypher_form = OPEN_PARENS, LABEL, OPEN_BRACES, { IDENTIFIER, literal, [ COMMA ] }, CLOSE_BRACES
literal = STRING | NUMBER
edge = OPEN_BRACKETS, CONTENT, CLOSE_BRACKETS
28 29 30 |
# File 'lib/aspen/parser.rb', line 28 def parse Aspen::AST::Nodes::Narrative.new(parse_statements) end |
#parse_comment ⇒ Object
53 54 55 56 57 |
# File 'lib/aspen/parser.rb', line 53 def parse_comment if comment = expect(:COMMENT) Aspen::AST::Nodes::Comment.new(comment.first.last) end end |
#parse_custom_statement ⇒ Object
59 60 61 62 63 64 65 |
# File 'lib/aspen/parser.rb', line 59 def parse_custom_statement if content = expect(:CUSTOM_GRAMMAR_STATEMENT) # FIXME: Why does this need a #first and a #last? # Seems unnecessarily nested. Maybe this happened in the lexer. Aspen::AST::Nodes::CustomStatement.new(content.first.last) end end |
#parse_edge ⇒ Object
170 171 172 173 174 |
# File 'lib/aspen/parser.rb', line 170 def parse_edge if (_, content, _ = expect(:OPEN_BRACKETS, :CONTENT, :CLOSE_BRACKETS)) Aspen::AST::Nodes::Edge.new(content.last) end end |
#parse_list_item ⇒ Object
100 101 102 103 104 105 106 107 108 109 |
# File 'lib/aspen/parser.rb', line 100 def parse_list_item node = nil if (_, content = expect(:BULLET, :CONTENT)) node = Aspen::AST::Nodes::Node.new(attribute: content.last) end if (label = parse_list_item_label) node.label = label end return node end |
#parse_list_item_label ⇒ Object
111 112 113 114 115 116 |
# File 'lib/aspen/parser.rb', line 111 def parse_list_item_label if (_, item_label, _ = expect(:OPEN_PARENS, :CONTENT, :CLOSE_PARENS)) # If singularizing should be conditional, we need to introduce the env in the parser. return item_label.last end end |
#parse_list_items ⇒ Object
90 91 92 93 94 95 96 97 98 |
# File 'lib/aspen/parser.rb', line 90 def parse_list_items if need(:START_LIST) results = [] while target = parse_list_item results << target end results end end |
#parse_list_label ⇒ Object
83 84 85 86 87 88 |
# File 'lib/aspen/parser.rb', line 83 def parse_list_label if (_, plural_label, _ = expect(:OPEN_PARENS, :CONTENT, :CLOSE_PARENS)) # If singularizing should be conditional, we need to introduce the env in the parser. return plural_label.last.singularize end end |
#parse_list_statement ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/aspen/parser.rb', line 67 def parse_list_statement if expect(:PREPARE_START_LIST) origin = parse_node edge = parse_edge label = parse_list_label targets = parse_list_items expect(:END_LIST) targets.map do |target| # puts "TARGET #{target.attribute.content.inner_content} had label #{target.label.content.inner_content.inspect}" target.label = label if target.label.content.inner_content.nil? # puts "TARGET #{target.attribute.content.inner_content} has label #{target.label.content.inner_content.inspect}" Aspen::AST::Nodes::Statement.new(origin: origin, edge: edge, target: target) end end end |
#parse_literal ⇒ Object
166 167 168 |
# File 'lib/aspen/parser.rb', line 166 def parse_literal raise NotImplementedError, "#parse_literal not yet implemented" end |
#parse_node ⇒ Object
135 136 137 138 |
# File 'lib/aspen/parser.rb', line 135 def parse_node # parse_node_cypher_form || parse_node_grouped_form || parse_node_short_form end |
#parse_node_cypher_form ⇒ Object
This complicates things greatly. Can we skip this for now, by rewriting the tests to get rid of this case, and come back to it?
160 161 162 163 164 |
# File 'lib/aspen/parser.rb', line 160 def parse_node_cypher_form if (_, label, _, content, _ = expect(:OPEN_PARENS, :CONTENT, :SEPARATOR, :CONTENT, :CLOSE_PARENS)) Aspen::AST::Nodes::Node.new(content: content.last, label: label.last) end end |
#parse_node_grouped_form ⇒ Object
140 141 142 143 144 145 146 147 |
# File 'lib/aspen/parser.rb', line 140 def parse_node_grouped_form if (_, label, sep, content, _ = expect(:OPEN_PARENS, :LABEL, :SEPARATOR, :CONTENT, :CLOSE_PARENS)) Aspen::AST::Nodes::Node.new( attribute: content.last, label: label.last ) end end |
#parse_node_labeled_form ⇒ Object
119 120 121 |
# File 'lib/aspen/parser.rb', line 119 def parse_node_labeled_form raise NotImplementedError, "#parse_node_labeled_form not yet implemented" end |
#parse_node_short_form ⇒ Object
149 150 151 152 153 154 155 156 |
# File 'lib/aspen/parser.rb', line 149 def parse_node_short_form # Terminal instructions require a "need" _, content, _ = need(:OPEN_PARENS, :CONTENT, :CLOSE_PARENS) Aspen::AST::Nodes::Node.new( attribute: content.last, label: nil ) end |
#parse_statement ⇒ Object
46 47 48 49 50 51 |
# File 'lib/aspen/parser.rb', line 46 def parse_statement parse_comment || parse_custom_statement || parse_list_statement || parse_vanilla_statement end |
#parse_statements ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/aspen/parser.rb', line 34 def parse_statements results = [] # Make sure this returns on empty while result = parse_statement results.push(*result) break if tokens[position].nil? end results end |
#parse_vanilla_statement ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/aspen/parser.rb', line 123 def parse_vanilla_statement # TODO: Might benefit from a condition when doing non-vanilla statements? origin = parse_node edge = parse_edge target = parse_node # SMELL: Nil check advance if peek && peek.first == :END_STATEMENT Aspen::AST::Nodes::Statement.new(origin: origin, edge: edge, target: target) end |